@aglyn/plugins-ai 1.0.0-beta.270 → 1.0.0-beta.271
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.d.ts +1 -1
- package/src/lib/activity/ai-activity-actions.js +1 -0
- package/src/lib/activity/ai-activity-actions.js.map +1 -1
- package/src/lib/assets/site-styles/beauty.webp +0 -0
- package/src/lib/assets/site-styles/blog.webp +0 -0
- package/src/lib/assets/site-styles/business.webp +0 -0
- package/src/lib/assets/site-styles/coming-soon.webp +0 -0
- package/src/lib/assets/site-styles/education.webp +0 -0
- package/src/lib/assets/site-styles/events.webp +0 -0
- package/src/lib/assets/site-styles/fitness.webp +0 -0
- package/src/lib/assets/site-styles/landing.webp +0 -0
- package/src/lib/assets/site-styles/music.webp +0 -0
- package/src/lib/assets/site-styles/nonprofit.webp +0 -0
- package/src/lib/assets/site-styles/personal.webp +0 -0
- package/src/lib/assets/site-styles/photography.webp +0 -0
- package/src/lib/assets/site-styles/portfolio.webp +0 -0
- package/src/lib/assets/site-styles/professional.webp +0 -0
- package/src/lib/assets/site-styles/realestate.webp +0 -0
- package/src/lib/assets/site-styles/restaurant.webp +0 -0
- package/src/lib/assets/site-styles/store.webp +0 -0
- package/src/lib/assets/site-styles/studio.webp +0 -0
- package/src/lib/assets/site-styles/trades.webp +0 -0
- package/src/lib/assets/site-styles/wellness.webp +0 -0
- package/src/lib/assets/site-styles/yoga.webp +0 -0
- package/src/lib/components/ai-credits-card.component.d.ts +4 -3
- package/src/lib/components/ai-credits-card.component.js +15 -15
- package/src/lib/components/ai-credits-card.component.js.map +1 -1
- package/src/lib/components/ai-job-input-form.component.d.ts +36 -0
- package/src/lib/components/ai-job-input-form.component.js +100 -0
- package/src/lib/components/ai-job-input-form.component.js.map +1 -0
- package/src/lib/components/ai-job-requests.d.ts +4 -0
- package/src/lib/components/ai-job-requests.js +4 -0
- package/src/lib/components/ai-job-requests.js.map +1 -1
- package/src/lib/components/ai-site-start-card.component.d.ts +1 -1
- package/src/lib/components/ai-site-start-card.component.js +99 -31
- package/src/lib/components/ai-site-start-card.component.js.map +1 -1
- package/src/lib/components/ai-site-start-steps.component.d.ts +43 -2
- package/src/lib/components/ai-site-start-steps.component.js +651 -15
- package/src/lib/components/ai-site-start-steps.component.js.map +1 -1
- package/src/lib/components/ai-site-start-tracking.d.ts +10 -0
- package/src/lib/components/ai-site-start-tracking.js +14 -0
- package/src/lib/components/ai-site-start-tracking.js.map +1 -1
- package/src/lib/components/ai-site-style-previews.js +26 -22
- package/src/lib/components/ai-site-style-previews.js.map +1 -1
- package/src/lib/components/ai-upsell-dialog.component.d.ts +7 -5
- package/src/lib/components/ai-upsell-dialog.component.js +8 -6
- package/src/lib/components/ai-upsell-dialog.component.js.map +1 -1
- package/src/lib/components/assist-build-card.component.js +11 -1
- package/src/lib/components/assist-build-card.component.js.map +1 -1
- package/src/lib/components/assist-jobs-drawer.component.js +9 -1
- package/src/lib/components/assist-jobs-drawer.component.js.map +1 -1
- package/src/lib/components/assist-panel.component.js +8 -4
- package/src/lib/components/assist-panel.component.js.map +1 -1
- package/src/lib/components/staff-org-ai-card.component.js +4 -7
- package/src/lib/components/staff-org-ai-card.component.js.map +1 -1
- package/src/lib/declarations.d.ts +2 -2
- package/src/lib/declarations.js +9 -5
- package/src/lib/declarations.js.map +1 -1
- package/src/lib/jobs/ai-build-capabilities.js +3 -1
- package/src/lib/jobs/ai-build-capabilities.js.map +1 -1
- package/src/lib/jobs/ai-business-profile-prefill.d.ts +1 -1
- package/src/lib/jobs/ai-business-profile-prefill.js +14 -3
- package/src/lib/jobs/ai-business-profile-prefill.js.map +1 -1
- package/src/lib/jobs/ai-job-build-step.js +5 -3
- package/src/lib/jobs/ai-job-build-step.js.map +1 -1
- package/src/lib/jobs/ai-job-form-step.d.ts +15 -1
- package/src/lib/jobs/ai-job-form-step.js +75 -8
- package/src/lib/jobs/ai-job-form-step.js.map +1 -1
- package/src/lib/jobs/ai-job-page-language.d.ts +13 -0
- package/src/lib/jobs/ai-job-page-language.js +37 -1
- package/src/lib/jobs/ai-job-page-language.js.map +1 -1
- package/src/lib/jobs/ai-job-page-step.d.ts +17 -0
- package/src/lib/jobs/ai-job-page-step.js +37 -16
- package/src/lib/jobs/ai-job-page-step.js.map +1 -1
- package/src/lib/jobs/ai-job-plan-step.d.ts +25 -2
- package/src/lib/jobs/ai-job-plan-step.js +103 -29
- package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
- package/src/lib/jobs/ai-job-settings-step.js +4 -3
- package/src/lib/jobs/ai-job-settings-step.js.map +1 -1
- package/src/lib/jobs/ai-job-site-datasets.d.ts +27 -0
- package/src/lib/jobs/ai-job-site-datasets.js +140 -14
- package/src/lib/jobs/ai-job-site-datasets.js.map +1 -1
- package/src/lib/jobs/ai-job-site-look.js +18 -5
- package/src/lib/jobs/ai-job-site-look.js.map +1 -1
- package/src/lib/jobs/ai-job-site-step.d.ts +16 -1
- package/src/lib/jobs/ai-job-site-step.js +95 -22
- package/src/lib/jobs/ai-job-site-step.js.map +1 -1
- package/src/lib/jobs/ai-job-text-step.d.ts +8 -1
- package/src/lib/jobs/ai-job-text-step.js.map +1 -1
- package/src/lib/jobs/ai-job-tracking-step.d.ts +14 -3
- package/src/lib/jobs/ai-job-tracking-step.js +28 -5
- package/src/lib/jobs/ai-job-tracking-step.js.map +1 -1
- package/src/lib/jobs/ai-jobs.d.ts +8 -1
- package/src/lib/jobs/ai-jobs.js +63 -8
- package/src/lib/jobs/ai-jobs.js.map +1 -1
- package/src/lib/jobs/ai-layout-stock-photos.d.ts +27 -2
- package/src/lib/jobs/ai-layout-stock-photos.js +190 -19
- package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -1
- package/src/lib/jobs/ai-site-inspiration-signals.d.ts +98 -0
- package/src/lib/jobs/ai-site-inspiration-signals.js +585 -0
- package/src/lib/jobs/ai-site-inspiration-signals.js.map +1 -0
- package/src/lib/jobs/ai-site-inspiration.d.ts +157 -0
- package/src/lib/jobs/ai-site-inspiration.js +346 -0
- package/src/lib/jobs/ai-site-inspiration.js.map +1 -0
- package/src/lib/jobs/ai-site-publish.d.ts +26 -1
- package/src/lib/jobs/ai-site-publish.js +162 -13
- package/src/lib/jobs/ai-site-publish.js.map +1 -1
- package/src/lib/jobs/ai-theme-brand-inputs.d.ts +16 -0
- package/src/lib/jobs/ai-theme-brand-inputs.js +18 -4
- package/src/lib/jobs/ai-theme-brand-inputs.js.map +1 -1
- package/src/lib/jobs/fixtures/ai-candle-shop-free-plan-recording.d.ts +97 -0
- package/src/lib/jobs/fixtures/ai-candle-shop-free-plan-recording.js +137 -0
- package/src/lib/jobs/fixtures/ai-candle-shop-free-plan-recording.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-site-inspiration-pages.d.ts +38 -0
- package/src/lib/jobs/fixtures/ai-site-inspiration-pages.js +103 -0
- package/src/lib/jobs/fixtures/ai-site-inspiration-pages.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl3988-recordings.d.ts +25 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl3988-recordings.js +174 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl3988-recordings.js.map +1 -0
- package/src/lib/layout-language/ai-layout-compiler.d.ts +1 -1
- package/src/lib/layout-language/ai-layout-compiler.js +438 -25
- package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
- package/src/lib/layout-language/ai-layout-contact.d.ts +57 -0
- package/src/lib/layout-language/ai-layout-contact.js +137 -0
- package/src/lib/layout-language/ai-layout-contact.js.map +1 -0
- package/src/lib/layout-language/ai-layout-copy.d.ts +12 -0
- package/src/lib/layout-language/ai-layout-copy.js +34 -2
- package/src/lib/layout-language/ai-layout-copy.js.map +1 -1
- package/src/lib/layout-language/ai-layout-design.d.ts +65 -8
- package/src/lib/layout-language/ai-layout-design.js +411 -97
- package/src/lib/layout-language/ai-layout-design.js.map +1 -1
- package/src/lib/layout-language/ai-layout-frame.js +23 -0
- package/src/lib/layout-language/ai-layout-frame.js.map +1 -1
- package/src/lib/layout-language/ai-layout-labels.d.ts +2 -0
- package/src/lib/layout-language/ai-layout-labels.js +12 -6
- package/src/lib/layout-language/ai-layout-labels.js.map +1 -1
- package/src/lib/layout-language/ai-layout-language.d.ts +3 -2
- package/src/lib/layout-language/ai-layout-language.js +4 -3
- package/src/lib/layout-language/ai-layout-language.js.map +1 -1
- package/src/lib/layout-language/ai-layout-links.d.ts +13 -0
- package/src/lib/layout-language/ai-layout-links.js +30 -0
- package/src/lib/layout-language/ai-layout-links.js.map +1 -1
- package/src/lib/layout-language/ai-layout-pictures.d.ts +49 -6
- package/src/lib/layout-language/ai-layout-pictures.js +145 -22
- package/src/lib/layout-language/ai-layout-pictures.js.map +1 -1
- package/src/lib/model/ai-build-job.d.ts +16 -1
- package/src/lib/model/ai-build-job.js +40 -0
- package/src/lib/model/ai-build-job.js.map +1 -1
- package/src/lib/model/ai-job-input.d.ts +33 -0
- package/src/lib/model/ai-job-input.js +59 -0
- package/src/lib/model/ai-job-input.js.map +1 -0
- package/src/lib/model/ai-job-notice.d.ts +4 -0
- package/src/lib/model/ai-job-notice.js +11 -1
- package/src/lib/model/ai-job-notice.js.map +1 -1
- package/src/lib/model/ai-jobs.types.d.ts +40 -1
- package/src/lib/model/ai-jobs.types.js.map +1 -1
- package/src/lib/model/ai-site-details.d.ts +122 -0
- package/src/lib/model/ai-site-details.js +300 -0
- package/src/lib/model/ai-site-details.js.map +1 -0
- package/src/lib/model/ai-site-entity.d.ts +181 -0
- package/src/lib/model/ai-site-entity.js +390 -0
- package/src/lib/model/ai-site-entity.js.map +1 -0
- package/src/lib/model/ai-site-inspiration.d.ts +72 -0
- package/src/lib/model/ai-site-inspiration.js +109 -0
- package/src/lib/model/ai-site-inspiration.js.map +1 -0
- package/src/lib/model/ai-site-job.d.ts +13 -1
- package/src/lib/model/ai-site-job.js +15 -2
- package/src/lib/model/ai-site-job.js.map +1 -1
- package/src/lib/model/ai-site-kinds.js +109 -21
- package/src/lib/model/ai-site-kinds.js.map +1 -1
- package/src/lib/model/ai-site-look.d.ts +10 -0
- package/src/lib/model/ai-site-look.js +24 -0
- package/src/lib/model/ai-site-look.js.map +1 -1
- package/src/lib/model/ai-site-start-seo.d.ts +19 -5
- package/src/lib/model/ai-site-start-seo.js +25 -7
- package/src/lib/model/ai-site-start-seo.js.map +1 -1
- package/src/lib/model/ai-site-start-steps.d.ts +9 -3
- package/src/lib/model/ai-site-start-steps.js +67 -5
- package/src/lib/model/ai-site-start-steps.js.map +1 -1
- package/src/lib/model/ai-site-start.d.ts +68 -4
- package/src/lib/model/ai-site-start.js +166 -13
- package/src/lib/model/ai-site-start.js.map +1 -1
- package/src/lib/model/ai-upsell-copy.js +4 -1
- package/src/lib/model/ai-upsell-copy.js.map +1 -1
- package/src/lib/plan-entitlements.d.ts +4 -3
- package/src/lib/plan-entitlements.js +3 -8
- package/src/lib/plan-entitlements.js.map +1 -1
- package/src/lib/runtime/ai-dataset-generation.d.ts +8 -1
- package/src/lib/runtime/ai-dataset-generation.js +12 -2
- package/src/lib/runtime/ai-dataset-generation.js.map +1 -1
- package/src/lib/runtime/ai-doctrine-validators.d.ts +26 -33
- package/src/lib/runtime/ai-doctrine-validators.js +54 -44
- package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
- package/src/lib/runtime/ai-doctrine.js +1 -1
- package/src/lib/runtime/ai-doctrine.js.map +1 -1
- package/src/lib/runtime/ai-node-tree.d.ts +7 -0
- package/src/lib/runtime/ai-node-tree.js +9 -1
- package/src/lib/runtime/ai-node-tree.js.map +1 -1
- package/src/lib/server/ai-create-route.d.ts +1 -1
- package/src/lib/server/ai-create-route.js +3 -4
- package/src/lib/server/ai-create-route.js.map +1 -1
- package/src/lib/server/ai-jobs-resume.js +27 -3
- package/src/lib/server/ai-jobs-resume.js.map +1 -1
- package/src/lib/server/ai-jobs-route.js +7 -0
- package/src/lib/server/ai-jobs-route.js.map +1 -1
- package/src/lib/usage/assist-credits.d.ts +4 -4
- package/src/lib/usage/assist-credits.js +4 -4
- package/src/lib/usage/assist-credits.js.map +1 -1
- package/src/lib/usage/staff-org-ai-view.js +6 -3
- package/src/lib/usage/staff-org-ai-view.js.map +1 -1
- package/src/lib/usage/staff-org-ai.d.ts +4 -2
- package/src/lib/usage/staff-org-ai.js +7 -7
- package/src/lib/usage/staff-org-ai.js.map +1 -1
- package/src/lib/usage/staff-org-usage-ai.js +2 -2
- package/src/lib/usage/staff-org-usage-ai.js.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/runtime/ai-dataset-generation.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 type { AiStepKind } from '../providers/catalog'\nimport type { AiProvider } from '../providers/contract'\nimport { AI_ROUTING_TABLE, type AiPluginSettings } from '../providers/routing'\nimport {\n AI_DATASET_LIMITS,\n AI_DATASET_LIST_SEPARATOR,\n AI_DATASET_TOOL,\n AI_DATASET_TOOL_NAME,\n checkAiDataset,\n type AiDataset,\n} from '../tools/ai-dataset-tool'\nimport { runValidatedGeneration, type AiValidatedGeneration } from './ai-doctrine'\nimport type { AiSystemBlock } from './ai-runtime'\n\n/**\n * A SITE'S DATASETS (AGL-3616): the typed fields and first records of one\n * dataset a site plan created, through the doctrine's generation call and the\n * strict `submit_dataset` tool. The data plugin's writer stores what it\n * answers; nothing here writes.\n *\n * Routed as `job.products`, the row a store's first products are proposed on\n * (no thinking, a structured list from a brief, held to the storefront claim\n * rules): one dataset of a dozen records is the same work. Its answer is held\n * to a ceiling of its own under that row's. The rules are cached and\n * byte-identical; the site's words, the dataset and the pages that show it\n * ride in the user turn.\n */\n\n/** The step a dataset is routed as. */\nexport const AI_DATASET_STEP: AiStepKind = 'job.products'\n\n/**\n * One dataset's answer ceiling: twelve fields and twelve records of a few\n * sentences each, written as JSON, about 9,000 characters at three a token\n * with room; under the routing row's.\n */\nexport const AI_DATASET_MAX_TOKENS = Math.min(4_000, AI_ROUTING_TABLE[AI_DATASET_STEP].maxTokens)\n\n/** The generation kind a dataset is asked under, which the doctrine scopes. */\nexport const AI_DATASET_KIND = 'dataset'\n\n/** The rules for one dataset. Byte-identical on every request. */\nexport const AI_DATASET_INSTRUCTIONS: AiSystemBlock[] = [\n {\n text:\n 'You design one dataset of a new website: a list of like things — a menu, a team, services, portfolio pieces, events, questions and answers — kept as records the owner edits in one place, which the site’s pages list.\\n\\n' +\n `Answer by calling ${AI_DATASET_TOOL_NAME} exactly once. A reply in prose cannot be used.\\n\\n` +\n 'Rules:\\n' +\n [\n 'Keep the planned fields, in order and named exactly as planned; the pages around the dataset already name them. Add a field only where the records clearly need it.',\n 'Type each field: text for words, including a date or a time written the way a visitor reads it; number or integer only for a figure a visitor compares; boolean for yes or no; list for a few short tags. The first field names each record and is text.',\n `Write ${AI_DATASET_LIMITS.recordsMin} to ${AI_DATASET_LIMITS.recordsMax} records, as many as the brief supports: what the business actually offers, in its own words where the brief gives them, otherwise plain and general enough to be true of it.`,\n 'Never invent a fact: no price, date, address, phone number, award, credential, client or number the brief does not give, and no review, testimonial, rating or quote from anyone. Leave a value \"\" rather than make one up.',\n 'Never give a person a name the brief does not give: a team member the brief does not name is their role, such as \"Head chef\".',\n 'Never say anything cures, treats, heals or prevents anything, and never promise a health, financial or legal result.',\n `Values are plain text with no links, markup, emoji or square brackets, at most ${AI_DATASET_LIMITS.valueMax} characters each; a description is one to three sentences.`,\n 'Write in the language of the brief.',\n ]\n .map((rule) => `- ${rule}`)\n .join('\\n'),\n cacheBreakpoint: true,\n },\n]\n\nexport interface AiDatasetPromptInput {\n /** The site's words: the brief and its answers, as a unit's brief carries them. */\n brief: string\n /** The dataset as the plan named it, and why it has one. */\n name: string\n why: string\n /** The field names the plan gave it. */\n fields: readonly string[]\n /** The sections that list it, by page: \"Menu › Our dishes (12 items)\". */\n shownIn: readonly string[]\n /** Whether each record also gets a page of its own. */\n recordPages: boolean\n}\n\n/** The user turn: the site's words, the dataset, and where it is shown. */\nexport function aiDatasetPrompt(input: AiDatasetPromptInput): string {\n return [\n 'Brief:',\n input.brief.trim(),\n `Dataset: “${input.name}” — ${input.why.trim() || 'the site’s structured content'}`,\n `Planned fields: ${input.fields.length ? input.fields.map((field) => `“${field}”`).join(', ') : '(none: choose them)'}`,\n input.shownIn.length ? `Listed on: ${input.shownIn.join('; ')}.` : 'Listed on the site’s pages.',\n input.recordPages\n ? 'Each record also gets a page of its own, so give each one enough to read: a sentence or two describing it.'\n : 'Each record is shown as a card, so keep its values short.',\n ].join('\\n')\n}\n\nexport interface GenerateAiDatasetInput extends AiDatasetPromptInput {\n /** What a claim or a price may be quoted from: the brief and the site's answers. */\n merchantWords: string\n settings?: AiPluginSettings\n model?: string\n maxTokens?: number\n signal?: AbortSignal\n provider?: AiProvider\n}\n\n/** Design one dataset. It writes nothing to the site. */\nexport function generateAiDataset(input: GenerateAiDatasetInput): Promise<AiValidatedGeneration<AiDataset>> {\n const row = AI_ROUTING_TABLE[AI_DATASET_STEP]\n return runValidatedGeneration(AI_DATASET_KIND, {\n step: AI_DATASET_STEP,\n ...(input.settings ? { settings: input.settings } : {}),\n ...(input.model ? { model: input.model } : {}),\n instructions: AI_DATASET_INSTRUCTIONS,\n messages: [{ role: 'user', content: aiDatasetPrompt(input) }],\n tool: AI_DATASET_TOOL,\n maxTokens: input.maxTokens ?? AI_DATASET_MAX_TOKENS,\n ...(row.thinking ? { thinking: row.thinking } : {}),\n ...(row.effort ? { effort: row.effort } : {}),\n ...(input.signal ? { signal: input.signal } : {}),\n ...(input.provider ? { provider: input.provider } : {}),\n check: (answer) => checkAiDataset(answer, { planned: input.fields, merchantWords: input.merchantWords }),\n }) as Promise<AiValidatedGeneration<AiDataset>>\n}\n\n/** A designed dataset as the data plugin's `dataset` writer takes it: values by field name. */\nexport function aiDatasetDraftContent(\n name: string,\n dataset: AiDataset,\n options: { recordPages: boolean },\n): Record<string, unknown> {\n const records = dataset.records.map((values) => {\n const record: Record<string, unknown> = {}\n dataset.fields.forEach((field, column) => {\n const value = (values[column] ?? '').trim()\n if (!value) return\n if (field.type === 'list') {\n record[field.name] = value.split(AI_DATASET_LIST_SEPARATOR.trim()).map((part) => part.trim()).filter(Boolean)\n } else if (field.type === 'number' || field.type === 'integer') {\n record[field.name] = value.replace(/,/g, '')\n } else {\n record[field.name] = value\n }\n })\n return record\n })\n return {\n name,\n fields: dataset.fields.map((field) => ({ name: field.name, type: field.type })),\n records,\n // A record page shows each record at an address made from its name.\n ...(options.recordPages && dataset.fields[0] ? { pageAddressFrom: dataset.fields[0].name } : {}),\n }\n}\n"],"names":["AI_ROUTING_TABLE","AI_DATASET_LIMITS","AI_DATASET_LIST_SEPARATOR","AI_DATASET_TOOL","AI_DATASET_TOOL_NAME","checkAiDataset","runValidatedGeneration","AI_DATASET_STEP","AI_DATASET_MAX_TOKENS","Math","min","maxTokens","AI_DATASET_KIND","AI_DATASET_INSTRUCTIONS","text","recordsMin","recordsMax","valueMax","map","rule","join","cacheBreakpoint","aiDatasetPrompt","input","brief","trim","name","why","fields","length","field","shownIn","recordPages","generateAiDataset","row","step","settings","model","instructions","messages","role","content","tool","thinking","effort","signal","provider","check","answer","planned","merchantWords","aiDatasetDraftContent","dataset","options","records","values","record","forEach","column","value","type","split","part","filter","Boolean","replace","pageAddressFrom"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/runtime/ai-dataset-generation.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 type { AiStepKind } from '../providers/catalog'\nimport type { AiProvider } from '../providers/contract'\nimport { AI_ROUTING_TABLE, type AiPluginSettings } from '../providers/routing'\nimport {\n AI_DATASET_LIMITS,\n AI_DATASET_LIST_SEPARATOR,\n AI_DATASET_TOOL,\n AI_DATASET_TOOL_NAME,\n checkAiDataset,\n type AiDataset,\n} from '../tools/ai-dataset-tool'\nimport { runValidatedGeneration, type AiValidatedGeneration } from './ai-doctrine'\nimport { aiLayoutArticles } from '../layout-language/ai-layout-copy'\nimport type { AiSystemBlock } from './ai-runtime'\n\n/**\n * A SITE'S DATASETS (AGL-3616): the typed fields and first records of one\n * dataset a site plan created, through the doctrine's generation call and the\n * strict `submit_dataset` tool. The data plugin's writer stores what it\n * answers; nothing here writes.\n *\n * Routed as `job.products`, the row a store's first products are proposed on\n * (no thinking, a structured list from a brief, held to the storefront claim\n * rules): one dataset of a dozen records is the same work. Its answer is held\n * to a ceiling of its own under that row's. The rules are cached and\n * byte-identical; the site's words, the dataset and the pages that show it\n * ride in the user turn.\n */\n\n/** The step a dataset is routed as. */\nexport const AI_DATASET_STEP: AiStepKind = 'job.products'\n\n/**\n * One dataset's answer ceiling: twelve fields and twelve records of a few\n * sentences each, written as JSON, about 9,000 characters at three a token\n * with room; under the routing row's.\n */\nexport const AI_DATASET_MAX_TOKENS = Math.min(4_000, AI_ROUTING_TABLE[AI_DATASET_STEP].maxTokens)\n\n/** The generation kind a dataset is asked under, which the doctrine scopes. */\nexport const AI_DATASET_KIND = 'dataset'\n\n/** The rules for one dataset. Byte-identical on every request. */\nexport const AI_DATASET_INSTRUCTIONS: AiSystemBlock[] = [\n {\n text:\n 'You design one dataset of a new website: a list of like things — a menu, a team, services, portfolio pieces, events, questions and answers — kept as records the owner edits in one place, which the site’s pages list.\\n\\n' +\n `Answer by calling ${AI_DATASET_TOOL_NAME} exactly once. A reply in prose cannot be used.\\n\\n` +\n 'Rules:\\n' +\n [\n 'Keep the planned fields, in order and named exactly as planned; the pages around the dataset already name them. Add a field only where the records clearly need it.',\n 'Type each field: text for words, including a date or a time written the way a visitor reads it; number or integer only for a figure a visitor compares; boolean for yes or no; list for a few short tags. The first field names each record and is text.',\n `Write ${AI_DATASET_LIMITS.recordsMin} to ${AI_DATASET_LIMITS.recordsMax} records, as many as the brief supports: what the business actually offers, in its own words where the brief gives them, otherwise plain and general enough to be true of it.`,\n 'Never invent a fact: no price, date, address, phone number, award, credential, client or number the brief does not give, and no review, testimonial, rating or quote from anyone. Leave a value \"\" rather than make one up.',\n 'Never give a person a name the brief does not give: a team member the brief does not name is their role, such as \"Head chef\".',\n 'Never say anything cures, treats, heals or prevents anything, and never promise a health, financial or legal result.',\n `Values are plain text with no links, markup, emoji or square brackets, at most ${AI_DATASET_LIMITS.valueMax} characters each; a description is one to three sentences.`,\n 'Write in the language of the brief.',\n ]\n .map((rule) => `- ${rule}`)\n .join('\\n'),\n cacheBreakpoint: true,\n },\n]\n\nexport interface AiDatasetPromptInput {\n /** The site's words: the brief and its answers, as a unit's brief carries them. */\n brief: string\n /** The dataset as the plan named it, and why it has one. */\n name: string\n why: string\n /** The field names the plan gave it. */\n fields: readonly string[]\n /** The sections that list it, by page: \"Menu › Our dishes (12 items)\". */\n shownIn: readonly string[]\n /** Whether each record also gets a page of its own. */\n recordPages: boolean\n}\n\n/** The user turn: the site's words, the dataset, and where it is shown. */\nexport function aiDatasetPrompt(input: AiDatasetPromptInput): string {\n return [\n 'Brief:',\n input.brief.trim(),\n `Dataset: “${input.name}” — ${input.why.trim() || 'the site’s structured content'}`,\n `Planned fields: ${input.fields.length ? input.fields.map((field) => `“${field}”`).join(', ') : '(none: choose them)'}`,\n input.shownIn.length ? `Listed on: ${input.shownIn.join('; ')}.` : 'Listed on the site’s pages.',\n input.recordPages\n ? 'Each record also gets a page of its own, so give each one enough to read: a sentence or two describing it.'\n : 'Each record is shown as a card, so keep its values short.',\n ].join('\\n')\n}\n\nexport interface GenerateAiDatasetInput extends AiDatasetPromptInput {\n /** What a claim or a price may be quoted from: the brief and the site's answers. */\n merchantWords: string\n settings?: AiPluginSettings\n model?: string\n maxTokens?: number\n signal?: AbortSignal\n provider?: AiProvider\n}\n\n/** Design one dataset. It writes nothing to the site. */\nexport function generateAiDataset(input: GenerateAiDatasetInput): Promise<AiValidatedGeneration<AiDataset>> {\n const row = AI_ROUTING_TABLE[AI_DATASET_STEP]\n return runValidatedGeneration(AI_DATASET_KIND, {\n step: AI_DATASET_STEP,\n ...(input.settings ? { settings: input.settings } : {}),\n ...(input.model ? { model: input.model } : {}),\n instructions: AI_DATASET_INSTRUCTIONS,\n messages: [{ role: 'user', content: aiDatasetPrompt(input) }],\n tool: AI_DATASET_TOOL,\n maxTokens: input.maxTokens ?? AI_DATASET_MAX_TOKENS,\n ...(row.thinking ? { thinking: row.thinking } : {}),\n ...(row.effort ? { effort: row.effort } : {}),\n ...(input.signal ? { signal: input.signal } : {}),\n ...(input.provider ? { provider: input.provider } : {}),\n check: (answer) => checkAiDataset(answer, { planned: input.fields, merchantWords: input.merchantWords }),\n }) as Promise<AiValidatedGeneration<AiDataset>>\n}\n\n/**\n * A designed dataset as the data plugin's `dataset` writer takes it: values by\n * field name. Its words' \"a\" and \"an\" agree with what follows them in English\n * (`aiLayoutArticles`, AGL-3988), as a page's do: the beta.270 Sugar Hollow\n * packages said \"A easygoing session\" in their records and on every page\n * that listed them.\n */\nexport function aiDatasetDraftContent(\n name: string,\n dataset: AiDataset,\n options: { recordPages: boolean; language?: string | null },\n): Record<string, unknown> {\n const said = (value: string) => aiLayoutArticles(value, options.language)\n const records = dataset.records.map((values) => {\n const record: Record<string, unknown> = {}\n dataset.fields.forEach((field, column) => {\n const value = (values[column] ?? '').trim()\n if (!value) return\n if (field.type === 'list') {\n record[field.name] = value.split(AI_DATASET_LIST_SEPARATOR.trim()).map((part) => said(part.trim())).filter(Boolean)\n } else if (field.type === 'number' || field.type === 'integer') {\n record[field.name] = value.replace(/,/g, '')\n } else if (field.type === 'text') {\n record[field.name] = said(value)\n } else {\n record[field.name] = value\n }\n })\n return record\n })\n return {\n name,\n fields: dataset.fields.map((field) => ({ name: field.name, type: field.type })),\n records,\n // A record page shows each record at an address made from its name.\n ...(options.recordPages && dataset.fields[0] ? { pageAddressFrom: dataset.fields[0].name } : {}),\n }\n}\n"],"names":["AI_ROUTING_TABLE","AI_DATASET_LIMITS","AI_DATASET_LIST_SEPARATOR","AI_DATASET_TOOL","AI_DATASET_TOOL_NAME","checkAiDataset","runValidatedGeneration","aiLayoutArticles","AI_DATASET_STEP","AI_DATASET_MAX_TOKENS","Math","min","maxTokens","AI_DATASET_KIND","AI_DATASET_INSTRUCTIONS","text","recordsMin","recordsMax","valueMax","map","rule","join","cacheBreakpoint","aiDatasetPrompt","input","brief","trim","name","why","fields","length","field","shownIn","recordPages","generateAiDataset","row","step","settings","model","instructions","messages","role","content","tool","thinking","effort","signal","provider","check","answer","planned","merchantWords","aiDatasetDraftContent","dataset","options","said","value","language","records","values","record","forEach","column","type","split","part","filter","Boolean","replace","pageAddressFrom"],"mappings":"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"}
|
|
@@ -1242,39 +1242,32 @@ export declare function aiFreePageSectionsWithin(creations: {
|
|
|
1242
1242
|
pages?: number;
|
|
1243
1243
|
}, credits?: Readonly<AiFreePageWorstCase>): number;
|
|
1244
1244
|
/**
|
|
1245
|
-
*
|
|
1246
|
-
*
|
|
1247
|
-
*
|
|
1248
|
-
*
|
|
1249
|
-
*
|
|
1250
|
-
*
|
|
1251
|
-
*
|
|
1252
|
-
*
|
|
1253
|
-
*
|
|
1254
|
-
*
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
*
|
|
1259
|
-
*
|
|
1260
|
-
*
|
|
1261
|
-
*
|
|
1262
|
-
*
|
|
1263
|
-
*
|
|
1264
|
-
*
|
|
1265
|
-
*
|
|
1266
|
-
*
|
|
1267
|
-
*
|
|
1268
|
-
*
|
|
1269
|
-
*
|
|
1270
|
-
*
|
|
1271
|
-
* 7 + 1, and the recorded yoga answer's 6 + 4 becomes 5 + 3, the shape its
|
|
1272
|
-
* own redo chose.
|
|
1273
|
-
*
|
|
1274
|
-
* A plan more than `AI_FREE_WALL_SETTLE_MAX_OVER` past the wall, a site
|
|
1275
|
-
* start past its page cap, a plan with a list split into sections, and a
|
|
1276
|
-
* plan the trim cannot fit without a section it keeps are returned
|
|
1277
|
-
* unchanged, for the wall to re-ask.
|
|
1245
|
+
* A Free plan past the wall is trimmed to the wall before the rules read the
|
|
1246
|
+
* plan (AGL-3737, AGL-3969), rather than re-asked: a plan over its budget is
|
|
1247
|
+
* the model's mistake, never the member's, and which sections go has one
|
|
1248
|
+
* answer. The live candle-shop start of 2026-10-12 asked for a home of 7 and
|
|
1249
|
+
* a second page of 2 against a wall of 8, three answers running, and stopped
|
|
1250
|
+
* needing input; the Free candle shop of the beta.265 eval asked for 11, and
|
|
1251
|
+
* its re-ask still for more than 8, and was refused (AGL-3969).
|
|
1252
|
+
*
|
|
1253
|
+
* One section goes at a time, exactly as many as the plan is over, so the
|
|
1254
|
+
* plan keeps the whole budget. Each goes from the lowest tier any page still
|
|
1255
|
+
* has: first a section `freeWallKeeps` does not hold; then one it holds only
|
|
1256
|
+
* by its name (a contact, a call to action, a storefront's sign-up); last one
|
|
1257
|
+
* that places something every use of which another section still places, so
|
|
1258
|
+
* no creation is left unplaced. Within a tier it is the last such section of
|
|
1259
|
+
* the page furthest past its share: the home at / past its fewest
|
|
1260
|
+
* (`aiSiteHomeMinSections`, five on a site start whose wall pays for a full
|
|
1261
|
+
* home), any other page past two; on a tie, the longer page, then the home.
|
|
1262
|
+
* No home goes under its fewest, no page under one section, and no page loses
|
|
1263
|
+
* its opening or a Shop page its product grid. The shares are what a site
|
|
1264
|
+
* start is told to plan (a home of five or six, the other page two or three):
|
|
1265
|
+
* the candle shop's 7 + 2 becomes 6 + 2, never 7 + 1, and the recorded yoga
|
|
1266
|
+
* answer's 6 + 4 becomes 5 + 3, the shape its own redo chose.
|
|
1267
|
+
*
|
|
1268
|
+
* A site start past its page cap and a plan with a list split into sections
|
|
1269
|
+
* are returned unchanged, for their re-ask; so is the rare plan whose every
|
|
1270
|
+
* section past the wall is one no tier may take.
|
|
1278
1271
|
*/
|
|
1279
1272
|
export declare function aiSettlePlanFreeWall(plan: AiBuildPlan, inventory: AiSiteInventory | null, capabilities?: AiPlanCapabilities | null): AiBuildPlan;
|
|
1280
1273
|
/**
|
|
@@ -5263,24 +5263,13 @@ function slugKey(slug) {
|
|
|
5263
5263
|
homeMin
|
|
5264
5264
|
};
|
|
5265
5265
|
}
|
|
5266
|
-
/**
|
|
5267
|
-
* The most sections past the Free wall a plan is trimmed by rather than
|
|
5268
|
-
* re-asked (AGL-3737). The live candle-shop start of 2026-10-12 planned 9
|
|
5269
|
-
* sections against a wall of 8 on all three answers, each with a home of 7:
|
|
5270
|
-
* the model reaching for the budget the site redo names ("plan 7 to 8") and
|
|
5271
|
-
* landing one band past it, which no re-ask cured. Within two, the plan's
|
|
5272
|
-
* shape is right and only a band or two the brief needs least is extra, so
|
|
5273
|
-
* taking those from the end loses nothing the plan depends on. Further over,
|
|
5274
|
-
* the shape itself is off — a list planned as sections, a page the wall
|
|
5275
|
-
* cannot pay for — and cutting more would drop content the model meant, so
|
|
5276
|
-
* that plan is still re-asked.
|
|
5277
|
-
*/ export const AI_FREE_WALL_SETTLE_MAX_OVER = 2;
|
|
5278
5266
|
/** A section through which a visitor reaches the owner: contact, a visit, a booking. */ const REACH_SECTION_NAME = /\b(?:contact|get in touch|visit(?: us)?|find us|locations?|hours|book(?:ing)?|reserve|reservations?)\b/i;
|
|
5279
5267
|
/** A section that asks a visitor to act: a call to action, "Start your practice", "Get started". */ const CALL_TO_ACTION_NAME = /\b(?:call to action|cta|get started|start (?:your|a|here|now|today)|join (?:us|now|today|the)|ready to)\b/i;
|
|
5280
5268
|
/**
|
|
5281
|
-
* Whether the Free wall's trim keeps a section of a page
|
|
5282
|
-
*
|
|
5283
|
-
*
|
|
5269
|
+
* Whether the Free wall's trim keeps a section of a page while the plan has
|
|
5270
|
+
* any other to take (AGL-3737, AGL-3969): the page's opening, any section
|
|
5271
|
+
* that places something (a dataset it lists, a form, a component — dropping
|
|
5272
|
+
* it would leave a creation unplaced), one that
|
|
5284
5273
|
* collects answers, says how to reach the owner or asks a visitor to act
|
|
5285
5274
|
* (AGL-3899: a home's call to action is its way to the form), and a storefront's
|
|
5286
5275
|
* listing parts — the bestsellers, the collections, the sign-up, and a Shop
|
|
@@ -5297,31 +5286,37 @@ function slugKey(slug) {
|
|
|
5297
5286
|
return aiLayoutIsShopPage(screen) && aiLayoutShopGridSection(screen.sections) === index;
|
|
5298
5287
|
}
|
|
5299
5288
|
/**
|
|
5300
|
-
* A Free plan
|
|
5301
|
-
*
|
|
5302
|
-
*
|
|
5303
|
-
* candle-shop start of 2026-10-12 asked for a home of 7 and
|
|
5304
|
-
* 2 against a wall of 8, three answers running, and stopped
|
|
5289
|
+
* A Free plan past the wall is trimmed to the wall before the rules read the
|
|
5290
|
+
* plan (AGL-3737, AGL-3969), rather than re-asked: a plan over its budget is
|
|
5291
|
+
* the model's mistake, never the member's, and which sections go has one
|
|
5292
|
+
* answer. The live candle-shop start of 2026-10-12 asked for a home of 7 and
|
|
5293
|
+
* a second page of 2 against a wall of 8, three answers running, and stopped
|
|
5294
|
+
* needing input; the Free candle shop of the beta.265 eval asked for 11, and
|
|
5295
|
+
* its re-ask still for more than 8, and was refused (AGL-3969).
|
|
5305
5296
|
*
|
|
5306
|
-
* One section goes at a time, the
|
|
5307
|
-
*
|
|
5308
|
-
*
|
|
5309
|
-
*
|
|
5310
|
-
*
|
|
5311
|
-
*
|
|
5312
|
-
*
|
|
5313
|
-
*
|
|
5314
|
-
*
|
|
5297
|
+
* One section goes at a time, exactly as many as the plan is over, so the
|
|
5298
|
+
* plan keeps the whole budget. Each goes from the lowest tier any page still
|
|
5299
|
+
* has: first a section `freeWallKeeps` does not hold; then one it holds only
|
|
5300
|
+
* by its name (a contact, a call to action, a storefront's sign-up); last one
|
|
5301
|
+
* that places something every use of which another section still places, so
|
|
5302
|
+
* no creation is left unplaced. Within a tier it is the last such section of
|
|
5303
|
+
* the page furthest past its share: the home at / past its fewest
|
|
5304
|
+
* (`aiSiteHomeMinSections`, five on a site start whose wall pays for a full
|
|
5305
|
+
* home), any other page past two; on a tie, the longer page, then the home.
|
|
5306
|
+
* No home goes under its fewest, no page under one section, and no page loses
|
|
5307
|
+
* its opening or a Shop page its product grid. The shares are what a site
|
|
5308
|
+
* start is told to plan (a home of five or six, the other page two or three):
|
|
5309
|
+
* the candle shop's 7 + 2 becomes 6 + 2, never 7 + 1, and the recorded yoga
|
|
5310
|
+
* answer's 6 + 4 becomes 5 + 3, the shape its own redo chose.
|
|
5315
5311
|
*
|
|
5316
|
-
* A
|
|
5317
|
-
*
|
|
5318
|
-
*
|
|
5319
|
-
* unchanged, for the wall to re-ask.
|
|
5312
|
+
* A site start past its page cap and a plan with a list split into sections
|
|
5313
|
+
* are returned unchanged, for their re-ask; so is the rare plan whose every
|
|
5314
|
+
* section past the wall is one no tier may take.
|
|
5320
5315
|
*/ export function aiSettlePlanFreeWall(plan, inventory, capabilities = null) {
|
|
5321
5316
|
const wall = freePlanWall(plan, inventory, capabilities);
|
|
5322
5317
|
if (!wall || wall.overPages) return plan;
|
|
5323
5318
|
const over = wall.asked - wall.fits;
|
|
5324
|
-
if (over <= 0
|
|
5319
|
+
if (over <= 0) return plan;
|
|
5325
5320
|
// A list split into sections is joined by its re-ask, which frees the room;
|
|
5326
5321
|
// a trim would cut one of its items and hide the split from the rule.
|
|
5327
5322
|
if (detectPlanSplitLists(plan, inventory, capabilities).length) return plan;
|
|
@@ -5332,27 +5327,42 @@ function slugKey(slug) {
|
|
|
5332
5327
|
const home = plan.screens.findIndex(aiSitePlanIsHome);
|
|
5333
5328
|
const floor = (screenIndex)=>screenIndex === home ? Math.max(wall.homeMin, 1) : 1;
|
|
5334
5329
|
const target = (screenIndex)=>screenIndex === home ? Math.max(wall.homeMin, 1) : 2;
|
|
5335
|
-
//
|
|
5336
|
-
const
|
|
5330
|
+
// Whether another kept section places every use of this one.
|
|
5331
|
+
const placedElsewhere = (screenIndex, at)=>kept[screenIndex][at].section.uses.every((use)=>kept.some((entries, other)=>entries.some((entry, place)=>(other !== screenIndex || place !== at) && entry.section.uses.includes(use))));
|
|
5332
|
+
// Whether the trim may take a page's section on a tier: 0 one the page does
|
|
5333
|
+
// not hold, 1 one it holds by name only, 2 a placement another still makes.
|
|
5334
|
+
const takes = (screenIndex, at, tier)=>{
|
|
5335
|
+
const screen = plan.screens[screenIndex];
|
|
5336
|
+
const { section, index } = kept[screenIndex][at];
|
|
5337
|
+
if (!freeWallKeeps(screen, index)) return true;
|
|
5338
|
+
if (tier === 0 || aiLayoutIsShopPage(screen) && aiLayoutShopGridSection(screen.sections) === index) return false;
|
|
5339
|
+
return section.uses.length === 0 || tier === 2 && placedElsewhere(screenIndex, at);
|
|
5340
|
+
};
|
|
5341
|
+
// The last section of a page the trim may take on a tier, or -1.
|
|
5342
|
+
const last = (screenIndex, tier)=>{
|
|
5337
5343
|
const entries = kept[screenIndex];
|
|
5338
5344
|
if (entries.length <= floor(screenIndex)) return -1;
|
|
5339
5345
|
for(let at = entries.length - 1; at > 0; at -= 1){
|
|
5340
|
-
if (
|
|
5346
|
+
if (takes(screenIndex, at, tier)) return at;
|
|
5341
5347
|
}
|
|
5342
5348
|
return -1;
|
|
5343
5349
|
};
|
|
5344
5350
|
for(let left = over; left > 0; left -= 1){
|
|
5345
5351
|
let pick = -1;
|
|
5346
|
-
|
|
5347
|
-
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
|
|
5351
|
-
|
|
5352
|
+
let tier = -1;
|
|
5353
|
+
while(pick === -1 && tier < 2){
|
|
5354
|
+
tier += 1;
|
|
5355
|
+
for(let index = 0; index < kept.length; index += 1){
|
|
5356
|
+
if (last(index, tier) === -1) continue;
|
|
5357
|
+
const room = kept[index].length - target(index);
|
|
5358
|
+
const best = pick === -1 ? null : kept[pick].length - target(pick);
|
|
5359
|
+
if (best === null || room > best || room === best && (kept[index].length > kept[pick].length || kept[index].length === kept[pick].length && index === home)) {
|
|
5360
|
+
pick = index;
|
|
5361
|
+
}
|
|
5352
5362
|
}
|
|
5353
5363
|
}
|
|
5354
5364
|
if (pick === -1) return plan;
|
|
5355
|
-
kept[pick].splice(last(pick), 1);
|
|
5365
|
+
kept[pick].splice(last(pick, tier), 1);
|
|
5356
5366
|
}
|
|
5357
5367
|
return _extends({}, plan, {
|
|
5358
5368
|
screens: plan.screens.map((screen, index)=>kept[index].length === screen.sections.length ? screen : _extends({}, screen, {
|