@aglyn/plugins-ai 1.0.0-beta.246 → 1.0.0-beta.249
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 +5 -1
- package/src/lib/activity/ai-activity-actions.js.map +1 -1
- package/src/lib/components/ai-job-links.js +14 -0
- package/src/lib/components/ai-job-links.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 +92 -19
- package/src/lib/components/ai-site-start-card.component.js.map +1 -1
- package/src/lib/declarations.server.js +12 -0
- package/src/lib/declarations.server.js.map +1 -1
- package/src/lib/jobs/ai-build-capabilities.js +56 -2
- package/src/lib/jobs/ai-build-capabilities.js.map +1 -1
- package/src/lib/jobs/ai-job-build-step.d.ts +3 -8
- package/src/lib/jobs/ai-job-build-step.js +49 -12
- package/src/lib/jobs/ai-job-build-step.js.map +1 -1
- package/src/lib/jobs/ai-job-form-dataset.d.ts +8 -5
- package/src/lib/jobs/ai-job-form-dataset.js +28 -10
- package/src/lib/jobs/ai-job-form-dataset.js.map +1 -1
- package/src/lib/jobs/ai-job-form-step.d.ts +20 -4
- package/src/lib/jobs/ai-job-form-step.js +98 -28
- package/src/lib/jobs/ai-job-form-step.js.map +1 -1
- package/src/lib/jobs/ai-job-layout-language.d.ts +6 -2
- package/src/lib/jobs/ai-job-layout-language.js +16 -5
- package/src/lib/jobs/ai-job-layout-language.js.map +1 -1
- package/src/lib/jobs/ai-job-layout-step.js +4 -1
- package/src/lib/jobs/ai-job-layout-step.js.map +1 -1
- package/src/lib/jobs/ai-job-media-step.d.ts +239 -0
- package/src/lib/jobs/ai-job-media-step.js +610 -0
- package/src/lib/jobs/ai-job-media-step.js.map +1 -0
- package/src/lib/jobs/ai-job-page-language.d.ts +2 -0
- package/src/lib/jobs/ai-job-page-language.js +9 -0
- package/src/lib/jobs/ai-job-page-language.js.map +1 -1
- package/src/lib/jobs/ai-job-page-sections.js +4 -3
- package/src/lib/jobs/ai-job-page-sections.js.map +1 -1
- package/src/lib/jobs/ai-job-page-step.js +3 -2
- package/src/lib/jobs/ai-job-page-step.js.map +1 -1
- package/src/lib/jobs/ai-job-plan-step.d.ts +10 -1
- package/src/lib/jobs/ai-job-plan-step.js +73 -15
- package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
- package/src/lib/jobs/ai-job-settings-step.d.ts +0 -4
- package/src/lib/jobs/ai-job-settings-step.js +2 -7
- package/src/lib/jobs/ai-job-settings-step.js.map +1 -1
- package/src/lib/jobs/ai-job-site-content.d.ts +2 -2
- package/src/lib/jobs/ai-job-site-content.js +5 -3
- package/src/lib/jobs/ai-job-site-content.js.map +1 -1
- package/src/lib/jobs/ai-job-site-datasets.d.ts +1 -1
- package/src/lib/jobs/ai-job-site-datasets.js +3 -2
- package/src/lib/jobs/ai-job-site-datasets.js.map +1 -1
- package/src/lib/jobs/ai-job-site-events.d.ts +148 -0
- package/src/lib/jobs/ai-job-site-events.js +313 -0
- package/src/lib/jobs/ai-job-site-events.js.map +1 -0
- package/src/lib/jobs/ai-job-site-step.d.ts +9 -3
- package/src/lib/jobs/ai-job-site-step.js +63 -17
- package/src/lib/jobs/ai-job-site-step.js.map +1 -1
- package/src/lib/jobs/ai-job-tracking-step.d.ts +184 -0
- package/src/lib/jobs/ai-job-tracking-step.js +501 -0
- package/src/lib/jobs/ai-job-tracking-step.js.map +1 -0
- package/src/lib/jobs/ai-layout-stock-photos.d.ts +41 -0
- package/src/lib/jobs/ai-layout-stock-photos.js +71 -3
- package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -1
- package/src/lib/jobs/ai-site-publish.js +2 -3
- package/src/lib/jobs/ai-site-publish.js.map +1 -1
- package/src/lib/jobs/ai-stock-photo-picker.d.ts +24 -0
- package/src/lib/jobs/ai-stock-photo-picker.js +108 -0
- package/src/lib/jobs/ai-stock-photo-picker.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-jazz-events-build-plan-recording.d.ts +37 -0
- package/src/lib/jobs/fixtures/ai-jazz-events-build-plan-recording.js +47 -0
- package/src/lib/jobs/fixtures/ai-jazz-events-build-plan-recording.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl3760-recordings.d.ts +21 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl3760-recordings.js +128 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl3760-recordings.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl3769-recordings.d.ts +21 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl3769-recordings.js +126 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl3769-recordings.js.map +1 -0
- package/src/lib/layout-language/ai-layout-compiler.d.ts +10 -4
- package/src/lib/layout-language/ai-layout-compiler.js +38 -19
- package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
- package/src/lib/layout-language/ai-layout-frame.d.ts +7 -5
- package/src/lib/layout-language/ai-layout-frame.js +12 -9
- package/src/lib/layout-language/ai-layout-frame.js.map +1 -1
- package/src/lib/layout-language/ai-layout-gaps.js +3 -1
- package/src/lib/layout-language/ai-layout-gaps.js.map +1 -1
- package/src/lib/layout-language/ai-layout-labels.d.ts +70 -0
- package/src/lib/layout-language/ai-layout-labels.js +162 -0
- package/src/lib/layout-language/ai-layout-labels.js.map +1 -0
- package/src/lib/layout-language/ai-layout-links.js +5 -2
- package/src/lib/layout-language/ai-layout-links.js.map +1 -1
- package/src/lib/layout-language/ai-layout-listings.d.ts +14 -1
- package/src/lib/layout-language/ai-layout-listings.js +32 -5
- package/src/lib/layout-language/ai-layout-listings.js.map +1 -1
- package/src/lib/model/ai-build-event-page.d.ts +70 -0
- package/src/lib/model/ai-build-event-page.js +145 -0
- package/src/lib/model/ai-build-event-page.js.map +1 -0
- package/src/lib/model/ai-build-job.d.ts +21 -0
- package/src/lib/model/ai-build-job.js +39 -0
- package/src/lib/model/ai-build-job.js.map +1 -1
- package/src/lib/model/ai-build-plan.d.ts +25 -14
- package/src/lib/model/ai-build-plan.js +33 -23
- package/src/lib/model/ai-build-plan.js.map +1 -1
- package/src/lib/model/ai-job-activity.js +3 -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 +3 -1
- package/src/lib/model/ai-jobs.types.js.map +1 -1
- package/src/lib/model/ai-plan-capabilities.d.ts +8 -0
- package/src/lib/model/ai-plan-capabilities.js.map +1 -1
- package/src/lib/model/ai-site-inventory.d.ts +2 -0
- package/src/lib/model/ai-site-inventory.js +5 -0
- package/src/lib/model/ai-site-inventory.js.map +1 -1
- package/src/lib/model/ai-site-job.d.ts +2 -2
- package/src/lib/model/ai-site-job.js +3 -3
- package/src/lib/model/ai-site-job.js.map +1 -1
- package/src/lib/runtime/ai-doctrine-validators.d.ts +25 -3
- package/src/lib/runtime/ai-doctrine-validators.js +53 -6
- package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
- package/src/lib/runtime/ai-doctrine.d.ts +6 -1
- package/src/lib/runtime/ai-doctrine.js +13 -9
- package/src/lib/runtime/ai-doctrine.js.map +1 -1
- package/src/lib/runtime/ai-eval-live.d.ts +1 -1
- package/src/lib/runtime/ai-eval-live.js +1 -1
- package/src/lib/runtime/ai-eval-live.js.map +1 -1
- package/src/lib/runtime/ai-palette.d.ts +3 -1
- package/src/lib/runtime/ai-palette.generated.js +498 -10
- package/src/lib/runtime/ai-palette.generated.js.map +1 -1
- package/src/lib/runtime/ai-palette.js +5 -3
- package/src/lib/runtime/ai-palette.js.map +1 -1
- package/src/lib/runtime/ai-template-examples.js +8 -2
- package/src/lib/runtime/ai-template-examples.js.map +1 -1
- package/src/lib/server.js +8 -0
- package/src/lib/server.js.map +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-job-media-step.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 { createResourceUid } from '@aglyn/aglyn/app-utils/create-resource-uid'\nimport { MEDIA_ALT_MAX_LENGTH } from '@aglyn/aglyn/app-utils/media-alt'\nimport { embeddedMetadataIsCurrent } from '@aglyn/aglyn/app-utils/media-embedded-fields'\nimport {\n MEDIA_FOLDER_MAX_DEPTH,\n MEDIA_FOLDER_NAME_MAX_LENGTH,\n newMediaFolderDoc,\n normalizeFolderName,\n} from '@aglyn/aglyn/app-utils/media-folders'\nimport {\n MEDIA_TAG_MAX_COUNT,\n MEDIA_TAG_MAX_LENGTH,\n mediaFilterKeys,\n mediaNameWords,\n normalizeMediaTags,\n} from '@aglyn/aglyn/app-utils/media-metadata'\nimport { hostRoleCanWrite } from '@aglyn/aglyn/app-utils/organizations'\nimport type { PluginAiCapabilityArgsSchema } from '@aglyn/aglyn/plugin-manager/plugin-ai-capabilities'\nimport { getLockdownVerdict } from '@aglyn/tenant-data-admin/server/lockdown'\nimport { resolveOrgIdForHost } from '@aglyn/tenant-data-admin/server/organizations'\nimport { FieldValue, type Firestore } from 'firebase-admin/firestore'\nimport type { AiJobOutput } from '../model/ai-jobs.types'\nimport { registerAiJobAdmission, type AiJobAdmission, type AiJobAdmissionRefusal } from './ai-job-admission'\nimport { aiJobEditModel } from './ai-job-edit-step'\nimport { aiLimitReview, aiUnspentOutcome } from './ai-job-generation'\nimport type { AiJobStepOutcome, AiJobStepRunner } from './ai-job-text-step'\nimport { registerAiJobStep } from './ai-jobs'\n\n/**\n * The `media` step (AGL-3752): organizing files already in a site's own media\n * library — the folder each is filed in, its tags, its alt text and its name —\n * as a first-class build operation, so \"put the kiln photos in a Studio\n * folder\", \"tag these portfolio\" or \"write the missing alt text\" is one item\n * on Assist's plan card.\n *\n * NO MODEL. The planner wrote the values as the item's arguments; this holds\n * each to the rule the media library's own controls hold it to and writes it,\n * so it costs no credits.\n *\n * ── Only the library's own fields ────────────────────────────────────────\n *\n * Exactly what the Details drawer and the grid's bulk actions write on a\n * file's document: `fileName` (200), `alt` (`MEDIA_ALT_MAX_LENGTH`), `tags`\n * (`normalizeMediaTags`: lower case, 20 of 40 characters), and `folderId`\n * with the legacy `folder` name beside it, with the library's filter and\n * search keys re-derived from the document as the write leaves it\n * (`mediaFilterKeys`). A new folder is the New folder button's: a\n * `mediaFolders` document made by `newMediaFolderDoc`, its name held by\n * `normalizeFolderName`, unique among its siblings without case, at most\n * `MEDIA_FOLDER_MAX_DEPTH` deep. Filing a file writes its folder as the\n * drawer's save does; the stored object takes the folder's path the next time\n * that folder is moved or renamed, as after a drawer save. Its address never\n * changes, so no page that uses it breaks.\n *\n * NEVER: uploading, copying, replacing or deleting a file, its bytes or the\n * details inside them, its sharing or privacy, renaming or deleting a folder,\n * or anything in the organization's shared library (every site of the\n * workspace uses it). Those are not arguments.\n *\n * ── Alt text ─────────────────────────────────────────────────────────────\n *\n * Alt text describes ONE image: `alt` is for one image the request says what\n * it shows. `altFromDetails` writes a missing alt from what the library\n * already holds about the image — its description, or the caption, headline\n * or title inside the file — and names the images that hold none. Never the\n * file name, which read aloud is worse than silence (`inheritedMediaAlt`).\n * The library's alt is what a placement takes when the image is placed;\n * placements made before keep their own.\n *\n * ── Who may ──────────────────────────────────────────────────────────────\n *\n * The rules' own for a site library (`canWriteHostContent`,\n * `hostWritesFrozen`): a member with the admin, editor or author role, while\n * no lockdown freezes the site, its org or the platform. Asked at the door,\n * before the write, and the role again inside the transaction that writes.\n *\n * ── Idempotent ───────────────────────────────────────────────────────────\n *\n * One transaction reads the files and folders as they are stored and writes\n * only what differs; a folder of the asked name is found before one is made.\n * A pass asked again writes nothing.\n */\n\nexport const AI_MEDIA_KIND = 'media' as const\n\n/** ASSUMED: the site, the org, up to 20 file lookups and one transaction. No model. */\nexport const AI_JOB_MEDIA_STEP_MINIMUM_MS = 8_000\n\nexport const AI_MEDIA_NO_SITE_COPY = 'Open the site whose media library should change.'\nexport const AI_MEDIA_ROLE_COPY = 'Organizing the media library needs the admin, editor or author role on this site.'\nexport const AI_MEDIA_LOCKED_COPY = 'This site is not accepting changes right now.'\nexport const AI_MEDIA_NOTHING_COPY = 'The request named no file in the media library and no change this could make to it.'\n\n/** Where a person finds what the op changed. */\nexport const AI_MEDIA_WHERE = 'the site’s Media library'\n\n/** The output's fixed id: one site's library, whatever changed. */\nexport const AI_MEDIA_OUTPUT_ID = 'library'\n\n/** The library's own limits, each from the control that edits the field. */\nexport const AI_MEDIA_LIMITS = {\n /** Files one item may name or select. */\n files: 20,\n /** The Details drawer's file name. */\n fileName: 200,\n alt: MEDIA_ALT_MAX_LENGTH,\n tags: MEDIA_TAG_MAX_COUNT,\n tag: MEDIA_TAG_MAX_LENGTH,\n /** A folder path: five names of 60 and their separators. */\n folder: MEDIA_FOLDER_MAX_DEPTH * (MEDIA_FOLDER_NAME_MAX_LENGTH + 3),\n} as const\n\n/** The item's arguments, as the planner fills them in. */\nexport const AI_MEDIA_ARGS_SCHEMA: PluginAiCapabilityArgsSchema = {\n type: 'object',\n properties: {\n files: {\n type: 'array',\n description: 'Files already in this site’s media library, each by its id or exact file name as the request gives it.',\n items: { type: 'string', maxLength: 200 },\n maxItems: AI_MEDIA_LIMITS.files,\n },\n missingAlt: {\n type: 'boolean',\n description: 'True to also take the site library’s images that have no alt text yet (up to 20), for altFromDetails.',\n },\n folder: {\n type: 'string',\n description: 'The folder to file them in, as a path such as Portfolio / 2026; a folder not there yet is made.',\n maxLength: AI_MEDIA_LIMITS.folder,\n },\n addTags: {\n type: 'array',\n description: 'Tags to add, each a word or two.',\n items: { type: 'string', maxLength: AI_MEDIA_LIMITS.tag },\n maxItems: AI_MEDIA_LIMITS.tags,\n },\n removeTags: {\n type: 'array',\n description: 'Tags to take off.',\n items: { type: 'string', maxLength: AI_MEDIA_LIMITS.tag },\n maxItems: AI_MEDIA_LIMITS.tags,\n },\n rename: {\n type: 'string',\n description: 'A new file name, for exactly one file. Its address does not change.',\n maxLength: AI_MEDIA_LIMITS.fileName,\n },\n alt: {\n type: 'string',\n description:\n 'Alt text for exactly one image, saying what it shows in one plain sentence, only from what the request says about it. Never its file name.',\n maxLength: AI_MEDIA_LIMITS.alt,\n },\n altFromDetails: {\n type: 'boolean',\n description: 'True to write each image’s missing alt text from its own description or caption already in the library.',\n },\n },\n additionalProperties: false,\n}\n\n/** What an item asks, each value read and held to the library's rule. */\nexport interface AiMediaRequest {\n files: string[]\n missingAlt: boolean\n /** The folder path's names, root first. */\n folder?: string[]\n addTags: string[]\n removeTags: string[]\n rename?: string\n alt?: string\n altFromDetails: boolean\n}\n\nexport interface AiMediaRead {\n request: AiMediaRequest\n problems: string[]\n}\n\nconst text = (value: unknown): string => (typeof value === 'string' ? value.replace(/\\s+/g, ' ').trim() : '')\nconst list = (value: unknown): string[] =>\n (Array.isArray(value) ? value : typeof value === 'string' ? [value] : []).map(text).filter(Boolean)\n\n/** A folder path's names, root first, or a sentence saying why it cannot be one. */\nexport function aiMediaFolderPathOf(value: string): string[] | { error: string } {\n const names = value.split('/').map((part) => part.trim()).filter(Boolean)\n if (!names.length) return { error: 'The folder has no name.' }\n if (names.length > MEDIA_FOLDER_MAX_DEPTH) return { error: `Folders can nest at most ${MEDIA_FOLDER_MAX_DEPTH} levels.` }\n const normalized: string[] = []\n for (const name of names) {\n const one = normalizeFolderName(name)\n if (!one) return { error: `A folder name is at most ${MEDIA_FOLDER_NAME_MAX_LENGTH} characters.` }\n normalized.push(one)\n }\n return normalized\n}\n\n/** Words that name no image: alt text made of them alone describes nothing. */\nconst EMPTY_ALT = /^(an? |the )?(image|photo|photograph|picture|pic|graphic|img|icon|file|logo|banner|thumbnail)s?( of)?\\.?$/i\n\n/** Why this alt text describes nothing, or `null`. */\nexport function aiMediaAltProblem(alt: string, fileName: string): string | null {\n if (EMPTY_ALT.test(alt.trim())) return `“${alt}” does not say what the image shows.`\n const folded = (value: string) => mediaNameWords(value).toLowerCase().replace(/\\s+/g, ' ')\n const base = fileName.replace(/\\.[A-Za-z0-9]{2,5}$/, '')\n if (folded(alt) && (folded(alt) === folded(fileName) || folded(alt) === folded(base))) {\n return 'Alt text that repeats the file name does not say what the image shows.'\n }\n return null\n}\n\n/** The item's arguments read: what may be written, and a sentence for each that may not. */\nexport function aiMediaRequestOf(inputs: Readonly<Record<string, unknown>> | null | undefined): AiMediaRead {\n const problems: string[] = []\n const files = [...new Set(list(inputs?.['files']).map((one) => one.slice(0, 200)))]\n if (files.length > AI_MEDIA_LIMITS.files) problems.push(`One change takes at most ${AI_MEDIA_LIMITS.files} files; the rest were left.`)\n const request: AiMediaRequest = {\n files: files.slice(0, AI_MEDIA_LIMITS.files),\n missingAlt: inputs?.['missingAlt'] === true,\n addTags: normalizeMediaTags(list(inputs?.['addTags'])),\n removeTags: normalizeMediaTags(list(inputs?.['removeTags'])),\n altFromDetails: inputs?.['altFromDetails'] === true,\n }\n const folder = text(inputs?.['folder'])\n if (folder) {\n const path = aiMediaFolderPathOf(folder)\n if (Array.isArray(path)) request.folder = path\n else problems.push(path.error)\n }\n const rename = text(inputs?.['rename'])\n if (rename) {\n if (rename.length > AI_MEDIA_LIMITS.fileName) problems.push(`A file name is at most ${AI_MEDIA_LIMITS.fileName} characters.`)\n else if (request.files.length !== 1 || request.missingAlt) problems.push('A new name is for exactly one file.')\n else request.rename = rename\n }\n const alt = text(inputs?.['alt'])\n if (alt) {\n if (alt.length > AI_MEDIA_LIMITS.alt) problems.push(`Alt text is at most ${AI_MEDIA_LIMITS.alt} characters.`)\n else if (request.files.length !== 1 || request.missingAlt) problems.push('Alt text describes one image; name exactly one.')\n else request.alt = alt\n }\n return { request, problems }\n}\n\n/** Whether a read request names files and a change to make to them. */\nexport function aiMediaRequestEmpty(request: AiMediaRequest): boolean {\n const selects = request.files.length > 0 || request.missingAlt\n const changes =\n request.folder !== undefined ||\n request.addTags.length > 0 ||\n request.removeTags.length > 0 ||\n request.rename !== undefined ||\n request.alt !== undefined ||\n request.altFromDetails\n return !selects || !changes\n}\n\n// ── Files and folders ─────────────────────────────────────────────────────\n\n/** A site library row, as the op reads it. */\nexport interface AiMediaRow {\n id: string\n /** The document as stored, which the filter keys are derived from. */\n data: Record<string, unknown>\n}\n\n/** A media folder, as the op reads it. */\nexport interface AiMediaFolderRow {\n id: string\n name: string\n parentId: string | null\n}\n\nconst fileNameOf = (row: AiMediaRow) => String(row.data['fileName'] ?? '') || row.id\nconst isImage = (row: AiMediaRow) => String(row.data['contentType'] ?? '').startsWith('image/')\n\n/**\n * The file a name or id names among the rows read from the site's library:\n * never a deleted one. Its id wins over a file name; two files of one name\n * are refused in words.\n */\nexport function aiMediaFileOf(source: string, rows: readonly AiMediaRow[]): AiMediaRow | { error: string } {\n const live = rows.filter((row) => row.data['deletedAt'] == null)\n const byId = live.find((row) => row.id === source)\n if (byId) return byId\n const named = live.filter((row) => row.data['fileName'] === source)\n if (named.length > 1) return { error: `The media library has more than one file called “${source}”; name it by its id.` }\n return named[0] ?? { error: `This site’s media library has no file “${source}”.` }\n}\n\n/**\n * Alt text written from what the library already holds about an image: its\n * own description, else the caption, headline or title read from inside the\n * file (only while that record still describes the file's bytes). `null`\n * when it holds none that says what the image shows.\n */\nexport function aiMediaAltFromDetails(row: AiMediaRow): string | null {\n const candidates: unknown[] = [row.data['description']]\n const embedded = row.data['embeddedMetadata']\n if (embeddedMetadataIsCurrent(embedded, row.data['contentSha256'])) {\n const byKey = new Map(embedded.fields.map((field) => [field.key, field.value]))\n candidates.push(byKey.get('description'), byKey.get('headline'), byKey.get('title'))\n }\n for (const candidate of candidates) {\n const value = text(candidate)\n if (!value) continue\n const alt = value.length > AI_MEDIA_LIMITS.alt ? `${value.slice(0, AI_MEDIA_LIMITS.alt - 1).replace(/\\s+\\S*$/, '')}…` : value\n if (!aiMediaAltProblem(alt, fileNameOf(row))) return alt\n }\n return null\n}\n\n/** A folder to make: its name, and its parent's id or its index among those made before it. */\nexport interface AiMediaFolderCreate {\n name: string\n parent: { id: string | null } | { made: number }\n}\n\n/**\n * Where a folder path lands: the existing folders it walks, matched without\n * case among siblings as the library's sibling rule matches them, and the\n * folders left to make below the last one found.\n */\nexport function aiMediaFolderPlan(\n path: readonly string[],\n folders: readonly AiMediaFolderRow[],\n): { existingId: string | null; create: AiMediaFolderCreate[] } {\n let parentId: string | null = null\n let index = 0\n for (; index < path.length; index += 1) {\n const name = path[index].toLowerCase()\n const found = folders.find((folder) => folder.parentId === parentId && folder.name.trim().toLowerCase() === name)\n if (!found) break\n parentId = found.id\n }\n const create: AiMediaFolderCreate[] = path.slice(index).map((name, offset) => ({\n name,\n parent: offset === 0 ? { id: parentId } : { made: offset - 1 },\n }))\n return { existingId: parentId, create }\n}\n\n/** One file's change: the fields to write and the sentences that say it. */\nexport interface AiMediaFileChange {\n update: Record<string, unknown>\n said: string[]\n notDone: string[]\n}\n\n/**\n * What the request changes on one file, compared with what is stored: only\n * the fields that differ, with the filter keys re-derived from the document\n * as the change leaves it, exactly as the Details drawer derives them.\n */\nexport function aiMediaFileChange(\n row: AiMediaRow,\n request: AiMediaRequest,\n folder: { id: string; name: string } | null,\n): AiMediaFileChange {\n const name = fileNameOf(row)\n const update: Record<string, unknown> = {}\n const said: string[] = []\n const notDone: string[] = []\n if (request.rename && request.rename !== row.data['fileName']) {\n update['fileName'] = request.rename\n said.push(`“${name}” is now called “${request.rename}”.`)\n }\n const tags = Array.isArray(row.data['tags']) ? (row.data['tags'] as unknown[]).map(String) : []\n if (request.addTags.length || request.removeTags.length) {\n const removed = new Set(request.removeTags)\n const next = normalizeMediaTags([...tags, ...request.addTags]).filter((tag) => !removed.has(tag))\n const dropped = request.addTags.filter((tag) => !removed.has(tag) && !next.includes(tag))\n if (dropped.length) notDone.push(`“${name}” holds ${AI_MEDIA_LIMITS.tags} tags at most, so ${dropped.join(', ')} was not added.`)\n if (JSON.stringify(next) !== JSON.stringify(tags)) {\n update['tags'] = next\n said.push(`“${name}” is tagged ${next.length ? next.join(', ') : 'with nothing'}.`)\n }\n }\n if (folder && (row.data['folderId'] ?? null) !== folder.id) {\n update['folderId'] = folder.id\n // The legacy name beside it, as the drawer keeps it until every reader is on folderId.\n update['folder'] = folder.name\n said.push(`“${name}” is in ${folder.name}.`)\n }\n const storedAlt = text(row.data['alt'])\n let alt: string | null = null\n if (request.alt) {\n if (!isImage(row)) notDone.push(`“${name}” is not an image, so it takes no alt text.`)\n else {\n const problem = aiMediaAltProblem(request.alt, name)\n if (problem) notDone.push(problem)\n else alt = request.alt\n }\n } else if (request.altFromDetails && isImage(row) && !storedAlt) {\n alt = aiMediaAltFromDetails(row)\n if (!alt) notDone.push(`“${name}” has no description or caption in the library to write its alt text from; say what it shows.`)\n }\n if (alt && alt !== storedAlt) {\n update['alt'] = alt\n said.push(`“${name}” has alt text.`)\n }\n if (update['fileName'] !== undefined || update['alt'] !== undefined) {\n Object.assign(update, mediaFilterKeys({ ...row.data, ...update }))\n }\n return { update, said, notDone }\n}\n\nexport type AiMediaWrite =\n | { ok: true; done: string[]; notDone: string[]; changedFiles: number; madeFolders: string[]; altChanged: boolean }\n | { ok: false; error: string }\n\nconst ID_SHAPE = /^[A-Za-z0-9_-]{1,128}$/\n\n/**\n * The library change, written in one transaction that reads the site, its\n * folders and the named files as they are stored NOW: the member still holds\n * a write role, a folder of the asked name is used before one is made, and\n * only fields that differ are written.\n */\nexport async function writeAiMediaChanges(\n firestore: Firestore,\n input: { hostId: string; uid: string; request: AiMediaRequest; now: Date },\n): Promise<AiMediaWrite> {\n const hostRef = firestore.collection('hosts').doc(input.hostId)\n const mediaRef = hostRef.collection('media')\n const foldersRef = hostRef.collection('mediaFolders')\n const { request } = input\n return firestore.runTransaction(async (tx): Promise<AiMediaWrite> => {\n // Every read first: a transaction writes nothing until its reads are done.\n const host = await tx.get(hostRef)\n if (!host.exists) return { ok: false, error: 'Unknown site' }\n const roles = (host.get('memberRoles') ?? {}) as Record<string, unknown>\n if (!hostRoleCanWrite(roles[input.uid])) return { ok: false, error: AI_MEDIA_ROLE_COPY }\n const notDone: string[] = []\n const rows = new Map<string, AiMediaRow>()\n for (const source of request.files) {\n const read: AiMediaRow[] = []\n if (ID_SHAPE.test(source)) {\n const byId = await tx.get(mediaRef.doc(source))\n if (byId.exists) read.push({ id: byId.id, data: byId.data() ?? {} })\n }\n const byName = await tx.get(mediaRef.where('fileName', '==', source).limit(5))\n for (const doc of byName.docs) if (!read.some((row) => row.id === doc.id)) read.push({ id: doc.id, data: doc.data() })\n const found = aiMediaFileOf(source, read)\n if ('error' in found) notDone.push(found.error)\n else rows.set(found.id, found)\n }\n if (request.missingAlt) {\n // The library's own \"Alt text is missing\" filter: `hasAlt`, which every writer derives.\n const missing = await tx.get(mediaRef.where('hasAlt', '==', false).limit(AI_MEDIA_LIMITS.files * 2))\n for (const doc of missing.docs) {\n const row = { id: doc.id, data: doc.data() }\n if (rows.size >= AI_MEDIA_LIMITS.files) break\n if (row.data['deletedAt'] == null && isImage(row)) rows.set(row.id, row)\n }\n if (!missing.docs.length && !request.files.length) notDone.push('Every image in this site’s media library has alt text.')\n }\n const folders: AiMediaFolderRow[] = []\n if (request.folder && rows.size) {\n const stored = await tx.get(foldersRef.limit(500))\n for (const doc of stored.docs) {\n folders.push({ id: doc.id, name: String(doc.get('name') ?? ''), parentId: (doc.get('parentId') as string | null) ?? null })\n }\n }\n\n let folder: { id: string; name: string } | null = null\n const madeFolders: string[] = []\n if (request.folder && rows.size) {\n const plan = aiMediaFolderPlan(request.folder, folders)\n const made: string[] = []\n for (const one of plan.create) {\n const ref = foldersRef.doc(createResourceUid())\n const parentId = 'id' in one.parent ? one.parent.id : made[one.parent.made]\n // The New folder button's document: a site library's folder stores no scope.\n tx.set(ref, newMediaFolderDoc({ name: one.name, parentId, createdAt: FieldValue.serverTimestamp(), visibleTo: null }))\n made.push(ref.id)\n madeFolders.push(one.name)\n }\n const id = made[made.length - 1] ?? plan.existingId\n if (id) folder = { id, name: request.folder[request.folder.length - 1] }\n }\n\n const done: string[] = madeFolders.map((name) => `Made the folder ${name}.`)\n let changedFiles = 0\n let altChanged = false\n for (const row of rows.values()) {\n const change = aiMediaFileChange(row, request, folder)\n notDone.push(...change.notDone)\n if (!Object.keys(change.update).length) continue\n tx.update(mediaRef.doc(row.id), { ...change.update, updatedAt: input.now })\n done.push(...change.said)\n changedFiles += 1\n if (change.update['alt'] !== undefined) altChanged = true\n }\n return { ok: true, done, notDone, changedFiles, madeFolders, altChanged }\n })\n}\n\n// ── The step ──────────────────────────────────────────────────────────────\n\n/** Why this member may not organize this site's library now, or `null`. */\nexport async function aiMediaAccessRefusal(\n input: { host: FirebaseFirestore.DocumentSnapshot; uid: string; org: object | null },\n deps: { lockdown?: typeof getLockdownVerdict } = {},\n): Promise<string | null> {\n if (!input.host.exists) return 'Unknown site'\n const roles = (input.host.get('memberRoles') ?? {}) as Record<string, unknown>\n if (!hostRoleCanWrite(roles[input.uid])) return AI_MEDIA_ROLE_COPY\n const locked = await (deps.lockdown ?? getLockdownVerdict)({\n staff: false,\n uid: input.uid,\n org: input.org as never,\n host: input.host.data() as never,\n intent: 'write',\n })\n return locked ? AI_MEDIA_LOCKED_COPY : null\n}\n\n/** The output's note: what changed, that it is live, and what was not done. */\nexport function aiMediaOutputNote(done: readonly string[], notDone: readonly string[], altChanged: boolean): string {\n // The build's own wording for an item with no draft state (AGL-3745).\n const did = done.length ? `${done.join(' ')} Live now, in ${AI_MEDIA_WHERE}.` : 'Nothing needed changing.'\n const placed = altChanged ? ' Images placed from now on take the new alt text; ones already on a page keep their own.' : ''\n const not = notDone.length ? ` Not done: ${notDone.join(' ')}` : ''\n return `${did}${placed}${not}`.slice(0, 1_000)\n}\n\nexport interface AiJobMediaStepDeps {\n write?: typeof writeAiMediaChanges\n lockdown?: typeof getLockdownVerdict\n}\n\nexport function createAiJobMediaStep(deps: AiJobMediaStepDeps = {}): AiJobStepRunner {\n const write = deps.write ?? writeAiMediaChanges\n return async ({ job, now, firestore, org, modelFor }): Promise<AiJobStepOutcome> => {\n // No model is asked: the outcome records the edit step's at no cost.\n const model = modelFor?.('job.edit') ?? aiJobEditModel()\n const unspent = (failure: string): AiJobStepOutcome => ({ ...aiUnspentOutcome(model), failure })\n const hostId = job.hostId\n if (!hostId) return unspent(AI_MEDIA_NO_SITE_COPY)\n const read = aiMediaRequestOf(job.inputs)\n if (aiMediaRequestEmpty(read.request)) return unspent([AI_MEDIA_NOTHING_COPY, ...read.problems].join(' '))\n const orgData = (org ?? ((await firestore.collection('orgs').doc(job.orgId).get()).data() ?? null)) as Record<string, unknown> | null\n const host = await firestore.collection('hosts').doc(hostId).get()\n const refused = await aiMediaAccessRefusal({ host, uid: job.createdBy, org: orgData }, { lockdown: deps.lockdown })\n if (refused) return aiUnspentOutcome(model, { review: aiLimitReview(refused) })\n const written = await write(firestore, { hostId, uid: job.createdBy, request: read.request, now })\n if (written.ok === false) return unspent(written.error)\n const notDone = [...read.problems, ...written.notDone]\n if (!written.done.length && notDone.length) return unspent(notDone.join(' '))\n const output: AiJobOutput = {\n resource: 'media',\n id: AI_MEDIA_OUTPUT_ID,\n hostId,\n hostSubdomain: (typeof host.get('subdomain') === 'string' && host.get('subdomain')) || null,\n label: 'Media library',\n note: aiMediaOutputNote(written.done, notDone, written.altChanged),\n }\n return aiUnspentOutcome(model, { outputs: [output] })\n }\n}\n\nexport const runAiJobMediaStep = createAiJobMediaStep()\n\n// ── Admission ─────────────────────────────────────────────────────────────\n\nexport interface AiMediaJobAdmissionDeps {\n ownerOf?: typeof resolveOrgIdForHost\n lockdown?: typeof getLockdownVerdict\n}\n\n/**\n * A library change is admitted on a site of the job's own org, for a member\n * who may write its library now, where the request names files and a change\n * this can make. Refused in those words before anything is written.\n */\nexport function createAiMediaJobAdmission(deps: AiMediaJobAdmissionDeps = {}): AiJobAdmission {\n const ownerOf = deps.ownerOf ?? resolveOrgIdForHost\n return async (context): Promise<AiJobAdmissionRefusal | null> => {\n if (!context.hostId) return { status: 400, error: AI_MEDIA_NO_SITE_COPY }\n const owner = await ownerOf(context.hostId)\n if (!owner || owner !== context.orgId) return { status: 404, error: 'Unknown site' }\n const host = await context.firestore.collection('hosts').doc(context.hostId).get()\n const refused = await aiMediaAccessRefusal({ host, uid: context.uid ?? '', org: context.org }, { lockdown: deps.lockdown })\n if (refused) return { status: 403, error: refused }\n const read = aiMediaRequestOf(context.inputs as Record<string, unknown>)\n return aiMediaRequestEmpty(read.request) ? { status: 400, error: [AI_MEDIA_NOTHING_COPY, ...read.problems].join(' ') } : null\n }\n}\n\nexport const aiMediaJobAdmission = createAiMediaJobAdmission()\n\n/** Registers the media library step and its door (AGL-3752). */\nexport function registerAiMediaJob(): void {\n registerAiJobStep(AI_MEDIA_KIND, runAiJobMediaStep, { minimumMs: AI_JOB_MEDIA_STEP_MINIMUM_MS })\n registerAiJobAdmission(AI_MEDIA_KIND, aiMediaJobAdmission)\n}\n"],"names":["createResourceUid","MEDIA_ALT_MAX_LENGTH","embeddedMetadataIsCurrent","MEDIA_FOLDER_MAX_DEPTH","MEDIA_FOLDER_NAME_MAX_LENGTH","newMediaFolderDoc","normalizeFolderName","MEDIA_TAG_MAX_COUNT","MEDIA_TAG_MAX_LENGTH","mediaFilterKeys","mediaNameWords","normalizeMediaTags","hostRoleCanWrite","getLockdownVerdict","resolveOrgIdForHost","FieldValue","registerAiJobAdmission","aiJobEditModel","aiLimitReview","aiUnspentOutcome","registerAiJobStep","AI_MEDIA_KIND","AI_JOB_MEDIA_STEP_MINIMUM_MS","AI_MEDIA_NO_SITE_COPY","AI_MEDIA_ROLE_COPY","AI_MEDIA_LOCKED_COPY","AI_MEDIA_NOTHING_COPY","AI_MEDIA_WHERE","AI_MEDIA_OUTPUT_ID","AI_MEDIA_LIMITS","files","fileName","alt","tags","tag","folder","AI_MEDIA_ARGS_SCHEMA","type","properties","description","items","maxLength","maxItems","missingAlt","addTags","removeTags","rename","altFromDetails","additionalProperties","text","value","replace","trim","list","Array","isArray","map","filter","Boolean","aiMediaFolderPathOf","names","split","part","length","error","normalized","name","one","push","EMPTY_ALT","aiMediaAltProblem","test","folded","toLowerCase","base","aiMediaRequestOf","inputs","problems","Set","slice","request","path","aiMediaRequestEmpty","selects","changes","undefined","fileNameOf","row","String","data","id","isImage","startsWith","aiMediaFileOf","source","rows","named","live","byId","find","aiMediaAltFromDetails","candidates","embedded","byKey","Map","fields","field","key","get","candidate","aiMediaFolderPlan","folders","parentId","index","found","create","offset","parent","made","existingId","aiMediaFileChange","update","said","notDone","removed","next","has","dropped","includes","join","JSON","stringify","storedAlt","problem","Object","assign","ID_SHAPE","writeAiMediaChanges","firestore","input","hostRef","collection","doc","hostId","mediaRef","foldersRef","runTransaction","tx","host","exists","ok","roles","uid","read","byName","where","limit","docs","some","set","missing","size","stored","madeFolders","plan","ref","createdAt","serverTimestamp","visibleTo","done","changedFiles","altChanged","values","change","keys","updatedAt","now","aiMediaAccessRefusal","deps","locked","lockdown","staff","org","intent","aiMediaOutputNote","did","placed","not","createAiJobMediaStep","write","job","modelFor","model","unspent","failure","orgData","orgId","refused","createdBy","review","written","output","resource","hostSubdomain","label","note","outputs","runAiJobMediaStep","createAiMediaJobAdmission","ownerOf","context","status","owner","aiMediaJobAdmission","registerAiMediaJob","minimumMs"],"mappings":";AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,iBAAiB,QAAQ,6CAA4C;AAC9E,SAASC,oBAAoB,QAAQ,mCAAkC;AACvE,SAASC,yBAAyB,QAAQ,+CAA8C;AACxF,SACEC,sBAAsB,EACtBC,4BAA4B,EAC5BC,iBAAiB,EACjBC,mBAAmB,QACd,uCAAsC;AAC7C,SACEC,mBAAmB,EACnBC,oBAAoB,EACpBC,eAAe,EACfC,cAAc,EACdC,kBAAkB,QACb,wCAAuC;AAC9C,SAASC,gBAAgB,QAAQ,uCAAsC;AAEvE,SAASC,kBAAkB,QAAQ,2CAA0C;AAC7E,SAASC,mBAAmB,QAAQ,gDAA+C;AACnF,SAASC,UAAU,QAAwB,2BAA0B;AAErE,SAASC,sBAAsB,QAAyD,wBAAoB;AAC5G,SAASC,cAAc,QAAQ,wBAAoB;AACnD,SAASC,aAAa,EAAEC,gBAAgB,QAAQ,yBAAqB;AAErE,SAASC,iBAAiB,QAAQ,eAAW;AAE7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqDC,GAED,OAAO,MAAMC,gBAAgB,QAAgB;AAE7C,qFAAqF,GACrF,OAAO,MAAMC,+BAA+B,KAAK;AAEjD,OAAO,MAAMC,wBAAwB,mDAAkD;AACvF,OAAO,MAAMC,qBAAqB,oFAAmF;AACrH,OAAO,MAAMC,uBAAuB,gDAA+C;AACnF,OAAO,MAAMC,wBAAwB,sFAAqF;AAE1H,8CAA8C,GAC9C,OAAO,MAAMC,iBAAiB,2BAA0B;AAExD,iEAAiE,GACjE,OAAO,MAAMC,qBAAqB,UAAS;AAE3C,0EAA0E,GAC1E,OAAO,MAAMC,kBAAkB;IAC7B,uCAAuC,GACvCC,OAAO;IACP,oCAAoC,GACpCC,UAAU;IACVC,KAAK/B;IACLgC,MAAM1B;IACN2B,KAAK1B;IACL,0DAA0D,GAC1D2B,QAAQhC,yBAA0BC,CAAAA,+BAA+B,CAAA;AACnE,EAAU;AAEV,wDAAwD,GACxD,OAAO,MAAMgC,uBAAqD;IAChEC,MAAM;IACNC,YAAY;QACVR,OAAO;YACLO,MAAM;YACNE,aAAa;YACbC,OAAO;gBAAEH,MAAM;gBAAUI,WAAW;YAAI;YACxCC,UAAUb,gBAAgBC,KAAK;QACjC;QACAa,YAAY;YACVN,MAAM;YACNE,aAAa;QACf;QACAJ,QAAQ;YACNE,MAAM;YACNE,aAAa;YACbE,WAAWZ,gBAAgBM,MAAM;QACnC;QACAS,SAAS;YACPP,MAAM;YACNE,aAAa;YACbC,OAAO;gBAAEH,MAAM;gBAAUI,WAAWZ,gBAAgBK,GAAG;YAAC;YACxDQ,UAAUb,gBAAgBI,IAAI;QAChC;QACAY,YAAY;YACVR,MAAM;YACNE,aAAa;YACbC,OAAO;gBAAEH,MAAM;gBAAUI,WAAWZ,gBAAgBK,GAAG;YAAC;YACxDQ,UAAUb,gBAAgBI,IAAI;QAChC;QACAa,QAAQ;YACNT,MAAM;YACNE,aAAa;YACbE,WAAWZ,gBAAgBE,QAAQ;QACrC;QACAC,KAAK;YACHK,MAAM;YACNE,aACE;YACFE,WAAWZ,gBAAgBG,GAAG;QAChC;QACAe,gBAAgB;YACdV,MAAM;YACNE,aAAa;QACf;IACF;IACAS,sBAAsB;AACxB,EAAC;AAoBD,MAAMC,OAAO,CAACC,QAA4B,OAAOA,UAAU,WAAWA,MAAMC,OAAO,CAAC,QAAQ,KAAKC,IAAI,KAAK;AAC1G,MAAMC,OAAO,CAACH,QACZ,AAACI,CAAAA,MAAMC,OAAO,CAACL,SAASA,QAAQ,OAAOA,UAAU,WAAW;QAACA;KAAM,GAAG,EAAE,AAAD,EAAGM,GAAG,CAACP,MAAMQ,MAAM,CAACC;AAE7F,kFAAkF,GAClF,OAAO,SAASC,oBAAoBT,KAAa;IAC/C,MAAMU,QAAQV,MAAMW,KAAK,CAAC,KAAKL,GAAG,CAAC,CAACM,OAASA,KAAKV,IAAI,IAAIK,MAAM,CAACC;IACjE,IAAI,CAACE,MAAMG,MAAM,EAAE,OAAO;QAAEC,OAAO;IAA0B;IAC7D,IAAIJ,MAAMG,MAAM,GAAG5D,wBAAwB,OAAO;QAAE6D,OAAO,CAAC,yBAAyB,EAAE7D,uBAAuB,QAAQ,CAAC;IAAC;IACxH,MAAM8D,aAAuB,EAAE;IAC/B,KAAK,MAAMC,QAAQN,MAAO;QACxB,MAAMO,MAAM7D,oBAAoB4D;QAChC,IAAI,CAACC,KAAK,OAAO;YAAEH,OAAO,CAAC,yBAAyB,EAAE5D,6BAA6B,YAAY,CAAC;QAAC;QACjG6D,WAAWG,IAAI,CAACD;IAClB;IACA,OAAOF;AACT;AAEA,6EAA6E,GAC7E,MAAMI,YAAY;AAElB,oDAAoD,GACpD,OAAO,SAASC,kBAAkBtC,GAAW,EAAED,QAAgB;IAC7D,IAAIsC,UAAUE,IAAI,CAACvC,IAAIoB,IAAI,KAAK,OAAO,CAAC,CAAC,EAAEpB,IAAI,oCAAoC,CAAC;IACpF,MAAMwC,SAAS,CAACtB,QAAkBxC,eAAewC,OAAOuB,WAAW,GAAGtB,OAAO,CAAC,QAAQ;IACtF,MAAMuB,OAAO3C,SAASoB,OAAO,CAAC,uBAAuB;IACrD,IAAIqB,OAAOxC,QAASwC,CAAAA,OAAOxC,SAASwC,OAAOzC,aAAayC,OAAOxC,SAASwC,OAAOE,KAAI,GAAI;QACrF,OAAO;IACT;IACA,OAAO;AACT;AAEA,0FAA0F,GAC1F,OAAO,SAASC,iBAAiBC,MAA4D;IAC3F,MAAMC,WAAqB,EAAE;IAC7B,MAAM/C,QAAQ;WAAI,IAAIgD,IAAIzB,KAAKuB,0BAAAA,MAAQ,CAAC,QAAQ,EAAEpB,GAAG,CAAC,CAACW,MAAQA,IAAIY,KAAK,CAAC,GAAG;KAAO;IACnF,IAAIjD,MAAMiC,MAAM,GAAGlC,gBAAgBC,KAAK,EAAE+C,SAAST,IAAI,CAAC,CAAC,yBAAyB,EAAEvC,gBAAgBC,KAAK,CAAC,2BAA2B,CAAC;IACtI,MAAMkD,UAA0B;QAC9BlD,OAAOA,MAAMiD,KAAK,CAAC,GAAGlD,gBAAgBC,KAAK;QAC3Ca,YAAYiC,CAAAA,0BAAAA,MAAQ,CAAC,aAAa,MAAK;QACvChC,SAASjC,mBAAmB0C,KAAKuB,0BAAAA,MAAQ,CAAC,UAAU;QACpD/B,YAAYlC,mBAAmB0C,KAAKuB,0BAAAA,MAAQ,CAAC,aAAa;QAC1D7B,gBAAgB6B,CAAAA,0BAAAA,MAAQ,CAAC,iBAAiB,MAAK;IACjD;IACA,MAAMzC,SAASc,KAAK2B,0BAAAA,MAAQ,CAAC,SAAS;IACtC,IAAIzC,QAAQ;QACV,MAAM8C,OAAOtB,oBAAoBxB;QACjC,IAAImB,MAAMC,OAAO,CAAC0B,OAAOD,QAAQ7C,MAAM,GAAG8C;aACrCJ,SAAST,IAAI,CAACa,KAAKjB,KAAK;IAC/B;IACA,MAAMlB,SAASG,KAAK2B,0BAAAA,MAAQ,CAAC,SAAS;IACtC,IAAI9B,QAAQ;QACV,IAAIA,OAAOiB,MAAM,GAAGlC,gBAAgBE,QAAQ,EAAE8C,SAAST,IAAI,CAAC,CAAC,uBAAuB,EAAEvC,gBAAgBE,QAAQ,CAAC,YAAY,CAAC;aACvH,IAAIiD,QAAQlD,KAAK,CAACiC,MAAM,KAAK,KAAKiB,QAAQrC,UAAU,EAAEkC,SAAST,IAAI,CAAC;aACpEY,QAAQlC,MAAM,GAAGA;IACxB;IACA,MAAMd,MAAMiB,KAAK2B,0BAAAA,MAAQ,CAAC,MAAM;IAChC,IAAI5C,KAAK;QACP,IAAIA,IAAI+B,MAAM,GAAGlC,gBAAgBG,GAAG,EAAE6C,SAAST,IAAI,CAAC,CAAC,oBAAoB,EAAEvC,gBAAgBG,GAAG,CAAC,YAAY,CAAC;aACvG,IAAIgD,QAAQlD,KAAK,CAACiC,MAAM,KAAK,KAAKiB,QAAQrC,UAAU,EAAEkC,SAAST,IAAI,CAAC;aACpEY,QAAQhD,GAAG,GAAGA;IACrB;IACA,OAAO;QAAEgD;QAASH;IAAS;AAC7B;AAEA,qEAAqE,GACrE,OAAO,SAASK,oBAAoBF,OAAuB;IACzD,MAAMG,UAAUH,QAAQlD,KAAK,CAACiC,MAAM,GAAG,KAAKiB,QAAQrC,UAAU;IAC9D,MAAMyC,UACJJ,QAAQ7C,MAAM,KAAKkD,aACnBL,QAAQpC,OAAO,CAACmB,MAAM,GAAG,KACzBiB,QAAQnC,UAAU,CAACkB,MAAM,GAAG,KAC5BiB,QAAQlC,MAAM,KAAKuC,aACnBL,QAAQhD,GAAG,KAAKqD,aAChBL,QAAQjC,cAAc;IACxB,OAAO,CAACoC,WAAW,CAACC;AACtB;AAkBA,MAAME,aAAa,CAACC;QAA2BA;WAAPC,QAAOD,qBAAAA,IAAIE,IAAI,CAAC,WAAW,YAApBF,qBAAwB,OAAOA,IAAIG,EAAE;;AACpF,MAAMC,UAAU,CAACJ;QAA2BA;WAAPC,QAAOD,wBAAAA,IAAIE,IAAI,CAAC,cAAc,YAAvBF,wBAA2B,IAAIK,UAAU,CAAC;;AAEtF;;;;CAIC,GACD,OAAO,SAASC,cAAcC,MAAc,EAAEC,IAA2B;QAMhEC;IALP,MAAMC,OAAOF,KAAKtC,MAAM,CAAC,CAAC8B,MAAQA,IAAIE,IAAI,CAAC,YAAY,IAAI;IAC3D,MAAMS,OAAOD,KAAKE,IAAI,CAAC,CAACZ,MAAQA,IAAIG,EAAE,KAAKI;IAC3C,IAAII,MAAM,OAAOA;IACjB,MAAMF,QAAQC,KAAKxC,MAAM,CAAC,CAAC8B,MAAQA,IAAIE,IAAI,CAAC,WAAW,KAAKK;IAC5D,IAAIE,MAAMjC,MAAM,GAAG,GAAG,OAAO;QAAEC,OAAO,CAAC,iDAAiD,EAAE8B,OAAO,qBAAqB,CAAC;IAAC;IACxH,QAAOE,UAAAA,KAAK,CAAC,EAAE,YAARA,UAAY;QAAEhC,OAAO,CAAC,uCAAuC,EAAE8B,OAAO,EAAE,CAAC;IAAC;AACnF;AAEA;;;;;CAKC,GACD,OAAO,SAASM,sBAAsBb,GAAe;IACnD,MAAMc,aAAwB;QAACd,IAAIE,IAAI,CAAC,cAAc;KAAC;IACvD,MAAMa,WAAWf,IAAIE,IAAI,CAAC,mBAAmB;IAC7C,IAAIvF,0BAA0BoG,UAAUf,IAAIE,IAAI,CAAC,gBAAgB,GAAG;QAClE,MAAMc,QAAQ,IAAIC,IAAIF,SAASG,MAAM,CAACjD,GAAG,CAAC,CAACkD,QAAU;gBAACA,MAAMC,GAAG;gBAAED,MAAMxD,KAAK;aAAC;QAC7EmD,WAAWjC,IAAI,CAACmC,MAAMK,GAAG,CAAC,gBAAgBL,MAAMK,GAAG,CAAC,aAAaL,MAAMK,GAAG,CAAC;IAC7E;IACA,KAAK,MAAMC,aAAaR,WAAY;QAClC,MAAMnD,QAAQD,KAAK4D;QACnB,IAAI,CAAC3D,OAAO;QACZ,MAAMlB,MAAMkB,MAAMa,MAAM,GAAGlC,gBAAgBG,GAAG,GAAG,GAAGkB,MAAM6B,KAAK,CAAC,GAAGlD,gBAAgBG,GAAG,GAAG,GAAGmB,OAAO,CAAC,WAAW,IAAI,CAAC,CAAC,GAAGD;QACxH,IAAI,CAACoB,kBAAkBtC,KAAKsD,WAAWC,OAAO,OAAOvD;IACvD;IACA,OAAO;AACT;AAQA;;;;CAIC,GACD,OAAO,SAAS8E,kBACd7B,IAAuB,EACvB8B,OAAoC;IAEpC,IAAIC,WAA0B;IAC9B,IAAIC,QAAQ;IACZ,MAAOA,QAAQhC,KAAKlB,MAAM,EAAEkD,SAAS,EAAG;QACtC,MAAM/C,OAAOe,IAAI,CAACgC,MAAM,CAACxC,WAAW;QACpC,MAAMyC,QAAQH,QAAQZ,IAAI,CAAC,CAAChE,SAAWA,OAAO6E,QAAQ,KAAKA,YAAY7E,OAAO+B,IAAI,CAACd,IAAI,GAAGqB,WAAW,OAAOP;QAC5G,IAAI,CAACgD,OAAO;QACZF,WAAWE,MAAMxB,EAAE;IACrB;IACA,MAAMyB,SAAgClC,KAAKF,KAAK,CAACkC,OAAOzD,GAAG,CAAC,CAACU,MAAMkD,SAAY,CAAA;YAC7ElD;YACAmD,QAAQD,WAAW,IAAI;gBAAE1B,IAAIsB;YAAS,IAAI;gBAAEM,MAAMF,SAAS;YAAE;QAC/D,CAAA;IACA,OAAO;QAAEG,YAAYP;QAAUG;IAAO;AACxC;AASA;;;;CAIC,GACD,OAAO,SAASK,kBACdjC,GAAe,EACfP,OAAuB,EACvB7C,MAA2C;QAqB5BoD;IAnBf,MAAMrB,OAAOoB,WAAWC;IACxB,MAAMkC,SAAkC,CAAC;IACzC,MAAMC,OAAiB,EAAE;IACzB,MAAMC,UAAoB,EAAE;IAC5B,IAAI3C,QAAQlC,MAAM,IAAIkC,QAAQlC,MAAM,KAAKyC,IAAIE,IAAI,CAAC,WAAW,EAAE;QAC7DgC,MAAM,CAAC,WAAW,GAAGzC,QAAQlC,MAAM;QACnC4E,KAAKtD,IAAI,CAAC,CAAC,CAAC,EAAEF,KAAK,iBAAiB,EAAEc,QAAQlC,MAAM,CAAC,EAAE,CAAC;IAC1D;IACA,MAAMb,OAAOqB,MAAMC,OAAO,CAACgC,IAAIE,IAAI,CAAC,OAAO,IAAI,AAACF,IAAIE,IAAI,CAAC,OAAO,CAAejC,GAAG,CAACgC,UAAU,EAAE;IAC/F,IAAIR,QAAQpC,OAAO,CAACmB,MAAM,IAAIiB,QAAQnC,UAAU,CAACkB,MAAM,EAAE;QACvD,MAAM6D,UAAU,IAAI9C,IAAIE,QAAQnC,UAAU;QAC1C,MAAMgF,OAAOlH,mBAAmB;eAAIsB;eAAS+C,QAAQpC,OAAO;SAAC,EAAEa,MAAM,CAAC,CAACvB,MAAQ,CAAC0F,QAAQE,GAAG,CAAC5F;QAC5F,MAAM6F,UAAU/C,QAAQpC,OAAO,CAACa,MAAM,CAAC,CAACvB,MAAQ,CAAC0F,QAAQE,GAAG,CAAC5F,QAAQ,CAAC2F,KAAKG,QAAQ,CAAC9F;QACpF,IAAI6F,QAAQhE,MAAM,EAAE4D,QAAQvD,IAAI,CAAC,CAAC,CAAC,EAAEF,KAAK,QAAQ,EAAErC,gBAAgBI,IAAI,CAAC,kBAAkB,EAAE8F,QAAQE,IAAI,CAAC,MAAM,eAAe,CAAC;QAChI,IAAIC,KAAKC,SAAS,CAACN,UAAUK,KAAKC,SAAS,CAAClG,OAAO;YACjDwF,MAAM,CAAC,OAAO,GAAGI;YACjBH,KAAKtD,IAAI,CAAC,CAAC,CAAC,EAAEF,KAAK,YAAY,EAAE2D,KAAK9D,MAAM,GAAG8D,KAAKI,IAAI,CAAC,QAAQ,eAAe,CAAC,CAAC;QACpF;IACF;IACA,IAAI9F,UAAU,EAACoD,qBAAAA,IAAIE,IAAI,CAAC,WAAW,YAApBF,qBAAwB,UAAUpD,OAAOuD,EAAE,EAAE;QAC1D+B,MAAM,CAAC,WAAW,GAAGtF,OAAOuD,EAAE;QAC9B,uFAAuF;QACvF+B,MAAM,CAAC,SAAS,GAAGtF,OAAO+B,IAAI;QAC9BwD,KAAKtD,IAAI,CAAC,CAAC,CAAC,EAAEF,KAAK,QAAQ,EAAE/B,OAAO+B,IAAI,CAAC,CAAC,CAAC;IAC7C;IACA,MAAMkE,YAAYnF,KAAKsC,IAAIE,IAAI,CAAC,MAAM;IACtC,IAAIzD,MAAqB;IACzB,IAAIgD,QAAQhD,GAAG,EAAE;QACf,IAAI,CAAC2D,QAAQJ,MAAMoC,QAAQvD,IAAI,CAAC,CAAC,CAAC,EAAEF,KAAK,2CAA2C,CAAC;aAChF;YACH,MAAMmE,UAAU/D,kBAAkBU,QAAQhD,GAAG,EAAEkC;YAC/C,IAAImE,SAASV,QAAQvD,IAAI,CAACiE;iBACrBrG,MAAMgD,QAAQhD,GAAG;QACxB;IACF,OAAO,IAAIgD,QAAQjC,cAAc,IAAI4C,QAAQJ,QAAQ,CAAC6C,WAAW;QAC/DpG,MAAMoE,sBAAsBb;QAC5B,IAAI,CAACvD,KAAK2F,QAAQvD,IAAI,CAAC,CAAC,CAAC,EAAEF,KAAK,6FAA6F,CAAC;IAChI;IACA,IAAIlC,OAAOA,QAAQoG,WAAW;QAC5BX,MAAM,CAAC,MAAM,GAAGzF;QAChB0F,KAAKtD,IAAI,CAAC,CAAC,CAAC,EAAEF,KAAK,eAAe,CAAC;IACrC;IACA,IAAIuD,MAAM,CAAC,WAAW,KAAKpC,aAAaoC,MAAM,CAAC,MAAM,KAAKpC,WAAW;QACnEiD,OAAOC,MAAM,CAACd,QAAQhH,gBAAgB,aAAK8E,IAAIE,IAAI,EAAKgC;IAC1D;IACA,OAAO;QAAEA;QAAQC;QAAMC;IAAQ;AACjC;AAMA,MAAMa,WAAW;AAEjB;;;;;CAKC,GACD,OAAO,eAAeC,oBACpBC,SAAoB,EACpBC,KAA0E;IAE1E,MAAMC,UAAUF,UAAUG,UAAU,CAAC,SAASC,GAAG,CAACH,MAAMI,MAAM;IAC9D,MAAMC,WAAWJ,QAAQC,UAAU,CAAC;IACpC,MAAMI,aAAaL,QAAQC,UAAU,CAAC;IACtC,MAAM,EAAE7D,OAAO,EAAE,GAAG2D;IACpB,OAAOD,UAAUQ,cAAc,CAAC,OAAOC;YAItBC;QAHf,2EAA2E;QAC3E,MAAMA,OAAO,MAAMD,GAAGvC,GAAG,CAACgC;QAC1B,IAAI,CAACQ,KAAKC,MAAM,EAAE,OAAO;YAAEC,IAAI;YAAOtF,OAAO;QAAe;QAC5D,MAAMuF,SAASH,YAAAA,KAAKxC,GAAG,CAAC,0BAATwC,YAA2B,CAAC;QAC3C,IAAI,CAACxI,iBAAiB2I,KAAK,CAACZ,MAAMa,GAAG,CAAC,GAAG,OAAO;YAAEF,IAAI;YAAOtF,OAAOxC;QAAmB;QACvF,MAAMmG,UAAoB,EAAE;QAC5B,MAAM5B,OAAO,IAAIS;QACjB,KAAK,MAAMV,UAAUd,QAAQlD,KAAK,CAAE;YAClC,MAAM2H,OAAqB,EAAE;YAC7B,IAAIjB,SAASjE,IAAI,CAACuB,SAAS;oBAEuBI;gBADhD,MAAMA,OAAO,MAAMiD,GAAGvC,GAAG,CAACoC,SAASF,GAAG,CAAChD;gBACvC,IAAII,KAAKmD,MAAM,EAAEI,KAAKrF,IAAI,CAAC;oBAAEsB,IAAIQ,KAAKR,EAAE;oBAAED,IAAI,GAAES,aAAAA,KAAKT,IAAI,cAATS,aAAe,CAAC;gBAAE;YACpE;YACA,MAAMwD,SAAS,MAAMP,GAAGvC,GAAG,CAACoC,SAASW,KAAK,CAAC,YAAY,MAAM7D,QAAQ8D,KAAK,CAAC;YAC3E,KAAK,MAAMd,OAAOY,OAAOG,IAAI,CAAE,IAAI,CAACJ,KAAKK,IAAI,CAAC,CAACvE,MAAQA,IAAIG,EAAE,KAAKoD,IAAIpD,EAAE,GAAG+D,KAAKrF,IAAI,CAAC;gBAAEsB,IAAIoD,IAAIpD,EAAE;gBAAED,MAAMqD,IAAIrD,IAAI;YAAG;YACpH,MAAMyB,QAAQrB,cAAcC,QAAQ2D;YACpC,IAAI,WAAWvC,OAAOS,QAAQvD,IAAI,CAAC8C,MAAMlD,KAAK;iBACzC+B,KAAKgE,GAAG,CAAC7C,MAAMxB,EAAE,EAAEwB;QAC1B;QACA,IAAIlC,QAAQrC,UAAU,EAAE;YACtB,wFAAwF;YACxF,MAAMqH,UAAU,MAAMb,GAAGvC,GAAG,CAACoC,SAASW,KAAK,CAAC,UAAU,MAAM,OAAOC,KAAK,CAAC/H,gBAAgBC,KAAK,GAAG;YACjG,KAAK,MAAMgH,OAAOkB,QAAQH,IAAI,CAAE;gBAC9B,MAAMtE,MAAM;oBAAEG,IAAIoD,IAAIpD,EAAE;oBAAED,MAAMqD,IAAIrD,IAAI;gBAAG;gBAC3C,IAAIM,KAAKkE,IAAI,IAAIpI,gBAAgBC,KAAK,EAAE;gBACxC,IAAIyD,IAAIE,IAAI,CAAC,YAAY,IAAI,QAAQE,QAAQJ,MAAMQ,KAAKgE,GAAG,CAACxE,IAAIG,EAAE,EAAEH;YACtE;YACA,IAAI,CAACyE,QAAQH,IAAI,CAAC9F,MAAM,IAAI,CAACiB,QAAQlD,KAAK,CAACiC,MAAM,EAAE4D,QAAQvD,IAAI,CAAC;QAClE;QACA,MAAM2C,UAA8B,EAAE;QACtC,IAAI/B,QAAQ7C,MAAM,IAAI4D,KAAKkE,IAAI,EAAE;YAC/B,MAAMC,SAAS,MAAMf,GAAGvC,GAAG,CAACqC,WAAWW,KAAK,CAAC;YAC7C,KAAK,MAAMd,OAAOoB,OAAOL,IAAI,CAAE;oBACWf,UAAmCA;gBAA3E/B,QAAQ3C,IAAI,CAAC;oBAAEsB,IAAIoD,IAAIpD,EAAE;oBAAExB,MAAMsB,QAAOsD,WAAAA,IAAIlC,GAAG,CAAC,mBAARkC,WAAmB;oBAAK9B,QAAQ,GAAG8B,YAAAA,IAAIlC,GAAG,CAAC,uBAARkC,YAAyC;gBAAK;YAC3H;QACF;QAEA,IAAI3G,SAA8C;QAClD,MAAMgI,cAAwB,EAAE;QAChC,IAAInF,QAAQ7C,MAAM,IAAI4D,KAAKkE,IAAI,EAAE;gBAWpB3C;YAVX,MAAM8C,OAAOtD,kBAAkB9B,QAAQ7C,MAAM,EAAE4E;YAC/C,MAAMO,OAAiB,EAAE;YACzB,KAAK,MAAMnD,OAAOiG,KAAKjD,MAAM,CAAE;gBAC7B,MAAMkD,MAAMpB,WAAWH,GAAG,CAAC9I;gBAC3B,MAAMgH,WAAW,QAAQ7C,IAAIkD,MAAM,GAAGlD,IAAIkD,MAAM,CAAC3B,EAAE,GAAG4B,IAAI,CAACnD,IAAIkD,MAAM,CAACC,IAAI,CAAC;gBAC3E,6EAA6E;gBAC7E6B,GAAGY,GAAG,CAACM,KAAKhK,kBAAkB;oBAAE6D,MAAMC,IAAID,IAAI;oBAAE8C;oBAAUsD,WAAWvJ,WAAWwJ,eAAe;oBAAIC,WAAW;gBAAK;gBACnHlD,KAAKlD,IAAI,CAACiG,IAAI3E,EAAE;gBAChByE,YAAY/F,IAAI,CAACD,IAAID,IAAI;YAC3B;YACA,MAAMwB,MAAK4B,SAAAA,IAAI,CAACA,KAAKvD,MAAM,GAAG,EAAE,YAArBuD,SAAyB8C,KAAK7C,UAAU;YACnD,IAAI7B,IAAIvD,SAAS;gBAAEuD;gBAAIxB,MAAMc,QAAQ7C,MAAM,CAAC6C,QAAQ7C,MAAM,CAAC4B,MAAM,GAAG,EAAE;YAAC;QACzE;QAEA,MAAM0G,OAAiBN,YAAY3G,GAAG,CAAC,CAACU,OAAS,CAAC,gBAAgB,EAAEA,KAAK,CAAC,CAAC;QAC3E,IAAIwG,eAAe;QACnB,IAAIC,aAAa;QACjB,KAAK,MAAMpF,OAAOQ,KAAK6E,MAAM,GAAI;YAC/B,MAAMC,SAASrD,kBAAkBjC,KAAKP,SAAS7C;YAC/CwF,QAAQvD,IAAI,IAAIyG,OAAOlD,OAAO;YAC9B,IAAI,CAACW,OAAOwC,IAAI,CAACD,OAAOpD,MAAM,EAAE1D,MAAM,EAAE;YACxCoF,GAAG1B,MAAM,CAACuB,SAASF,GAAG,CAACvD,IAAIG,EAAE,GAAG,aAAKmF,OAAOpD,MAAM;gBAAEsD,WAAWpC,MAAMqC,GAAG;;YACxEP,KAAKrG,IAAI,IAAIyG,OAAOnD,IAAI;YACxBgD,gBAAgB;YAChB,IAAIG,OAAOpD,MAAM,CAAC,MAAM,KAAKpC,WAAWsF,aAAa;QACvD;QACA,OAAO;YAAErB,IAAI;YAAMmB;YAAM9C;YAAS+C;YAAcP;YAAaQ;QAAW;IAC1E;AACF;AAEA,6EAA6E;AAE7E,yEAAyE,GACzE,OAAO,eAAeM,qBACpBtC,KAAoF,EACpFuC,OAAiD,CAAC,CAAC;QAGpCvC,iBAEOuC;IAHtB,IAAI,CAACvC,MAAMS,IAAI,CAACC,MAAM,EAAE,OAAO;IAC/B,MAAME,SAASZ,kBAAAA,MAAMS,IAAI,CAACxC,GAAG,CAAC,0BAAf+B,kBAAiC,CAAC;IACjD,IAAI,CAAC/H,iBAAiB2I,KAAK,CAACZ,MAAMa,GAAG,CAAC,GAAG,OAAOhI;IAChD,MAAM2J,SAAS,MAAM,EAACD,iBAAAA,KAAKE,QAAQ,YAAbF,iBAAiBrK,oBAAoB;QACzDwK,OAAO;QACP7B,KAAKb,MAAMa,GAAG;QACd8B,KAAK3C,MAAM2C,GAAG;QACdlC,MAAMT,MAAMS,IAAI,CAAC3D,IAAI;QACrB8F,QAAQ;IACV;IACA,OAAOJ,SAAS1J,uBAAuB;AACzC;AAEA,6EAA6E,GAC7E,OAAO,SAAS+J,kBAAkBf,IAAuB,EAAE9C,OAA0B,EAAEgD,UAAmB;IACxG,sEAAsE;IACtE,MAAMc,MAAMhB,KAAK1G,MAAM,GAAG,GAAG0G,KAAKxC,IAAI,CAAC,KAAK,cAAc,EAAEtG,eAAe,CAAC,CAAC,GAAG;IAChF,MAAM+J,SAASf,aAAa,6FAA6F;IACzH,MAAMgB,MAAMhE,QAAQ5D,MAAM,GAAG,CAAC,WAAW,EAAE4D,QAAQM,IAAI,CAAC,MAAM,GAAG;IACjE,OAAO,GAAGwD,MAAMC,SAASC,KAAK,CAAC5G,KAAK,CAAC,GAAG;AAC1C;AAOA,OAAO,SAAS6G,qBAAqBV,OAA2B,CAAC,CAAC;QAClDA;IAAd,MAAMW,SAAQX,cAAAA,KAAKW,KAAK,YAAVX,cAAczC;IAC5B,OAAO,OAAO,EAAEqD,GAAG,EAAEd,GAAG,EAAEtC,SAAS,EAAE4C,GAAG,EAAES,QAAQ,EAAE;kBAQzB;QAPzB,qEAAqE;QACrE,MAAMC,gBAAQD,4BAAAA,SAAW,8BAAe9K;QACxC,MAAMgL,UAAU,CAACC,UAAuC,aAAK/K,iBAAiB6K;gBAAQE;;QACtF,MAAMnD,SAAS+C,IAAI/C,MAAM;QACzB,IAAI,CAACA,QAAQ,OAAOkD,QAAQ1K;QAC5B,MAAMkI,OAAO9E,iBAAiBmH,IAAIlH,MAAM;QACxC,IAAIM,oBAAoBuE,KAAKzE,OAAO,GAAG,OAAOiH,QAAQ;YAACvK;eAA0B+H,KAAK5E,QAAQ;SAAC,CAACoD,IAAI,CAAC;QACrG,MAAMkE,UAAWb,cAAAA,OAAQ,QAAA,AAAC,CAAA,MAAM5C,UAAUG,UAAU,CAAC,QAAQC,GAAG,CAACgD,IAAIM,KAAK,EAAExF,GAAG,EAAC,EAAGnB,IAAI,cAA9D,QAAoE;QAC7F,MAAM2D,OAAO,MAAMV,UAAUG,UAAU,CAAC,SAASC,GAAG,CAACC,QAAQnC,GAAG;QAChE,MAAMyF,UAAU,MAAMpB,qBAAqB;YAAE7B;YAAMI,KAAKsC,IAAIQ,SAAS;YAAEhB,KAAKa;QAAQ,GAAG;YAAEf,UAAUF,KAAKE,QAAQ;QAAC;QACjH,IAAIiB,SAAS,OAAOlL,iBAAiB6K,OAAO;YAAEO,QAAQrL,cAAcmL;QAAS;QAC7E,MAAMG,UAAU,MAAMX,MAAMnD,WAAW;YAAEK;YAAQS,KAAKsC,IAAIQ,SAAS;YAAEtH,SAASyE,KAAKzE,OAAO;YAAEgG;QAAI;QAChG,IAAIwB,QAAQlD,EAAE,KAAK,OAAO,OAAO2C,QAAQO,QAAQxI,KAAK;QACtD,MAAM2D,UAAU;eAAI8B,KAAK5E,QAAQ;eAAK2H,QAAQ7E,OAAO;SAAC;QACtD,IAAI,CAAC6E,QAAQ/B,IAAI,CAAC1G,MAAM,IAAI4D,QAAQ5D,MAAM,EAAE,OAAOkI,QAAQtE,QAAQM,IAAI,CAAC;QACxE,MAAMwE,SAAsB;YAC1BC,UAAU;YACVhH,IAAI9D;YACJmH;YACA4D,eAAe,AAAC,OAAOvD,KAAKxC,GAAG,CAAC,iBAAiB,YAAYwC,KAAKxC,GAAG,CAAC,gBAAiB;YACvFgG,OAAO;YACPC,MAAMrB,kBAAkBgB,QAAQ/B,IAAI,EAAE9C,SAAS6E,QAAQ7B,UAAU;QACnE;QACA,OAAOxJ,iBAAiB6K,OAAO;YAAEc,SAAS;gBAACL;aAAO;QAAC;IACrD;AACF;AAEA,OAAO,MAAMM,oBAAoBnB,uBAAsB;AASvD;;;;CAIC,GACD,OAAO,SAASoB,0BAA0B9B,OAAgC,CAAC,CAAC;QAC1DA;IAAhB,MAAM+B,WAAU/B,gBAAAA,KAAK+B,OAAO,YAAZ/B,gBAAgBpK;IAChC,OAAO,OAAOoM;YAK4CA;QAJxD,IAAI,CAACA,QAAQnE,MAAM,EAAE,OAAO;YAAEoE,QAAQ;YAAKnJ,OAAOzC;QAAsB;QACxE,MAAM6L,QAAQ,MAAMH,QAAQC,QAAQnE,MAAM;QAC1C,IAAI,CAACqE,SAASA,UAAUF,QAAQd,KAAK,EAAE,OAAO;YAAEe,QAAQ;YAAKnJ,OAAO;QAAe;QACnF,MAAMoF,OAAO,MAAM8D,QAAQxE,SAAS,CAACG,UAAU,CAAC,SAASC,GAAG,CAACoE,QAAQnE,MAAM,EAAEnC,GAAG;QAChF,MAAMyF,UAAU,MAAMpB,qBAAqB;YAAE7B;YAAMI,GAAG,GAAE0D,eAAAA,QAAQ1D,GAAG,YAAX0D,eAAe;YAAI5B,KAAK4B,QAAQ5B,GAAG;QAAC,GAAG;YAAEF,UAAUF,KAAKE,QAAQ;QAAC;QACzH,IAAIiB,SAAS,OAAO;YAAEc,QAAQ;YAAKnJ,OAAOqI;QAAQ;QAClD,MAAM5C,OAAO9E,iBAAiBuI,QAAQtI,MAAM;QAC5C,OAAOM,oBAAoBuE,KAAKzE,OAAO,IAAI;YAAEmI,QAAQ;YAAKnJ,OAAO;gBAACtC;mBAA0B+H,KAAK5E,QAAQ;aAAC,CAACoD,IAAI,CAAC;QAAK,IAAI;IAC3H;AACF;AAEA,OAAO,MAAMoF,sBAAsBL,4BAA2B;AAE9D,8DAA8D,GAC9D,OAAO,SAASM;IACdlM,kBAAkBC,eAAe0L,mBAAmB;QAAEQ,WAAWjM;IAA6B;IAC9FN,uBAAuBK,eAAegM;AACxC"}
|
|
@@ -170,6 +170,8 @@ export interface AiLayoutPageCheckInput {
|
|
|
170
170
|
only?: readonly number[];
|
|
171
171
|
/** The site the page is drawn for (`aiLayoutDesignOf`); absent, the compiler's first design. */
|
|
172
172
|
design?: AiLayoutDesign | null;
|
|
173
|
+
/** The site's language, which the compiler's own words are written in (AGL-3760); absent, English. */
|
|
174
|
+
language?: string;
|
|
173
175
|
}
|
|
174
176
|
/**
|
|
175
177
|
* The follow-up turn for the sections a page's answer left out (AGL-3660):
|
|
@@ -258,6 +258,11 @@ export const AI_JOB_PAGE_LANGUAGE_BUDGET = aiJobStepBudget({
|
|
|
258
258
|
// A music site's player (AGL-3716): placed empty, for the owner's own uploads.
|
|
259
259
|
return `${index + 1}. "${section.name}"${places}; the platform places a music player here for the artist's own tracks, which they add themselves: write only its heading and a line inviting visitors to listen, and no cards, list, images or links for songs`;
|
|
260
260
|
}
|
|
261
|
+
if ((listed == null ? void 0 : listed.listing.kind) === 'events') {
|
|
262
|
+
// The site's own dated events (AGL-3755), listed by the platform with their dates.
|
|
263
|
+
const names = listed.listing.records.length ? ` (${listed.listing.records.map((name)=>`"${name}"`).join(', ')})` : '';
|
|
264
|
+
return `${index + 1}. "${section.name}"${places}; the platform lists the site's upcoming events here${names} with their dates, places and photos: write only its heading and a line inviting visitors to come, and no cards, dates, list or links for events`;
|
|
265
|
+
}
|
|
261
266
|
if ((listed == null ? void 0 : listed.listing.kind) === 'reviews') {
|
|
262
267
|
// A store's own reviews (AGL-3676): shoppers write them; none is ever written here.
|
|
263
268
|
return `${index + 1}. "${section.name}"${places}; the platform shows the store's real customer reviews here with their star ratings, once shoppers leave them: write only its heading, and no quotes, names, ratings or cards`;
|
|
@@ -411,6 +416,8 @@ export const AI_JOB_PAGE_LANGUAGE_BUDGET = aiJobStepBudget({
|
|
|
411
416
|
sectionIds: input.sectionIds
|
|
412
417
|
}, input.design ? {
|
|
413
418
|
design: input.design
|
|
419
|
+
} : {}, input.language ? {
|
|
420
|
+
language: input.language
|
|
414
421
|
} : {}));
|
|
415
422
|
const stored = aiLayoutStoredTree(compiled.tree, 'screen', context, input.sectionIds);
|
|
416
423
|
if (stored.ok === false) {
|
|
@@ -552,6 +559,8 @@ export const AI_JOB_PAGE_LANGUAGE_BUDGET = aiJobStepBudget({
|
|
|
552
559
|
design: aiLayoutDesignOf(input.job, input.screen.slug)
|
|
553
560
|
}, only ? {
|
|
554
561
|
only
|
|
562
|
+
} : {}, input.plan.language ? {
|
|
563
|
+
language: input.plan.language
|
|
555
564
|
} : {})))
|
|
556
565
|
}, input.signal ? {
|
|
557
566
|
signal: input.signal
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-job-page-language.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 { CANVAS_ROOT_ELEMENT_ID } from '@aglyn/aglyn/foundation/constants/canvas'\nimport type { NodesMap } from '@aglyn/aglyn/types/nodes'\nimport { isAiPlanNewRef, type AiBuildPlanScreen } from '../model/ai-build-plan'\nimport type { AiJob, AiJobPlan } from '../model/ai-jobs.types'\nimport {\n aiHomeScreenIds,\n type AiSiteInventory,\n} from '../model/ai-site-inventory'\nimport { AI_LAYOUT_POST_ADDRESS_TOKENS, aiCompileLayoutPage } from '../layout-language/ai-layout-compiler'\nimport { aiLayoutListingAt, aiLayoutListingsOf, aiLayoutRecordHref, type AiLayoutListing } from '../layout-language/ai-layout-listings'\nimport {\n AI_LAYOUT_LANGUAGE_TEXT,\n AI_LAYOUT_PAGE_TOOL,\n aiReadLayoutPage,\n type AiLayoutSection,\n type AiLayoutSettlement,\n} from '../layout-language/ai-layout-language'\nimport type {\n AiLayoutPage,\n AiLayoutTargets,\n} from '../layout-language/ai-layout-links'\nimport { aiLayoutCopyCheck } from '../layout-language/ai-layout-gaps'\nimport { aiLayoutStoredTree } from '../layout-language/ai-layout-store'\nimport { AI_GENERATION_MAX_ATTEMPTS } from '../runtime/ai-generation-bounds'\nimport { AI_STEP_TIERS } from '../providers/catalog'\nimport {\n runValidatedGeneration,\n type AiGenerationCheck,\n type AiGenerationSpend,\n type AiValidatedGeneration,\n} from '../runtime/ai-doctrine'\nimport type { AiUsage } from '../providers/contract'\nimport {\n aiSettleMechanicalRules,\n aiSettleUnrelatedScreenLinks,\n validateAiDoctrineTree,\n type AiDoctrineNode,\n type AiDoctrineTreeContext,\n type AiDoctrineViolation,\n} from '../runtime/ai-doctrine-validators'\nimport type { AiLoadEstimate } from '../runtime/ai-palette'\nimport { aiSiteKindDesignLines, aiSiteKindOfInputs } from '../model/ai-site-kinds'\nimport { aiSiteSeed } from '../model/ai-site-look'\nimport type { AiLayoutDesign } from '../layout-language/ai-layout-design'\nimport { aiOriginJobId } from './ai-job-draft-ids'\nimport type { AiSystemBlock } from '../runtime/ai-runtime'\nimport { aiGenerationWorstCaseOnTierMs, aiJobStepBudget } from './ai-job-budget'\nimport { aiJobBriefLine, aiPlanReferenceLines } from './ai-job-generation'\nimport { aiLayoutIsHomeSlug, aiLayoutSiteAliases, aiLayoutSitePages } from './ai-job-layout-site-pages'\nimport { aiLayoutInventedContactViolations } from './ai-layout-site-facts'\n\n/**\n * A page built in the compact layout language (AGL-3660): the page step's\n * pass for a site's page units — a guided start's and a build's — in place of\n * the raw-tree section passes.\n *\n * ONE answer a page: every planned section, in the language, through\n * `submit_page`. The compiler writes the tree, the palette validator stores\n * it as it stores any generated tree, and the doctrine checks the whole page.\n * A section the answer left out or left empty is the one thing a re-ask asks\n * for: the sections that read are kept, and the second answer fills only\n * what is still missing. Then the page step's last pass runs as it always\n * has — the whole page held to the doctrine again, its listing written, the\n * draft reported — so the item ledger, the credits and Try again work exactly\n * as they did.\n */\n\n/** The unit input that says a page or a layout is built in the layout language. */\nexport const AI_LAYOUT_LANGUAGE_INPUT = 'layoutLanguage'\n\n/** The unit input naming the page of the site that places its form, where it is another page. */\nexport const AI_LAYOUT_FORM_PAGE_INPUT = 'layoutFormPage'\n\n/** Whether this job builds its page or its layout in the layout language. */\nexport function aiJobUsesLayoutLanguage(job: Pick<AiJob, 'inputs'>): boolean {\n return job.inputs?.[AI_LAYOUT_LANGUAGE_INPUT] === true\n}\n\n/**\n * How the language doors think (AGL-3660): adaptively, at an effort named\n * rather than left to the model's default. Zach, 2026-10-07: quality first —\n * a page and a site's frame are designed, not transcribed, and the caching\n * work pays for the thinking. Medium is where Claude Sonnet 5.5, the balanced\n * default, is tuned to start for multistep design work.\n */\nexport const AI_LAYOUT_LANGUAGE_THINKING = { thinking: 'adaptive', effort: 'medium' } as const\n\n/**\n * Room for the thinking a page's answer does before it writes, inside the\n * same `max_tokens` as the answer: thinking is drawn from the ceiling first,\n * so a ceiling sized for the answer alone would cut a thoughtful answer off.\n *\n * Bounded by TIME, not by money: the page step's answer, its re-ask and the\n * follow-up must fit the least time a beat gives a step\n * (`AI_JOB_STEP_MAX_MINIMUM_MS`), and `aiJobStepBudget` quietly lowers every\n * ceiling to what fits. 2,000 here, with the follow-up's 500, is the most\n * that fits whole on the balanced tier; at 5,000 the budget cut a page's\n * ceiling to 879 tokens, under the answer itself.\n */\nexport const AI_LAYOUT_PAGE_THINKING_TOKENS = 2_000\n\n/** The same room for a site's header and footer, whose step has the time for more. */\nexport const AI_LAYOUT_FRAME_THINKING_TOKENS = 4_000\n\n/**\n * The most one page's answer asks for: the answer and the thinking before it.\n * A section in the language is about 120 to 250 tokens with its copy, so the\n * largest page a plan admits — eight sections — fits in 3,000 with room (the\n * live runs of 2026-10-07 wrote 683 to 1,745); the compiler, not the ceiling,\n * keeps a page small.\n */\nexport const AI_JOB_PAGE_LANGUAGE_TOKENS = 3_000 + AI_LAYOUT_PAGE_THINKING_TOKENS\n\n/**\n * The most one section of a page is written in, its copy included: the top of\n * the 120 to 250 tokens a section runs to. The Free site wall prices each\n * planned section at it (AGL-3660).\n */\nexport const AI_LAYOUT_SECTION_MOST_TOKENS = 250\n\n/**\n * The time a language page pass needs: its lookup rounds, its answer and its\n * re-ask at `AI_JOB_PAGE_LANGUAGE_TOKENS` on the tier the page step is served\n * from, with the step's reads and writes.\n */\n/** The most the follow-up asking only for the sections an answer left out may run to, its thinking included. */\nexport const AI_JOB_PAGE_LANGUAGE_FOLLOW_UP_TOKENS = 1_500 + 500\n\nexport const AI_JOB_PAGE_LANGUAGE_BUDGET = aiJobStepBudget({\n tier: AI_STEP_TIERS['job.page'],\n maxTokens: AI_JOB_PAGE_LANGUAGE_TOKENS,\n // The follow-up for sections an answer left out is one more generation.\n ownReadsMs: aiGenerationWorstCaseOnTierMs({\n tier: AI_STEP_TIERS['job.page'],\n maxTokens: AI_JOB_PAGE_LANGUAGE_FOLLOW_UP_TOKENS,\n }),\n})\n\n/** The doctrine scope the language doors are told: values the compiler checks itself. */\nexport const AI_LAYOUT_PAGE_KIND = 'layout-page'\n\n/** The language, as the page door's cached instructions. */\nexport const AI_JOB_PAGE_LANGUAGE_INSTRUCTIONS: readonly AiSystemBlock[] = [\n {\n text: [\n AI_LAYOUT_LANGUAGE_TEXT,\n '',\n 'Answer with submit_page: the whole page, one entry in sections for each planned section, in order.',\n ].join('\\n'),\n cacheBreakpoint: true,\n },\n]\n\n/** The page of a site plan that places its form: the form the plan creates, or one the site has. */\nexport function aiLayoutFormPageOfPlan(\n plan: Pick<AiJobPlan, 'create' | 'screens'>,\n formIds: readonly string[] = [],\n): string | null {\n const created = new Set(\n plan.create\n .filter((entry) => entry.kind === 'form')\n .map((entry) => `new:${entry.name}`.toLowerCase()),\n )\n const forms = new Set(formIds)\n const screen = plan.screens.find((entry) =>\n entry.sections.some((section) =>\n section.uses.some((ref) =>\n isAiPlanNewRef(ref) ? created.has(ref.toLowerCase()) : forms.has(ref),\n ),\n ),\n )\n return typeof screen?.id === 'string' ? screen.id : null\n}\n\n/** Every word the job was given, which a page's contact details are held to. */\nexport function aiLayoutFacts(job: Pick<AiJob, 'brief' | 'inputs'>): string {\n const values = Object.values(job.inputs ?? {}).filter(\n (value): value is string => typeof value === 'string',\n )\n return [job.brief, ...values].join('\\n')\n}\n\n/** What a page's links resolve against: the site's pages, built and planned, its forms and components. */\nexport function aiLayoutPageTargets(input: {\n job: Pick<AiJob, 'brief' | 'inputs'>\n inventory: AiSiteInventory | null\n own: ReadonlyArray<string | null | undefined>\n}): AiLayoutTargets {\n const { job, inventory } = input\n const own = input.own.filter((id): id is string => !!id)\n const planned = aiLayoutSitePages(job.inputs)\n const pages: AiLayoutPage[] = [\n ...planned,\n // Planned pages merged into the blog (AGL-3676): a link to one goes to the blog.\n ...aiLayoutSiteAliases(job.inputs).filter((alias) => !planned.some((page) => page.id === alias.id)),\n ...(inventory?.screens ?? [])\n .filter(\n (row) => !row.template && !planned.some((page) => page.id === row.id),\n )\n .map((row) => ({ id: row.id, label: row.name, slug: row.slug })),\n ]\n const formPage = job.inputs?.[AI_LAYOUT_FORM_PAGE_INPUT]\n return {\n pageId: own[0] ?? null,\n pages: pages.filter((page) => !own.includes(page.id)),\n homeIds: aiHomeScreenIds(inventory),\n forms: (inventory?.forms ?? []).map((form) => ({\n id: form.id,\n name: form.name,\n })),\n formPageId:\n typeof formPage === 'string' && !own.includes(formPage) ? formPage : null,\n components: (inventory?.components ?? []).map((component) => ({\n id: component.id,\n name: component.name,\n props: component.props,\n })),\n facts: aiLayoutFacts(job),\n // The site's catalog and blog, and the sections that list them (AGL-3676),\n // and its datasets (AGL-3616).\n listings: aiLayoutListingsWithDatasets(aiLayoutListingsOf(job.inputs), inventory),\n }\n}\n\n/**\n * A page's listings with each dataset's held to the site's inventory\n * (AGL-3616): a records listing is kept only where the site has the dataset —\n * the tree check admits a repeat over no other, and a card left repeating\n * over nothing would show its `{{item.*}}` — and one that names no fields\n * takes the inventory's, in the dataset's order. Its cards link the record\n * pages the plan makes, else those the site already serves (AGL-3747).\n */\nexport function aiLayoutListingsWithDatasets(\n listings: readonly AiLayoutListing[],\n inventory: Pick<AiSiteInventory, 'datasets'> | null,\n): AiLayoutListing[] {\n return listings.flatMap((listing) => {\n if (listing.kind !== 'records') return [listing]\n const row = inventory?.datasets.find((dataset) => dataset.id === listing.datasetId)\n if (!row) return []\n // The photo field is the card's picture, never its words (AGL-3616).\n const imageField = listing.imageField ?? row.imageField\n // The address is the card's link to its record's page, never its words (AGL-3727).\n const addressField = listing.addressField ?? row.addressField\n // A record page the site already serves for the dataset (AGL-3747), where\n // the plan makes none of its own.\n const recordBase = listing.recordBase ?? row.recordBase\n const fields = (\n listing.fields?.length\n ? listing.fields\n : row.fields.map((name, index) => ({ id: row.fieldIds?.[index] || name, name, type: 'text' }))\n ).filter((field) => field.id !== imageField && field.id !== addressField)\n return fields.length\n ? [\n {\n ...listing,\n fields,\n ...(imageField ? { imageField } : {}),\n ...(recordBase && addressField ? { recordBase, addressField } : {}),\n },\n ]\n : []\n })\n}\n\n/**\n * The page check's context with what a section listing the blog's posts\n * binds (AGL-3676): each post's card links its post and shows its cover by\n * the tokens the page fills per post, which a page's store admits whole only\n * where a listing places them. A dataset's card shows its record's photo\n * the same way (AGL-3616), by `{{item.<photo field>}}`. And the page that\n * places the site's form, which a call to action asking a visitor to get in\n * touch links even when it is home (AGL-3729).\n */\nexport function aiLayoutListingContext(\n context: AiDoctrineTreeContext,\n targets: AiLayoutTargets,\n): AiDoctrineTreeContext {\n if (targets.formPageId) context = { ...context, formScreenIds: [targets.formPageId] }\n const here = (targets.listings ?? []).filter((listing) =>\n listing.placements.some((placement) => placement.screenId === targets.pageId),\n )\n const tokens = [\n ...(here.some((listing) => listing.kind === 'posts') ? AI_LAYOUT_POST_ADDRESS_TOKENS : []),\n ...here.flatMap((listing) => (listing.kind === 'records' && listing.imageField ? [`{{item.${listing.imageField}}}`] : [])),\n // Each card's link to its record's own page (AGL-3727), admitted whole.\n ...here.flatMap((listing) => {\n const href = aiLayoutRecordHref(listing)\n return href ? [href] : []\n }),\n ]\n if (!tokens.length) return context\n return { ...context, bindingTokens: [...new Set([...(context.bindingTokens ?? []), ...tokens])] }\n}\n\n/** The page's user turn: the page, the brief, the plan, its sections and where its links may go. */\nexport function aiLayoutPagePrompt(input: {\n job: Pick<AiJob, 'brief' | 'inputs' | '$id'>\n plan: AiJobPlan\n screen: AiBuildPlanScreen\n targets: AiLayoutTargets\n reusableComponents: boolean\n /** The sections a re-ask still needs, by plan index; absent on the first ask. */\n missing?: readonly number[]\n}): string {\n const { job, plan, screen, targets } = input\n const sections = screen.sections.map((section, index) => {\n const places = section.uses.length\n ? `; places ${section.uses.join(', ')}`\n : ''\n // A section the site's records fill (AGL-3676): the platform places them,\n // so the design writes the words around them and no group for them.\n const listed = aiLayoutListingAt(targets.listings ?? [], targets.pageId, index)\n if (listed?.listing.kind === 'tracks') {\n // A music site's player (AGL-3716): placed empty, for the owner's own uploads.\n return `${index + 1}. \"${section.name}\"${places}; the platform places a music player here for the artist's own tracks, which they add themselves: write only its heading and a line inviting visitors to listen, and no cards, list, images or links for songs`\n }\n if (listed?.listing.kind === 'reviews') {\n // A store's own reviews (AGL-3676): shoppers write them; none is ever written here.\n return `${index + 1}. \"${section.name}\"${places}; the platform shows the store's real customer reviews here with their star ratings, once shoppers leave them: write only its heading, and no quotes, names, ratings or cards`\n }\n if (listed?.listing.kind === 'signup') {\n // A store's newsletter field (AGL-3676), placed by the platform.\n return `${index + 1}. \"${section.name}\"${places}; the platform places the newsletter sign-up field here: write its heading and one line on what subscribers hear about, from the brief, and no form, button or offer the brief does not make`\n }\n if (listed?.listing.kind === 'records') {\n // One of the site's datasets (AGL-3616), repeated by the platform over its records.\n const names = listed.listing.records.length ? ` (${listed.listing.records.slice(0, 6).map((name) => `“${name}”`).join(', ')})` : ''\n return `${index + 1}. \"${section.name}\"${places}; the platform lists the records of the dataset “${listed.listing.name}”${names} here itself, one card each: write only its heading and a line about them, and no cards, list or images for them`\n }\n if (listed) {\n return `${index + 1}. \"${section.name}\"${places}; the platform lists ${listed.listing.name}'s ${listed.listing.kind} here itself, with their photos and links: write only its heading and a line about them, and no cards, list or images for them`\n }\n const items = section.items ? `; shows ${section.items} items` : ''\n return `${index + 1}. \"${section.name}\"${places}${items}`\n })\n // A page merged into the blog is not offered: the blog is, by its own entry.\n const pages = targets.pages.filter((page) => !page.standsInFor).map((page) => `${page.label} (page:${page.id})`)\n const components = targets.components.map(\n (component) =>\n `${component.name} (${component.id}; props ${Object.keys(component.props).join(', ') || 'none'})`,\n )\n return [\n `Page: \"${screen.title}\" at ${screen.slug}`,\n aiJobBriefLine(job),\n // The kind of site the person picked sets how its pages are arranged (AGL-3660).\n ...aiSiteKindDesignLines(job.inputs),\n ...aiPlanReferenceLines(plan),\n `Sections to design, in order:`,\n ...sections,\n pages.length\n ? `Other pages of this site: ${pages.join(', ')}.`\n : 'This site has no other page to link.',\n targets.forms.length\n ? `The site's form: ${targets.forms.map((form) => `${form.name} (${form.id})`).join(', ')}.`\n : 'The site has no saved form: place none.',\n ...(components.length\n ? [`Components this page may place: ${components.join('; ')}.`]\n : []),\n input.reusableComponents\n ? 'Where a section repeats an item, place the component its plan line names with cards whose to is that component.'\n : 'This site keeps no reusable components: draw repeated items as cards, steps, stats or a list.',\n // A per-job word, so two identical briefs are designed apart.\n `Design seed: ${job.$id.slice(-6)}.`,\n ].join('\\n')\n}\n\n/**\n * The site a page is designed for (AGL-3660): the kind its job names, the\n * seed its look was drawn with — the same for every page of the site, so the\n * site reads as one design — and whether the page is its home. `null` for a\n * job that names no kind of site, which compiles the compiler's first way.\n */\nexport function aiLayoutDesignOf(job: Pick<AiJob, '$id' | 'inputs'>, slug: string): AiLayoutDesign | null {\n const kind = aiSiteKindOfInputs(job.inputs)\n if (!kind) return null\n const style = job.inputs?.['siteStyle'] as Record<string, unknown> | undefined\n const seed = typeof style?.['seed'] === 'number' && Number.isFinite(style['seed']) ? (style['seed'] as number) >>> 0 : aiSiteSeed(aiOriginJobId(job))\n return { kind: kind.id, seed, home: aiLayoutIsHomeSlug(slug) }\n}\n\n/** A validated language page, stored as the page keeps it. */\nexport interface AiLayoutPageBuilt {\n nodes: NodesMap\n load: AiLoadEstimate | null\n settled: AiLayoutSettlement[]\n /** What the last answer's gaps took out of the page (`ai-layout-gaps.ts`). */\n dropped: string[]\n /** How many repeated items each plan section shows, as built (AGL-3660). */\n items: number[]\n}\n\nexport interface AiLayoutPageCheckInput {\n screen: AiBuildPlanScreen\n sectionIds: readonly string[]\n targets: AiLayoutTargets\n context: AiDoctrineTreeContext\n reusableComponents: boolean\n /**\n * What earlier answers gave, by plan index, shared between the page's\n * generations: a follow-up asking only for missing sections fills the rest.\n */\n kept?: Array<AiLayoutSection | null>\n /** The plan indices this answer's sections fill, in order; absent, every section. */\n only?: readonly number[]\n /** The site the page is drawn for (`aiLayoutDesignOf`); absent, the compiler's first design. */\n design?: AiLayoutDesign | null\n}\n\n/**\n * The follow-up turn for the sections a page's answer left out (AGL-3660):\n * the page as before, told which sections it already has, and asked for only\n * the missing ones, in order — the one part of a page asked for again.\n */\nexport function aiLayoutMissingSectionsPrompt(input: {\n base: string\n screen: AiBuildPlanScreen\n missing: readonly number[]\n}): string {\n const names = input.missing.map((index) => `${index + 1}. \"${input.screen.sections[index].name}\"`)\n return [\n input.base,\n '',\n `The other sections of this page are already designed. Design ONLY these, in this order, one entry in sections each: ${names.join('; ')}. Give each at least one block.`,\n ].join('\\n')\n}\n\n/** The plan indices a page still lacks, after the answers so far. */\nexport function aiLayoutMissingSections(kept: ReadonlyArray<AiLayoutSection | null>): number[] {\n return kept.flatMap((section, index) => (section ? [] : [index]))\n}\n\n/** The violation a planned section the answer gave nothing usable for is named by. */\nexport const AI_LAYOUT_SECTION_MISSING_CODE = 'layout-section-missing'\n\n/** The code a section planned with items that shows none is refused under (AGL-3660). */\nexport const AI_LAYOUT_SECTION_EMPTY_CODE = 'layout-section-no-items'\n\n/** How many of a section's planned items it must show: one for a short list, two for anything longer. */\nconst leastItems = (planned: number) => (planned >= 3 ? 2 : planned >= 1 ? 1 : 0)\n\n/**\n * How many repeated items each section shows once stored (AGL-3660): the\n * elements the compiler drew for them, under the ids they are stored by,\n * that are still in the page after anything later took words out.\n */\nexport function aiLayoutShownItems(\n itemIds: readonly (readonly string[])[],\n storedIds: Readonly<Record<string, string>>,\n nodes: Readonly<Record<string, unknown>>,\n): number[] {\n return itemIds.map((ids) => ids.filter((id) => storedIds[id] !== undefined && storedIds[id] in nodes).length)\n}\n\n/**\n * The sections a page planned with repeated items — cards, steps, a list —\n * that show none, or too few, once the page is built (AGL-3660). A heading\n * and an intro over nothing is a section a visitor reads as broken, so it is\n * asked for again.\n */\nexport function aiLayoutEmptyItemSections(\n screen: Pick<AiBuildPlanScreen, 'sections'>,\n items: readonly number[],\n /** Sections whose only items were customer quotes, which no answer may give (AGL-3676). */\n quotesOnly: readonly number[] = [],\n): AiDoctrineViolation[] {\n return screen.sections.flatMap((section, index): AiDoctrineViolation[] => {\n if (quotesOnly.includes(index)) return []\n const least = leastItems(section.items)\n if (!least) return []\n const shown = items[index] ?? 0\n if (shown >= least) return []\n return [\n {\n rule: null,\n code: AI_LAYOUT_SECTION_EMPTY_CODE,\n message: `Section ${index + 1} (\"${section.name}\") is planned with ${section.items} items and shows ${shown || 'none'}.`,\n detail: `Give section ${index + 1} one cards, steps, stats, list or faq block holding its ${section.items} items, each with a title and its words.`,\n },\n ]\n })\n}\n\n/**\n * The check a language page answer is held to: each planned section read,\n * the page compiled, stored and checked whole. Sections that read are kept\n * across the re-ask, so the second answer is asked only for what was missing,\n * and a section it sends again that already read is not taken twice.\n */\nexport function aiLayoutPageCheck(\n input: AiLayoutPageCheckInput,\n): AiGenerationCheck<AiLayoutPageBuilt> {\n const kept: Array<AiLayoutSection | null> = input.kept ?? input.screen.sections.map(() => null)\n const fills = input.only ?? input.screen.sections.map((_, index) => index)\n const context = aiLayoutListingContext(input.context, input.targets)\n let answers = 0\n return (answer) => {\n // The last answer a generation takes has its gaps taken out rather than asked about again.\n answers += 1\n const last = answers >= AI_GENERATION_MAX_ATTEMPTS\n const reading = aiReadLayoutPage(\n answer,\n fills.length,\n fills.map((index) => input.screen.sections[index]),\n )\n reading.sections.forEach((section, position) => {\n // A section the answer gives is taken as given; one it leaves out keeps\n // what an earlier answer gave, so a re-ask may send only what was missing.\n if (section) kept[fills[position]] = section\n })\n const missing = kept.flatMap((section, index) => (section ? [] : [index]))\n if (missing.length) {\n const names = missing.map(\n (index) => `${index + 1} (\"${input.screen.sections[index].name}\")`,\n )\n return {\n value: null,\n violations: [\n {\n rule: null,\n code: AI_LAYOUT_SECTION_MISSING_CODE,\n message: `The page left out section ${names.join(', ')}.`,\n detail: `Answer again with every section in order; the sections you already designed are kept, so only ${names.join(', ')} ${missing.length === 1 ? 'needs' : 'need'} its design. Give each at least one block.`,\n },\n ],\n }\n }\n const compiled = aiCompileLayoutPage(\n kept as AiLayoutSection[],\n { title: input.screen.title, sections: input.screen.sections },\n input.targets,\n {\n reusableComponents: input.reusableComponents,\n sectionIds: input.sectionIds,\n ...(input.design ? { design: input.design } : {}),\n },\n )\n const stored = aiLayoutStoredTree(\n compiled.tree,\n 'screen',\n context,\n input.sectionIds,\n )\n if (stored.ok === false) {\n // The compiler writes only palette trees, which the property spec holds;\n // a refusal here is the platform's, and is reported as one.\n console.error('ai layout page: a compiled page did not store', {\n error: stored.error,\n })\n return {\n value: null,\n violations: [\n {\n rule: null,\n code: 'layout-compile',\n message: 'This page could not be built. Try again.',\n detail: stored.error,\n },\n ],\n }\n }\n // No gap and no internal reference in the words of a page that is published as built.\n const copy = aiLayoutCopyCheck(\n stored.nodes,\n CANVAS_ROOT_ELEMENT_ID,\n {\n pages: input.targets.pages,\n ids: [\n ...input.targets.pages.map((page) => page.id),\n ...input.targets.forms.map((form) => form.id),\n ...input.targets.components.map((component) => component.id),\n ...input.sectionIds,\n ...(input.targets.pageId ? [input.targets.pageId] : []),\n ],\n },\n last,\n )\n const { dropped } = copy\n // An attribute a rule has one answer for is settled, not asked of the model again (AGL-3660),\n // and a link sent home for nothing is sent to the form or left out (AGL-3729).\n const nodes = aiSettleUnrelatedScreenLinks(\n aiSettleMechanicalRules(\n { rootId: CANVAS_ROOT_ELEMENT_ID, nodes: copy.nodes as unknown as Record<string, AiDoctrineNode> },\n 'page',\n ),\n 'page',\n { ...context, ownScreenIds: input.targets.pageId ? [input.targets.pageId] : [] },\n ).nodes as unknown as typeof copy.nodes\n const report = validateAiDoctrineTree(\n { rootId: CANVAS_ROOT_ELEMENT_ID, nodes },\n 'page',\n {\n ...context,\n scrollTargetIds: input.sectionIds,\n // The layout language draws its own picture cards (AGL-3660).\n repeatsCompiled: true,\n },\n )\n // Each section's items as they are stored, after anything the gaps took out.\n const items = aiLayoutShownItems(compiled.itemIds, stored.storedIds, nodes as unknown as Record<string, unknown>)\n // A street address or opening hours the job was never given is invented\n // (rule 14, AGL-3596), the same check a layout is held to; a phone number\n // or an email the compiler already writes as its gap.\n const violations: AiDoctrineViolation[] = [\n ...report.violations,\n ...copy.violations,\n ...aiLayoutEmptyItemSections(input.screen, items, compiled.quotesOnly),\n ...aiLayoutInventedContactViolations(\n { rootId: CANVAS_ROOT_ELEMENT_ID, nodes: nodes as unknown as Record<string, AiDoctrineNode> },\n input.targets.facts,\n ),\n ]\n return {\n value: violations.length\n ? null\n : {\n nodes,\n load: report.load,\n settled: [...reading.settled, ...compiled.settled],\n dropped,\n items,\n },\n violations,\n }\n }\n}\n\nexport interface AiLayoutPageRunInput {\n job: Pick<AiJob, 'brief' | 'inputs' | '$id'>\n plan: AiJobPlan\n screen: AiBuildPlanScreen\n sectionIds: readonly string[]\n targets: AiLayoutTargets\n context: AiDoctrineTreeContext\n reusableComponents: boolean\n inventory: AiSiteInventory | null\n model: string\n signal?: AbortSignal\n /** Wraps the check, for an eval that records each answer it reads. */\n observe?: (check: AiGenerationCheck<AiLayoutPageBuilt>) => AiGenerationCheck<AiLayoutPageBuilt>\n}\n\n/** Two generations' spend as one: every call is billed. */\nfunction spentTogether(first: AiGenerationSpend, second: AiGenerationSpend): AiGenerationSpend {\n const usage: AiUsage = {\n inputTokens: first.usage.inputTokens + second.usage.inputTokens,\n outputTokens: first.usage.outputTokens + second.usage.outputTokens,\n cacheReadTokens: first.usage.cacheReadTokens + second.usage.cacheReadTokens,\n cacheWriteTokens: first.usage.cacheWriteTokens + second.usage.cacheWriteTokens,\n }\n return {\n attempts: first.attempts + second.attempts,\n usage,\n estCostUsd: Math.round((first.estCostUsd + second.estCostUsd) * 1_000_000) / 1_000_000,\n model: second.model,\n stopReason: second.stopReason,\n effort: second.effort,\n }\n}\n\n/**\n * A whole page in the layout language: one answer for every section, and,\n * where that answer and its re-ask still left a section out, one follow-up\n * asking for only those (AGL-3660). The sections that read are kept between\n * them, so the page is compiled whole once every section is designed.\n */\nexport async function aiRunLayoutPage(input: AiLayoutPageRunInput): Promise<AiValidatedGeneration<AiLayoutPageBuilt>> {\n const kept: Array<AiLayoutSection | null> = input.screen.sections.map(() => null)\n const observe = input.observe ?? ((check) => check)\n const base = aiLayoutPagePrompt({\n job: input.job,\n plan: input.plan,\n screen: input.screen,\n targets: input.targets,\n reusableComponents: input.reusableComponents,\n })\n const ask = (content: string, maxTokens: number, only?: readonly number[]) =>\n runValidatedGeneration<AiLayoutPageBuilt>(AI_LAYOUT_PAGE_KIND, {\n step: 'job.page',\n model: input.model,\n instructions: AI_JOB_PAGE_LANGUAGE_INSTRUCTIONS,\n inventory: input.inventory,\n messages: [{ role: 'user', content }],\n tool: AI_LAYOUT_PAGE_TOOL,\n maxTokens,\n cutOff: { noun: 'page', smaller: 'Write shorter copy, and fewer items in each group.' },\n ...AI_LAYOUT_LANGUAGE_THINKING,\n check: observe(\n aiLayoutPageCheck({\n screen: input.screen,\n sectionIds: input.sectionIds,\n targets: input.targets,\n context: input.context,\n reusableComponents: input.reusableComponents,\n kept,\n design: aiLayoutDesignOf(input.job, input.screen.slug),\n ...(only ? { only } : {}),\n }),\n ),\n ...(input.signal ? { signal: input.signal } : {}),\n })\n const first = await ask(base, AI_JOB_PAGE_LANGUAGE_BUDGET.maxTokens(input.model))\n const missing = aiLayoutMissingSections(kept)\n if (\n first.status !== 'needs_input' ||\n !missing.length ||\n !first.violations.every((violation) => violation.code === AI_LAYOUT_SECTION_MISSING_CODE)\n ) {\n return first\n }\n const second = await ask(\n aiLayoutMissingSectionsPrompt({ base, screen: input.screen, missing }),\n Math.min(AI_JOB_PAGE_LANGUAGE_FOLLOW_UP_TOKENS, AI_JOB_PAGE_LANGUAGE_BUDGET.maxTokens(input.model)),\n missing,\n )\n return { ...second, ...spentTogether(first, second) }\n}\n"],"names":["CANVAS_ROOT_ELEMENT_ID","isAiPlanNewRef","aiHomeScreenIds","AI_LAYOUT_POST_ADDRESS_TOKENS","aiCompileLayoutPage","aiLayoutListingAt","aiLayoutListingsOf","aiLayoutRecordHref","AI_LAYOUT_LANGUAGE_TEXT","AI_LAYOUT_PAGE_TOOL","aiReadLayoutPage","aiLayoutCopyCheck","aiLayoutStoredTree","AI_GENERATION_MAX_ATTEMPTS","AI_STEP_TIERS","runValidatedGeneration","aiSettleMechanicalRules","aiSettleUnrelatedScreenLinks","validateAiDoctrineTree","aiSiteKindDesignLines","aiSiteKindOfInputs","aiSiteSeed","aiOriginJobId","aiGenerationWorstCaseOnTierMs","aiJobStepBudget","aiJobBriefLine","aiPlanReferenceLines","aiLayoutIsHomeSlug","aiLayoutSiteAliases","aiLayoutSitePages","aiLayoutInventedContactViolations","AI_LAYOUT_LANGUAGE_INPUT","AI_LAYOUT_FORM_PAGE_INPUT","aiJobUsesLayoutLanguage","job","inputs","AI_LAYOUT_LANGUAGE_THINKING","thinking","effort","AI_LAYOUT_PAGE_THINKING_TOKENS","AI_LAYOUT_FRAME_THINKING_TOKENS","AI_JOB_PAGE_LANGUAGE_TOKENS","AI_LAYOUT_SECTION_MOST_TOKENS","AI_JOB_PAGE_LANGUAGE_FOLLOW_UP_TOKENS","AI_JOB_PAGE_LANGUAGE_BUDGET","tier","maxTokens","ownReadsMs","AI_LAYOUT_PAGE_KIND","AI_JOB_PAGE_LANGUAGE_INSTRUCTIONS","text","join","cacheBreakpoint","aiLayoutFormPageOfPlan","plan","formIds","created","Set","create","filter","entry","kind","map","name","toLowerCase","forms","screen","screens","find","sections","some","section","uses","ref","has","id","aiLayoutFacts","values","Object","value","brief","aiLayoutPageTargets","input","own","inventory","planned","pages","alias","page","row","template","label","slug","formPage","pageId","includes","homeIds","form","formPageId","components","component","props","facts","listings","aiLayoutListingsWithDatasets","flatMap","listing","datasets","dataset","datasetId","imageField","addressField","recordBase","fields","length","index","fieldIds","type","field","aiLayoutListingContext","context","targets","formScreenIds","here","placements","placement","screenId","tokens","href","bindingTokens","aiLayoutPagePrompt","places","listed","names","records","slice","items","standsInFor","keys","title","reusableComponents","$id","aiLayoutDesignOf","style","seed","Number","isFinite","home","aiLayoutMissingSectionsPrompt","missing","base","aiLayoutMissingSections","kept","AI_LAYOUT_SECTION_MISSING_CODE","AI_LAYOUT_SECTION_EMPTY_CODE","leastItems","aiLayoutShownItems","itemIds","storedIds","nodes","ids","undefined","aiLayoutEmptyItemSections","quotesOnly","least","shown","rule","code","message","detail","aiLayoutPageCheck","fills","only","_","answers","answer","last","reading","forEach","position","violations","compiled","sectionIds","design","stored","tree","ok","console","error","copy","dropped","rootId","ownScreenIds","report","scrollTargetIds","repeatsCompiled","load","settled","spentTogether","first","second","usage","inputTokens","outputTokens","cacheReadTokens","cacheWriteTokens","attempts","estCostUsd","Math","round","model","stopReason","aiRunLayoutPage","observe","check","ask","content","step","instructions","messages","role","tool","cutOff","noun","smaller","signal","status","every","violation","min"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-job-page-language.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 { CANVAS_ROOT_ELEMENT_ID } from '@aglyn/aglyn/foundation/constants/canvas'\nimport type { NodesMap } from '@aglyn/aglyn/types/nodes'\nimport { isAiPlanNewRef, type AiBuildPlanScreen } from '../model/ai-build-plan'\nimport type { AiJob, AiJobPlan } from '../model/ai-jobs.types'\nimport {\n aiHomeScreenIds,\n type AiSiteInventory,\n} from '../model/ai-site-inventory'\nimport { AI_LAYOUT_POST_ADDRESS_TOKENS, aiCompileLayoutPage } from '../layout-language/ai-layout-compiler'\nimport { aiLayoutListingAt, aiLayoutListingsOf, aiLayoutRecordHref, type AiLayoutListing } from '../layout-language/ai-layout-listings'\nimport {\n AI_LAYOUT_LANGUAGE_TEXT,\n AI_LAYOUT_PAGE_TOOL,\n aiReadLayoutPage,\n type AiLayoutSection,\n type AiLayoutSettlement,\n} from '../layout-language/ai-layout-language'\nimport type {\n AiLayoutPage,\n AiLayoutTargets,\n} from '../layout-language/ai-layout-links'\nimport { aiLayoutCopyCheck } from '../layout-language/ai-layout-gaps'\nimport { aiLayoutStoredTree } from '../layout-language/ai-layout-store'\nimport { AI_GENERATION_MAX_ATTEMPTS } from '../runtime/ai-generation-bounds'\nimport { AI_STEP_TIERS } from '../providers/catalog'\nimport {\n runValidatedGeneration,\n type AiGenerationCheck,\n type AiGenerationSpend,\n type AiValidatedGeneration,\n} from '../runtime/ai-doctrine'\nimport type { AiUsage } from '../providers/contract'\nimport {\n aiSettleMechanicalRules,\n aiSettleUnrelatedScreenLinks,\n validateAiDoctrineTree,\n type AiDoctrineNode,\n type AiDoctrineTreeContext,\n type AiDoctrineViolation,\n} from '../runtime/ai-doctrine-validators'\nimport type { AiLoadEstimate } from '../runtime/ai-palette'\nimport { aiSiteKindDesignLines, aiSiteKindOfInputs } from '../model/ai-site-kinds'\nimport { aiSiteSeed } from '../model/ai-site-look'\nimport type { AiLayoutDesign } from '../layout-language/ai-layout-design'\nimport { aiOriginJobId } from './ai-job-draft-ids'\nimport type { AiSystemBlock } from '../runtime/ai-runtime'\nimport { aiGenerationWorstCaseOnTierMs, aiJobStepBudget } from './ai-job-budget'\nimport { aiJobBriefLine, aiPlanReferenceLines } from './ai-job-generation'\nimport { aiLayoutIsHomeSlug, aiLayoutSiteAliases, aiLayoutSitePages } from './ai-job-layout-site-pages'\nimport { aiLayoutInventedContactViolations } from './ai-layout-site-facts'\n\n/**\n * A page built in the compact layout language (AGL-3660): the page step's\n * pass for a site's page units — a guided start's and a build's — in place of\n * the raw-tree section passes.\n *\n * ONE answer a page: every planned section, in the language, through\n * `submit_page`. The compiler writes the tree, the palette validator stores\n * it as it stores any generated tree, and the doctrine checks the whole page.\n * A section the answer left out or left empty is the one thing a re-ask asks\n * for: the sections that read are kept, and the second answer fills only\n * what is still missing. Then the page step's last pass runs as it always\n * has — the whole page held to the doctrine again, its listing written, the\n * draft reported — so the item ledger, the credits and Try again work exactly\n * as they did.\n */\n\n/** The unit input that says a page or a layout is built in the layout language. */\nexport const AI_LAYOUT_LANGUAGE_INPUT = 'layoutLanguage'\n\n/** The unit input naming the page of the site that places its form, where it is another page. */\nexport const AI_LAYOUT_FORM_PAGE_INPUT = 'layoutFormPage'\n\n/** Whether this job builds its page or its layout in the layout language. */\nexport function aiJobUsesLayoutLanguage(job: Pick<AiJob, 'inputs'>): boolean {\n return job.inputs?.[AI_LAYOUT_LANGUAGE_INPUT] === true\n}\n\n/**\n * How the language doors think (AGL-3660): adaptively, at an effort named\n * rather than left to the model's default. Zach, 2026-10-07: quality first —\n * a page and a site's frame are designed, not transcribed, and the caching\n * work pays for the thinking. Medium is where Claude Sonnet 5.5, the balanced\n * default, is tuned to start for multistep design work.\n */\nexport const AI_LAYOUT_LANGUAGE_THINKING = { thinking: 'adaptive', effort: 'medium' } as const\n\n/**\n * Room for the thinking a page's answer does before it writes, inside the\n * same `max_tokens` as the answer: thinking is drawn from the ceiling first,\n * so a ceiling sized for the answer alone would cut a thoughtful answer off.\n *\n * Bounded by TIME, not by money: the page step's answer, its re-ask and the\n * follow-up must fit the least time a beat gives a step\n * (`AI_JOB_STEP_MAX_MINIMUM_MS`), and `aiJobStepBudget` quietly lowers every\n * ceiling to what fits. 2,000 here, with the follow-up's 500, is the most\n * that fits whole on the balanced tier; at 5,000 the budget cut a page's\n * ceiling to 879 tokens, under the answer itself.\n */\nexport const AI_LAYOUT_PAGE_THINKING_TOKENS = 2_000\n\n/** The same room for a site's header and footer, whose step has the time for more. */\nexport const AI_LAYOUT_FRAME_THINKING_TOKENS = 4_000\n\n/**\n * The most one page's answer asks for: the answer and the thinking before it.\n * A section in the language is about 120 to 250 tokens with its copy, so the\n * largest page a plan admits — eight sections — fits in 3,000 with room (the\n * live runs of 2026-10-07 wrote 683 to 1,745); the compiler, not the ceiling,\n * keeps a page small.\n */\nexport const AI_JOB_PAGE_LANGUAGE_TOKENS = 3_000 + AI_LAYOUT_PAGE_THINKING_TOKENS\n\n/**\n * The most one section of a page is written in, its copy included: the top of\n * the 120 to 250 tokens a section runs to. The Free site wall prices each\n * planned section at it (AGL-3660).\n */\nexport const AI_LAYOUT_SECTION_MOST_TOKENS = 250\n\n/**\n * The time a language page pass needs: its lookup rounds, its answer and its\n * re-ask at `AI_JOB_PAGE_LANGUAGE_TOKENS` on the tier the page step is served\n * from, with the step's reads and writes.\n */\n/** The most the follow-up asking only for the sections an answer left out may run to, its thinking included. */\nexport const AI_JOB_PAGE_LANGUAGE_FOLLOW_UP_TOKENS = 1_500 + 500\n\nexport const AI_JOB_PAGE_LANGUAGE_BUDGET = aiJobStepBudget({\n tier: AI_STEP_TIERS['job.page'],\n maxTokens: AI_JOB_PAGE_LANGUAGE_TOKENS,\n // The follow-up for sections an answer left out is one more generation.\n ownReadsMs: aiGenerationWorstCaseOnTierMs({\n tier: AI_STEP_TIERS['job.page'],\n maxTokens: AI_JOB_PAGE_LANGUAGE_FOLLOW_UP_TOKENS,\n }),\n})\n\n/** The doctrine scope the language doors are told: values the compiler checks itself. */\nexport const AI_LAYOUT_PAGE_KIND = 'layout-page'\n\n/** The language, as the page door's cached instructions. */\nexport const AI_JOB_PAGE_LANGUAGE_INSTRUCTIONS: readonly AiSystemBlock[] = [\n {\n text: [\n AI_LAYOUT_LANGUAGE_TEXT,\n '',\n 'Answer with submit_page: the whole page, one entry in sections for each planned section, in order.',\n ].join('\\n'),\n cacheBreakpoint: true,\n },\n]\n\n/** The page of a site plan that places its form: the form the plan creates, or one the site has. */\nexport function aiLayoutFormPageOfPlan(\n plan: Pick<AiJobPlan, 'create' | 'screens'>,\n formIds: readonly string[] = [],\n): string | null {\n const created = new Set(\n plan.create\n .filter((entry) => entry.kind === 'form')\n .map((entry) => `new:${entry.name}`.toLowerCase()),\n )\n const forms = new Set(formIds)\n const screen = plan.screens.find((entry) =>\n entry.sections.some((section) =>\n section.uses.some((ref) =>\n isAiPlanNewRef(ref) ? created.has(ref.toLowerCase()) : forms.has(ref),\n ),\n ),\n )\n return typeof screen?.id === 'string' ? screen.id : null\n}\n\n/** Every word the job was given, which a page's contact details are held to. */\nexport function aiLayoutFacts(job: Pick<AiJob, 'brief' | 'inputs'>): string {\n const values = Object.values(job.inputs ?? {}).filter(\n (value): value is string => typeof value === 'string',\n )\n return [job.brief, ...values].join('\\n')\n}\n\n/** What a page's links resolve against: the site's pages, built and planned, its forms and components. */\nexport function aiLayoutPageTargets(input: {\n job: Pick<AiJob, 'brief' | 'inputs'>\n inventory: AiSiteInventory | null\n own: ReadonlyArray<string | null | undefined>\n}): AiLayoutTargets {\n const { job, inventory } = input\n const own = input.own.filter((id): id is string => !!id)\n const planned = aiLayoutSitePages(job.inputs)\n const pages: AiLayoutPage[] = [\n ...planned,\n // Planned pages merged into the blog (AGL-3676): a link to one goes to the blog.\n ...aiLayoutSiteAliases(job.inputs).filter((alias) => !planned.some((page) => page.id === alias.id)),\n ...(inventory?.screens ?? [])\n .filter(\n (row) => !row.template && !planned.some((page) => page.id === row.id),\n )\n .map((row) => ({ id: row.id, label: row.name, slug: row.slug })),\n ]\n const formPage = job.inputs?.[AI_LAYOUT_FORM_PAGE_INPUT]\n return {\n pageId: own[0] ?? null,\n pages: pages.filter((page) => !own.includes(page.id)),\n homeIds: aiHomeScreenIds(inventory),\n forms: (inventory?.forms ?? []).map((form) => ({\n id: form.id,\n name: form.name,\n })),\n formPageId:\n typeof formPage === 'string' && !own.includes(formPage) ? formPage : null,\n components: (inventory?.components ?? []).map((component) => ({\n id: component.id,\n name: component.name,\n props: component.props,\n })),\n facts: aiLayoutFacts(job),\n // The site's catalog and blog, and the sections that list them (AGL-3676),\n // and its datasets (AGL-3616).\n listings: aiLayoutListingsWithDatasets(aiLayoutListingsOf(job.inputs), inventory),\n }\n}\n\n/**\n * A page's listings with each dataset's held to the site's inventory\n * (AGL-3616): a records listing is kept only where the site has the dataset —\n * the tree check admits a repeat over no other, and a card left repeating\n * over nothing would show its `{{item.*}}` — and one that names no fields\n * takes the inventory's, in the dataset's order. Its cards link the record\n * pages the plan makes, else those the site already serves (AGL-3747).\n */\nexport function aiLayoutListingsWithDatasets(\n listings: readonly AiLayoutListing[],\n inventory: Pick<AiSiteInventory, 'datasets'> | null,\n): AiLayoutListing[] {\n return listings.flatMap((listing) => {\n if (listing.kind !== 'records') return [listing]\n const row = inventory?.datasets.find((dataset) => dataset.id === listing.datasetId)\n if (!row) return []\n // The photo field is the card's picture, never its words (AGL-3616).\n const imageField = listing.imageField ?? row.imageField\n // The address is the card's link to its record's page, never its words (AGL-3727).\n const addressField = listing.addressField ?? row.addressField\n // A record page the site already serves for the dataset (AGL-3747), where\n // the plan makes none of its own.\n const recordBase = listing.recordBase ?? row.recordBase\n const fields = (\n listing.fields?.length\n ? listing.fields\n : row.fields.map((name, index) => ({ id: row.fieldIds?.[index] || name, name, type: 'text' }))\n ).filter((field) => field.id !== imageField && field.id !== addressField)\n return fields.length\n ? [\n {\n ...listing,\n fields,\n ...(imageField ? { imageField } : {}),\n ...(recordBase && addressField ? { recordBase, addressField } : {}),\n },\n ]\n : []\n })\n}\n\n/**\n * The page check's context with what a section listing the blog's posts\n * binds (AGL-3676): each post's card links its post and shows its cover by\n * the tokens the page fills per post, which a page's store admits whole only\n * where a listing places them. A dataset's card shows its record's photo\n * the same way (AGL-3616), by `{{item.<photo field>}}`. And the page that\n * places the site's form, which a call to action asking a visitor to get in\n * touch links even when it is home (AGL-3729).\n */\nexport function aiLayoutListingContext(\n context: AiDoctrineTreeContext,\n targets: AiLayoutTargets,\n): AiDoctrineTreeContext {\n if (targets.formPageId) context = { ...context, formScreenIds: [targets.formPageId] }\n const here = (targets.listings ?? []).filter((listing) =>\n listing.placements.some((placement) => placement.screenId === targets.pageId),\n )\n const tokens = [\n ...(here.some((listing) => listing.kind === 'posts') ? AI_LAYOUT_POST_ADDRESS_TOKENS : []),\n ...here.flatMap((listing) => (listing.kind === 'records' && listing.imageField ? [`{{item.${listing.imageField}}}`] : [])),\n // Each card's link to its record's own page (AGL-3727), admitted whole.\n ...here.flatMap((listing) => {\n const href = aiLayoutRecordHref(listing)\n return href ? [href] : []\n }),\n ]\n if (!tokens.length) return context\n return { ...context, bindingTokens: [...new Set([...(context.bindingTokens ?? []), ...tokens])] }\n}\n\n/** The page's user turn: the page, the brief, the plan, its sections and where its links may go. */\nexport function aiLayoutPagePrompt(input: {\n job: Pick<AiJob, 'brief' | 'inputs' | '$id'>\n plan: AiJobPlan\n screen: AiBuildPlanScreen\n targets: AiLayoutTargets\n reusableComponents: boolean\n /** The sections a re-ask still needs, by plan index; absent on the first ask. */\n missing?: readonly number[]\n}): string {\n const { job, plan, screen, targets } = input\n const sections = screen.sections.map((section, index) => {\n const places = section.uses.length\n ? `; places ${section.uses.join(', ')}`\n : ''\n // A section the site's records fill (AGL-3676): the platform places them,\n // so the design writes the words around them and no group for them.\n const listed = aiLayoutListingAt(targets.listings ?? [], targets.pageId, index)\n if (listed?.listing.kind === 'tracks') {\n // A music site's player (AGL-3716): placed empty, for the owner's own uploads.\n return `${index + 1}. \"${section.name}\"${places}; the platform places a music player here for the artist's own tracks, which they add themselves: write only its heading and a line inviting visitors to listen, and no cards, list, images or links for songs`\n }\n if (listed?.listing.kind === 'events') {\n // The site's own dated events (AGL-3755), listed by the platform with their dates.\n const names = listed.listing.records.length ? ` (${listed.listing.records.map((name) => `\"${name}\"`).join(', ')})` : ''\n return `${index + 1}. \"${section.name}\"${places}; the platform lists the site's upcoming events here${names} with their dates, places and photos: write only its heading and a line inviting visitors to come, and no cards, dates, list or links for events`\n }\n if (listed?.listing.kind === 'reviews') {\n // A store's own reviews (AGL-3676): shoppers write them; none is ever written here.\n return `${index + 1}. \"${section.name}\"${places}; the platform shows the store's real customer reviews here with their star ratings, once shoppers leave them: write only its heading, and no quotes, names, ratings or cards`\n }\n if (listed?.listing.kind === 'signup') {\n // A store's newsletter field (AGL-3676), placed by the platform.\n return `${index + 1}. \"${section.name}\"${places}; the platform places the newsletter sign-up field here: write its heading and one line on what subscribers hear about, from the brief, and no form, button or offer the brief does not make`\n }\n if (listed?.listing.kind === 'records') {\n // One of the site's datasets (AGL-3616), repeated by the platform over its records.\n const names = listed.listing.records.length ? ` (${listed.listing.records.slice(0, 6).map((name) => `“${name}”`).join(', ')})` : ''\n return `${index + 1}. \"${section.name}\"${places}; the platform lists the records of the dataset “${listed.listing.name}”${names} here itself, one card each: write only its heading and a line about them, and no cards, list or images for them`\n }\n if (listed) {\n return `${index + 1}. \"${section.name}\"${places}; the platform lists ${listed.listing.name}'s ${listed.listing.kind} here itself, with their photos and links: write only its heading and a line about them, and no cards, list or images for them`\n }\n const items = section.items ? `; shows ${section.items} items` : ''\n return `${index + 1}. \"${section.name}\"${places}${items}`\n })\n // A page merged into the blog is not offered: the blog is, by its own entry.\n const pages = targets.pages.filter((page) => !page.standsInFor).map((page) => `${page.label} (page:${page.id})`)\n const components = targets.components.map(\n (component) =>\n `${component.name} (${component.id}; props ${Object.keys(component.props).join(', ') || 'none'})`,\n )\n return [\n `Page: \"${screen.title}\" at ${screen.slug}`,\n aiJobBriefLine(job),\n // The kind of site the person picked sets how its pages are arranged (AGL-3660).\n ...aiSiteKindDesignLines(job.inputs),\n ...aiPlanReferenceLines(plan),\n `Sections to design, in order:`,\n ...sections,\n pages.length\n ? `Other pages of this site: ${pages.join(', ')}.`\n : 'This site has no other page to link.',\n targets.forms.length\n ? `The site's form: ${targets.forms.map((form) => `${form.name} (${form.id})`).join(', ')}.`\n : 'The site has no saved form: place none.',\n ...(components.length\n ? [`Components this page may place: ${components.join('; ')}.`]\n : []),\n input.reusableComponents\n ? 'Where a section repeats an item, place the component its plan line names with cards whose to is that component.'\n : 'This site keeps no reusable components: draw repeated items as cards, steps, stats or a list.',\n // A per-job word, so two identical briefs are designed apart.\n `Design seed: ${job.$id.slice(-6)}.`,\n ].join('\\n')\n}\n\n/**\n * The site a page is designed for (AGL-3660): the kind its job names, the\n * seed its look was drawn with — the same for every page of the site, so the\n * site reads as one design — and whether the page is its home. `null` for a\n * job that names no kind of site, which compiles the compiler's first way.\n */\nexport function aiLayoutDesignOf(job: Pick<AiJob, '$id' | 'inputs'>, slug: string): AiLayoutDesign | null {\n const kind = aiSiteKindOfInputs(job.inputs)\n if (!kind) return null\n const style = job.inputs?.['siteStyle'] as Record<string, unknown> | undefined\n const seed = typeof style?.['seed'] === 'number' && Number.isFinite(style['seed']) ? (style['seed'] as number) >>> 0 : aiSiteSeed(aiOriginJobId(job))\n return { kind: kind.id, seed, home: aiLayoutIsHomeSlug(slug) }\n}\n\n/** A validated language page, stored as the page keeps it. */\nexport interface AiLayoutPageBuilt {\n nodes: NodesMap\n load: AiLoadEstimate | null\n settled: AiLayoutSettlement[]\n /** What the last answer's gaps took out of the page (`ai-layout-gaps.ts`). */\n dropped: string[]\n /** How many repeated items each plan section shows, as built (AGL-3660). */\n items: number[]\n}\n\nexport interface AiLayoutPageCheckInput {\n screen: AiBuildPlanScreen\n sectionIds: readonly string[]\n targets: AiLayoutTargets\n context: AiDoctrineTreeContext\n reusableComponents: boolean\n /**\n * What earlier answers gave, by plan index, shared between the page's\n * generations: a follow-up asking only for missing sections fills the rest.\n */\n kept?: Array<AiLayoutSection | null>\n /** The plan indices this answer's sections fill, in order; absent, every section. */\n only?: readonly number[]\n /** The site the page is drawn for (`aiLayoutDesignOf`); absent, the compiler's first design. */\n design?: AiLayoutDesign | null\n /** The site's language, which the compiler's own words are written in (AGL-3760); absent, English. */\n language?: string\n}\n\n/**\n * The follow-up turn for the sections a page's answer left out (AGL-3660):\n * the page as before, told which sections it already has, and asked for only\n * the missing ones, in order — the one part of a page asked for again.\n */\nexport function aiLayoutMissingSectionsPrompt(input: {\n base: string\n screen: AiBuildPlanScreen\n missing: readonly number[]\n}): string {\n const names = input.missing.map((index) => `${index + 1}. \"${input.screen.sections[index].name}\"`)\n return [\n input.base,\n '',\n `The other sections of this page are already designed. Design ONLY these, in this order, one entry in sections each: ${names.join('; ')}. Give each at least one block.`,\n ].join('\\n')\n}\n\n/** The plan indices a page still lacks, after the answers so far. */\nexport function aiLayoutMissingSections(kept: ReadonlyArray<AiLayoutSection | null>): number[] {\n return kept.flatMap((section, index) => (section ? [] : [index]))\n}\n\n/** The violation a planned section the answer gave nothing usable for is named by. */\nexport const AI_LAYOUT_SECTION_MISSING_CODE = 'layout-section-missing'\n\n/** The code a section planned with items that shows none is refused under (AGL-3660). */\nexport const AI_LAYOUT_SECTION_EMPTY_CODE = 'layout-section-no-items'\n\n/** How many of a section's planned items it must show: one for a short list, two for anything longer. */\nconst leastItems = (planned: number) => (planned >= 3 ? 2 : planned >= 1 ? 1 : 0)\n\n/**\n * How many repeated items each section shows once stored (AGL-3660): the\n * elements the compiler drew for them, under the ids they are stored by,\n * that are still in the page after anything later took words out.\n */\nexport function aiLayoutShownItems(\n itemIds: readonly (readonly string[])[],\n storedIds: Readonly<Record<string, string>>,\n nodes: Readonly<Record<string, unknown>>,\n): number[] {\n return itemIds.map((ids) => ids.filter((id) => storedIds[id] !== undefined && storedIds[id] in nodes).length)\n}\n\n/**\n * The sections a page planned with repeated items — cards, steps, a list —\n * that show none, or too few, once the page is built (AGL-3660). A heading\n * and an intro over nothing is a section a visitor reads as broken, so it is\n * asked for again.\n */\nexport function aiLayoutEmptyItemSections(\n screen: Pick<AiBuildPlanScreen, 'sections'>,\n items: readonly number[],\n /** Sections whose only items were customer quotes, which no answer may give (AGL-3676). */\n quotesOnly: readonly number[] = [],\n): AiDoctrineViolation[] {\n return screen.sections.flatMap((section, index): AiDoctrineViolation[] => {\n if (quotesOnly.includes(index)) return []\n const least = leastItems(section.items)\n if (!least) return []\n const shown = items[index] ?? 0\n if (shown >= least) return []\n return [\n {\n rule: null,\n code: AI_LAYOUT_SECTION_EMPTY_CODE,\n message: `Section ${index + 1} (\"${section.name}\") is planned with ${section.items} items and shows ${shown || 'none'}.`,\n detail: `Give section ${index + 1} one cards, steps, stats, list or faq block holding its ${section.items} items, each with a title and its words.`,\n },\n ]\n })\n}\n\n/**\n * The check a language page answer is held to: each planned section read,\n * the page compiled, stored and checked whole. Sections that read are kept\n * across the re-ask, so the second answer is asked only for what was missing,\n * and a section it sends again that already read is not taken twice.\n */\nexport function aiLayoutPageCheck(\n input: AiLayoutPageCheckInput,\n): AiGenerationCheck<AiLayoutPageBuilt> {\n const kept: Array<AiLayoutSection | null> = input.kept ?? input.screen.sections.map(() => null)\n const fills = input.only ?? input.screen.sections.map((_, index) => index)\n const context = aiLayoutListingContext(input.context, input.targets)\n let answers = 0\n return (answer) => {\n // The last answer a generation takes has its gaps taken out rather than asked about again.\n answers += 1\n const last = answers >= AI_GENERATION_MAX_ATTEMPTS\n const reading = aiReadLayoutPage(\n answer,\n fills.length,\n fills.map((index) => input.screen.sections[index]),\n )\n reading.sections.forEach((section, position) => {\n // A section the answer gives is taken as given; one it leaves out keeps\n // what an earlier answer gave, so a re-ask may send only what was missing.\n if (section) kept[fills[position]] = section\n })\n const missing = kept.flatMap((section, index) => (section ? [] : [index]))\n if (missing.length) {\n const names = missing.map(\n (index) => `${index + 1} (\"${input.screen.sections[index].name}\")`,\n )\n return {\n value: null,\n violations: [\n {\n rule: null,\n code: AI_LAYOUT_SECTION_MISSING_CODE,\n message: `The page left out section ${names.join(', ')}.`,\n detail: `Answer again with every section in order; the sections you already designed are kept, so only ${names.join(', ')} ${missing.length === 1 ? 'needs' : 'need'} its design. Give each at least one block.`,\n },\n ],\n }\n }\n const compiled = aiCompileLayoutPage(\n kept as AiLayoutSection[],\n { title: input.screen.title, sections: input.screen.sections },\n input.targets,\n {\n reusableComponents: input.reusableComponents,\n sectionIds: input.sectionIds,\n ...(input.design ? { design: input.design } : {}),\n ...(input.language ? { language: input.language } : {}),\n },\n )\n const stored = aiLayoutStoredTree(\n compiled.tree,\n 'screen',\n context,\n input.sectionIds,\n )\n if (stored.ok === false) {\n // The compiler writes only palette trees, which the property spec holds;\n // a refusal here is the platform's, and is reported as one.\n console.error('ai layout page: a compiled page did not store', {\n error: stored.error,\n })\n return {\n value: null,\n violations: [\n {\n rule: null,\n code: 'layout-compile',\n message: 'This page could not be built. Try again.',\n detail: stored.error,\n },\n ],\n }\n }\n // No gap and no internal reference in the words of a page that is published as built.\n const copy = aiLayoutCopyCheck(\n stored.nodes,\n CANVAS_ROOT_ELEMENT_ID,\n {\n pages: input.targets.pages,\n ids: [\n ...input.targets.pages.map((page) => page.id),\n ...input.targets.forms.map((form) => form.id),\n ...input.targets.components.map((component) => component.id),\n ...input.sectionIds,\n ...(input.targets.pageId ? [input.targets.pageId] : []),\n ],\n },\n last,\n )\n const { dropped } = copy\n // An attribute a rule has one answer for is settled, not asked of the model again (AGL-3660),\n // and a link sent home for nothing is sent to the form or left out (AGL-3729).\n const nodes = aiSettleUnrelatedScreenLinks(\n aiSettleMechanicalRules(\n { rootId: CANVAS_ROOT_ELEMENT_ID, nodes: copy.nodes as unknown as Record<string, AiDoctrineNode> },\n 'page',\n ),\n 'page',\n { ...context, ownScreenIds: input.targets.pageId ? [input.targets.pageId] : [] },\n ).nodes as unknown as typeof copy.nodes\n const report = validateAiDoctrineTree(\n { rootId: CANVAS_ROOT_ELEMENT_ID, nodes },\n 'page',\n {\n ...context,\n scrollTargetIds: input.sectionIds,\n // The layout language draws its own picture cards (AGL-3660).\n repeatsCompiled: true,\n },\n )\n // Each section's items as they are stored, after anything the gaps took out.\n const items = aiLayoutShownItems(compiled.itemIds, stored.storedIds, nodes as unknown as Record<string, unknown>)\n // A street address or opening hours the job was never given is invented\n // (rule 14, AGL-3596), the same check a layout is held to; a phone number\n // or an email the compiler already writes as its gap.\n const violations: AiDoctrineViolation[] = [\n ...report.violations,\n ...copy.violations,\n ...aiLayoutEmptyItemSections(input.screen, items, compiled.quotesOnly),\n ...aiLayoutInventedContactViolations(\n { rootId: CANVAS_ROOT_ELEMENT_ID, nodes: nodes as unknown as Record<string, AiDoctrineNode> },\n input.targets.facts,\n ),\n ]\n return {\n value: violations.length\n ? null\n : {\n nodes,\n load: report.load,\n settled: [...reading.settled, ...compiled.settled],\n dropped,\n items,\n },\n violations,\n }\n }\n}\n\nexport interface AiLayoutPageRunInput {\n job: Pick<AiJob, 'brief' | 'inputs' | '$id'>\n plan: AiJobPlan\n screen: AiBuildPlanScreen\n sectionIds: readonly string[]\n targets: AiLayoutTargets\n context: AiDoctrineTreeContext\n reusableComponents: boolean\n inventory: AiSiteInventory | null\n model: string\n signal?: AbortSignal\n /** Wraps the check, for an eval that records each answer it reads. */\n observe?: (check: AiGenerationCheck<AiLayoutPageBuilt>) => AiGenerationCheck<AiLayoutPageBuilt>\n}\n\n/** Two generations' spend as one: every call is billed. */\nfunction spentTogether(first: AiGenerationSpend, second: AiGenerationSpend): AiGenerationSpend {\n const usage: AiUsage = {\n inputTokens: first.usage.inputTokens + second.usage.inputTokens,\n outputTokens: first.usage.outputTokens + second.usage.outputTokens,\n cacheReadTokens: first.usage.cacheReadTokens + second.usage.cacheReadTokens,\n cacheWriteTokens: first.usage.cacheWriteTokens + second.usage.cacheWriteTokens,\n }\n return {\n attempts: first.attempts + second.attempts,\n usage,\n estCostUsd: Math.round((first.estCostUsd + second.estCostUsd) * 1_000_000) / 1_000_000,\n model: second.model,\n stopReason: second.stopReason,\n effort: second.effort,\n }\n}\n\n/**\n * A whole page in the layout language: one answer for every section, and,\n * where that answer and its re-ask still left a section out, one follow-up\n * asking for only those (AGL-3660). The sections that read are kept between\n * them, so the page is compiled whole once every section is designed.\n */\nexport async function aiRunLayoutPage(input: AiLayoutPageRunInput): Promise<AiValidatedGeneration<AiLayoutPageBuilt>> {\n const kept: Array<AiLayoutSection | null> = input.screen.sections.map(() => null)\n const observe = input.observe ?? ((check) => check)\n const base = aiLayoutPagePrompt({\n job: input.job,\n plan: input.plan,\n screen: input.screen,\n targets: input.targets,\n reusableComponents: input.reusableComponents,\n })\n const ask = (content: string, maxTokens: number, only?: readonly number[]) =>\n runValidatedGeneration<AiLayoutPageBuilt>(AI_LAYOUT_PAGE_KIND, {\n step: 'job.page',\n model: input.model,\n instructions: AI_JOB_PAGE_LANGUAGE_INSTRUCTIONS,\n inventory: input.inventory,\n messages: [{ role: 'user', content }],\n tool: AI_LAYOUT_PAGE_TOOL,\n maxTokens,\n cutOff: { noun: 'page', smaller: 'Write shorter copy, and fewer items in each group.' },\n ...AI_LAYOUT_LANGUAGE_THINKING,\n check: observe(\n aiLayoutPageCheck({\n screen: input.screen,\n sectionIds: input.sectionIds,\n targets: input.targets,\n context: input.context,\n reusableComponents: input.reusableComponents,\n kept,\n design: aiLayoutDesignOf(input.job, input.screen.slug),\n ...(only ? { only } : {}),\n ...(input.plan.language ? { language: input.plan.language } : {}),\n }),\n ),\n ...(input.signal ? { signal: input.signal } : {}),\n })\n const first = await ask(base, AI_JOB_PAGE_LANGUAGE_BUDGET.maxTokens(input.model))\n const missing = aiLayoutMissingSections(kept)\n if (\n first.status !== 'needs_input' ||\n !missing.length ||\n !first.violations.every((violation) => violation.code === AI_LAYOUT_SECTION_MISSING_CODE)\n ) {\n return first\n }\n const second = await ask(\n aiLayoutMissingSectionsPrompt({ base, screen: input.screen, missing }),\n Math.min(AI_JOB_PAGE_LANGUAGE_FOLLOW_UP_TOKENS, AI_JOB_PAGE_LANGUAGE_BUDGET.maxTokens(input.model)),\n missing,\n )\n return { ...second, ...spentTogether(first, second) }\n}\n"],"names":["CANVAS_ROOT_ELEMENT_ID","isAiPlanNewRef","aiHomeScreenIds","AI_LAYOUT_POST_ADDRESS_TOKENS","aiCompileLayoutPage","aiLayoutListingAt","aiLayoutListingsOf","aiLayoutRecordHref","AI_LAYOUT_LANGUAGE_TEXT","AI_LAYOUT_PAGE_TOOL","aiReadLayoutPage","aiLayoutCopyCheck","aiLayoutStoredTree","AI_GENERATION_MAX_ATTEMPTS","AI_STEP_TIERS","runValidatedGeneration","aiSettleMechanicalRules","aiSettleUnrelatedScreenLinks","validateAiDoctrineTree","aiSiteKindDesignLines","aiSiteKindOfInputs","aiSiteSeed","aiOriginJobId","aiGenerationWorstCaseOnTierMs","aiJobStepBudget","aiJobBriefLine","aiPlanReferenceLines","aiLayoutIsHomeSlug","aiLayoutSiteAliases","aiLayoutSitePages","aiLayoutInventedContactViolations","AI_LAYOUT_LANGUAGE_INPUT","AI_LAYOUT_FORM_PAGE_INPUT","aiJobUsesLayoutLanguage","job","inputs","AI_LAYOUT_LANGUAGE_THINKING","thinking","effort","AI_LAYOUT_PAGE_THINKING_TOKENS","AI_LAYOUT_FRAME_THINKING_TOKENS","AI_JOB_PAGE_LANGUAGE_TOKENS","AI_LAYOUT_SECTION_MOST_TOKENS","AI_JOB_PAGE_LANGUAGE_FOLLOW_UP_TOKENS","AI_JOB_PAGE_LANGUAGE_BUDGET","tier","maxTokens","ownReadsMs","AI_LAYOUT_PAGE_KIND","AI_JOB_PAGE_LANGUAGE_INSTRUCTIONS","text","join","cacheBreakpoint","aiLayoutFormPageOfPlan","plan","formIds","created","Set","create","filter","entry","kind","map","name","toLowerCase","forms","screen","screens","find","sections","some","section","uses","ref","has","id","aiLayoutFacts","values","Object","value","brief","aiLayoutPageTargets","input","own","inventory","planned","pages","alias","page","row","template","label","slug","formPage","pageId","includes","homeIds","form","formPageId","components","component","props","facts","listings","aiLayoutListingsWithDatasets","flatMap","listing","datasets","dataset","datasetId","imageField","addressField","recordBase","fields","length","index","fieldIds","type","field","aiLayoutListingContext","context","targets","formScreenIds","here","placements","placement","screenId","tokens","href","bindingTokens","aiLayoutPagePrompt","places","listed","names","records","slice","items","standsInFor","keys","title","reusableComponents","$id","aiLayoutDesignOf","style","seed","Number","isFinite","home","aiLayoutMissingSectionsPrompt","missing","base","aiLayoutMissingSections","kept","AI_LAYOUT_SECTION_MISSING_CODE","AI_LAYOUT_SECTION_EMPTY_CODE","leastItems","aiLayoutShownItems","itemIds","storedIds","nodes","ids","undefined","aiLayoutEmptyItemSections","quotesOnly","least","shown","rule","code","message","detail","aiLayoutPageCheck","fills","only","_","answers","answer","last","reading","forEach","position","violations","compiled","sectionIds","design","language","stored","tree","ok","console","error","copy","dropped","rootId","ownScreenIds","report","scrollTargetIds","repeatsCompiled","load","settled","spentTogether","first","second","usage","inputTokens","outputTokens","cacheReadTokens","cacheWriteTokens","attempts","estCostUsd","Math","round","model","stopReason","aiRunLayoutPage","observe","check","ask","content","step","instructions","messages","role","tool","cutOff","noun","smaller","signal","status","every","violation","min"],"mappings":"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"}
|
|
@@ -18,7 +18,7 @@ import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
|
18
18
|
import { CANVAS_ROOT_ELEMENT_ID } from "@aglyn/aglyn/foundation/constants/canvas";
|
|
19
19
|
import { aiPlanCreateFor } from "../model/ai-build-plan.js";
|
|
20
20
|
import { aiPageTypeDefinition, parseAiPageJobInputs } from "../model/ai-page-job.js";
|
|
21
|
-
import { aiHomeScreenIds } from "../model/ai-site-inventory.js";
|
|
21
|
+
import { aiHomeScreenIds, aiHomeScreenNames } from "../model/ai-site-inventory.js";
|
|
22
22
|
import { AI_REASK_OFFENDING_MAX_CHARS, aiAnswerTree, aiNodeTreeContextFromInventory } from "../runtime/ai-doctrine.js";
|
|
23
23
|
import { aiSettleCutHeadings, aiSettleDisagreeingNodes, aiSettleGridItems, aiSettleMechanicalRules, detectCutLines, detectDisagreeingNodes, isAiLinkElement, validateAiDoctrineTree, walkTree } from "../runtime/ai-doctrine-validators.js";
|
|
24
24
|
import { AI_INSTANCE_REF_PROP, validateAiNodeTree } from "../runtime/ai-node-tree.js";
|
|
@@ -84,7 +84,7 @@ import { aiPlanItemCountViolations } from "./ai-job-plan-conformance.js";
|
|
|
84
84
|
'You build a web page one section at a time, in the order a confirmed plan gives. Each answer is ONE section: call submit_section with a flat node map whose root is the document wrapper (componentId "div") holding exactly one Section (section).',
|
|
85
85
|
'The first section is the top of the page and holds the page’s one h1, its title. Every later section opens with an h2, and headings below it step down one level at a time.',
|
|
86
86
|
'Place what the section’s plan line names. A component the site has is placed as an instance, never drawn again: componentId "reusableInstance", props {"refId": "<component id>", "propValues": {…}} filling the props the inventory lists. A form the site has is a Form (form) whose formId is that form’s id. Another page of the site is linked by its page id, with a Page Link (muiScreenLink) or a Button (muiButton) whose screenId is that id.',
|
|
87
|
-
'Where the request says the site keeps no reusable components, draw a repeated item in the section instead, written once. A form is only ever a saved one placed by its formId: where the plan line names no form, the section draws no form and no
|
|
87
|
+
'Where the request says the site keeps no reusable components, draw a repeated item in the section instead, written once. A form is only ever a saved one placed by its formId: where the plan line names no form, the section draws no form and no field of one.',
|
|
88
88
|
'Lay the section out with a Container, a Stack or a Grid ("container": true, "spacing": 3) of Grid items sized like "xs:12 md:4", and size nothing with a fixed width. Colors come from the theme’s palette tokens such as primary.main, spacing from the spacing scale, and type from the text variants.',
|
|
89
89
|
'The page renders inside the site’s layout, so a section is never a header, navigation or footer.',
|
|
90
90
|
'A picture is an Image (image) with alt text that says what it should show and no src, for the site owner to fill from the media library.',
|
|
@@ -401,7 +401,8 @@ function isRecord(value) {
|
|
|
401
401
|
}, tree, tree.screenIds || ((_options_linkablePages1 = options.linkablePages) == null ? void 0 : _options_linkablePages1.length) ? {
|
|
402
402
|
screenIds
|
|
403
403
|
} : {}, {
|
|
404
|
-
homeScreenIds: aiHomeScreenIds(inventory)
|
|
404
|
+
homeScreenIds: aiHomeScreenIds(inventory),
|
|
405
|
+
homeLabels: aiHomeScreenNames(inventory)
|
|
405
406
|
}, options.reusableComponents === false ? {
|
|
406
407
|
reusableComponents: false
|
|
407
408
|
} : {}, ((_options_sections = options.sections) == null ? void 0 : _options_sections.length) ? {
|