@aglyn/plugins-ai 1.0.0-beta.263 → 1.0.0-beta.264

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/package.json +17 -17
  2. package/src/lib/jobs/ai-job-page-sections.js +8 -2
  3. package/src/lib/jobs/ai-job-page-sections.js.map +1 -1
  4. package/src/lib/jobs/ai-job-site-datasets.d.ts +11 -1
  5. package/src/lib/jobs/ai-job-site-datasets.js +32 -7
  6. package/src/lib/jobs/ai-job-site-datasets.js.map +1 -1
  7. package/src/lib/jobs/ai-layout-stock-photos.d.ts +91 -11
  8. package/src/lib/jobs/ai-layout-stock-photos.js +1046 -48
  9. package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -1
  10. package/src/lib/jobs/fixtures/ai-stock-photo-juniper-records-recordings.d.ts +23 -0
  11. package/src/lib/jobs/fixtures/ai-stock-photo-juniper-records-recordings.js +163 -0
  12. package/src/lib/jobs/fixtures/ai-stock-photo-juniper-records-recordings.js.map +1 -0
  13. package/src/lib/jobs/fixtures/ai-stock-photo-learning-center-recordings.d.ts +23 -0
  14. package/src/lib/jobs/fixtures/ai-stock-photo-learning-center-recordings.js +53 -0
  15. package/src/lib/jobs/fixtures/ai-stock-photo-learning-center-recordings.js.map +1 -0
  16. package/src/lib/jobs/fixtures/ai-stock-photo-synchronicity-recordings.d.ts +21 -0
  17. package/src/lib/jobs/fixtures/ai-stock-photo-synchronicity-recordings.js +119 -0
  18. package/src/lib/jobs/fixtures/ai-stock-photo-synchronicity-recordings.js.map +1 -0
  19. package/src/lib/layout-language/ai-layout-compiler.js +6 -4
  20. package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
  21. package/src/lib/layout-language/ai-layout-listings.d.ts +7 -0
  22. package/src/lib/layout-language/ai-layout-listings.js +12 -0
  23. package/src/lib/layout-language/ai-layout-listings.js.map +1 -1
  24. package/src/lib/layout-language/ai-layout-pictures.d.ts +27 -8
  25. package/src/lib/layout-language/ai-layout-pictures.js +85 -4
  26. package/src/lib/layout-language/ai-layout-pictures.js.map +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-job-site-datasets.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 { checkDatasetQuota } from '@aglyn/aglyn/app-utils/plan-entitlements'\nimport { pluginResourceDraftWriter } from '@aglyn/aglyn/plugin-manager/plugin-resource-drafts'\nimport { isAiPlanNewRef, type AiBuildPlanCreate, type AiBuildPlanScreen } from '../model/ai-build-plan'\nimport type { AiJob, AiJobOutput, AiJobPlan } from '../model/ai-jobs.types'\nimport type { AiPlanCapabilities } from '../model/ai-plan-capabilities'\nimport { AI_SITE_DATASETS_MAX } from '../model/ai-site-job'\nimport { AI_STEP_TIERS } from '../providers/catalog'\nimport { aiModelForStep } from '../providers/routing'\nimport {\n AI_DATASET_MAX_TOKENS,\n AI_DATASET_STEP,\n aiDatasetDraftContent,\n generateAiDataset,\n} from '../runtime/ai-dataset-generation'\nimport {\n aiLayoutListingId,\n aiLayoutRecordBaseOf,\n aiLayoutRecordsPlacements,\n type AiLayoutListing,\n type AiLayoutListingField,\n type AiLayoutListingScreen,\n} from '../layout-language/ai-layout-listings'\nimport {\n aiLayoutStarterPhotos,\n type AiLayoutPicturePhoto,\n type AiLayoutPictureSlot,\n} from '../layout-language/ai-layout-pictures'\nimport { aiSiteWords } from '../model/ai-site-job'\nimport type { AiJobAdmissionContext } from './ai-job-admission'\nimport { aiOriginJobId } from './ai-job-draft-ids'\nimport { aiSiteProductPhotoSrc } from './ai-job-site-content'\nimport { aiLayoutStockPhotoSource, aiStockPhotoWordsOf } from './ai-layout-stock-photos'\nimport { AI_DATASET_DRAFT_RESOURCE } from './ai-build-unit-outcome'\nimport { aiJobStepBudget } from './ai-job-budget'\nimport { aiGenerationSpent, aiUnspentOutcome } from './ai-job-generation'\nimport { aiPluginDraftAdmissionRefusal } from './ai-job-plugin-drafts'\nimport type { AiJobStepContext, AiJobStepOutcome, AiJobStepRunner } from './ai-job-text-step'\n\n/**\n * A SITE START'S DATASETS (AGL-3616): \"Aglyn AI can also use/create datasets\n * too for whatever it needs\" (Zach, 2026-10-10).\n *\n * A site whose content is a list of like things — a restaurant's menu, a\n * studio's team, a contractor's services, a photographer's portfolio, an\n * events list, its questions and answers — keeps it as a DATASET, the way the\n * docs teach a person to: the owner edits one record and every page listing\n * it follows. On a workspace that may create datasets, the site plan creates\n * one for such content (`create`, kind `dataset`) and names it in the `uses`\n * of each section that lists it. The scaffold then builds each dataset as a\n * unit of its own, after the layout and before the form (which may write\n * its submissions to one) and the pages:\n *\n * - DESIGNED by the `submit_dataset` generation (`ai-dataset-generation.ts`):\n * the planned fields typed, at most a few more, and 3 to 12 records seeded\n * from the brief. Nothing anybody did not say: no review, testimonial,\n * rating, quote or person's name, no price the brief does not state.\n * - WRITTEN by the data plugin's `dataset` writer — this plugin never names\n * the datasets collection — with every rule the console's datasets route\n * has: the member's role and `data.manage`, `release_data_store`,\n * `dataStore` (Starter and up), `datasetsPerOrg` counted inside the create,\n * `recordsPerDataset` and the storage band.\n * - PICTURED where the plan lists it the way a gallery is listed (Zach,\n * 2026-10-10: a ceramic artist's \"Selected work\" came back as text-only\n * cards, where it had been an image-led gallery): a portfolio's pieces, a\n * team, a menu, classes and events, and services or offerings whose\n * section says it shows them in pictures (`aiSiteDatasetPicturesOf`). Such\n * a dataset gets an Image field, and each record a stock photo of its own\n * name in the site's craft, copied into the site's library — never one the\n * job already placed, else a starter photo — searched in code, so it\n * costs no credits (`aiSiteDatasetRecordPhotos`).\n * - LISTED by the pages built after it: each section naming it repeats over\n * the dataset (`aiSiteDatasetListings`, a `records` listing the layout\n * compiler draws, its card led by the record's photo where it has one),\n * and a page the plan made its record template binds its fields by id,\n * its photo the record's, and keeps the address field the writer added.\n *\n * Where datasets cannot be created — the Free taste, Starter's two used up,\n * the data store not released — the plan is told so and creates none, so its\n * sections write the items out. A dataset unit that fails or is refused\n * leaves the pages that list it built without it (they say so), and its\n * record page is not built.\n */\n\n/** The most datasets one site start creates. */\nexport { AI_SITE_DATASETS_MAX } from '../model/ai-site-job'\n\n/** The resource the data plugin's writer is registered under. */\nexport const AI_SITE_DATASET_RESOURCE = AI_DATASET_DRAFT_RESOURCE\n\n/** What the site's plugin list calls the plugin, for \"Turn on Data for this site\". */\nconst DATA_PLUGIN_LABEL = 'Data'\n\n/** The input a dataset unit's own job carries what it needs in. */\nexport const AI_SITE_DATASET_INPUT = 'siteDataset'\n\n/** What a dataset unit's job is told beside its creation. */\nexport interface AiSiteDatasetInput {\n /** The sections that list it, by page: \"Menu › Our dishes (12 items)\". */\n shownIn: string[]\n /** Whether a page of the plan is its record template. */\n recordPages: boolean\n /**\n * The form of the plan that writes its submissions to it (AGL-3616), by\n * name, with that form's planned fields; absent where no form does.\n */\n forForm?: { name: string; fields: string[] }\n /**\n * Whether its records carry a photo, and of what (AGL-3616): `things` for a\n * portfolio's pieces, a menu, classes; `people` for a team. Absent for a\n * list a visitor reads rather than looks at: questions, steps, hours.\n */\n pictures?: AiSiteDatasetPictures\n}\n\n/** What a dataset's records are pictured as: things or people. */\nexport type AiSiteDatasetPictures = 'things' | 'people'\n\n/** A list of questions, voices or plain facts: read, never pictured. */\nconst READ_ONLY_LIST =\n /\\b(faqs?|questions?|q ?& ?a|answers?|testimonials?|reviews?|quotes?|voices|hours|opening|steps?|process|policies|policy|terms|stats?|numbers|figures|milestones|timeline|values|benefits|reasons|features|requirements|checklist|ingredients|donations?|needs|partners|sponsors|supporters|roles|positions|jobs|openings)\\b/i\n/** A list of people: its photos are of the business's people. */\nconst PEOPLE_LIST =\n /\\b(team|staff|people|crew|instructors?|teachers?|tutors?|stylists?|barbers?|therapists?|coaches?|trainers?|chefs?|doctors?|dentists?|hygienists?|practitioners?|artists?|musicians?|performers?|speakers?|founders?|members?)\\b/i\n/** A list a visitor looks at before reading: pictured wherever it is listed. */\nconst PICTURED_LIST =\n /\\b(portfolio|pieces?|works?|projects?|gallery|galleries|collections?|series|menus?|dishes|plates|drinks|cocktails|wines?|beers?|coffees?|pastries|cakes|products?|items|events?|classes|class|workshops?|courses?|retreats?|tours?|trips?|adventures?|experiences?|rooms?|suites?|cabins?|properties|listings|homes|venues?|spaces?|recipes?|artworks?|paintings?|prints?|photos?|photographs?|designs?|commissions?|builds?|vehicles?|animals?|pets?|plants?|flowers?|bouquets?|arrangements?|case studies)\\b/i\n/** A section that says it shows its items in pictures: a gallery, a grid of photos, tiles. */\nconst PICTURED_SECTION =\n /\\b(gallery|galleries|grid|images?|photos?|photographs?|pictures?|lightbox|portfolio|showcase|tiles?|visuals?|lookbook|carousel|slideshow|mosaic|thumbnails?)\\b/i\n\n/**\n * Whether a dataset's records carry a photo, read off the plan (AGL-3616):\n * its name and the names of the sections that list it. Questions, voices and\n * plain facts never; people as people; a list a visitor looks at — pieces,\n * dishes, classes, events, rooms — always; any other list (services,\n * offerings, programs) only where a section that lists it says it shows them\n * in pictures, or names one of those. A dataset no page lists is not\n * pictured. Pure.\n */\nexport function aiSiteDatasetPicturesOf(\n dataset: Pick<AiBuildPlanCreate, 'name'>,\n sections: readonly string[],\n): AiSiteDatasetPictures | null {\n if (!sections.length) return null\n const own = dataset.name\n if (READ_ONLY_LIST.test(own)) return null\n if (PEOPLE_LIST.test(own)) return 'people'\n if (PICTURED_LIST.test(own)) return 'things'\n if (sections.some((section) => READ_ONLY_LIST.test(section) && !PICTURED_SECTION.test(section))) return null\n if (sections.some((section) => PEOPLE_LIST.test(section))) return 'people'\n if (sections.some((section) => PICTURED_LIST.test(section) || PICTURED_SECTION.test(section))) return 'things'\n return null\n}\n\n/** What a dataset row says when its design could not be written: our failure, refunded. */\nexport const AI_SITE_DATASET_NOT_WRITTEN_COPY = 'This dataset could not be added this time.'\n\n/** The note a written dataset carries on the job's page. */\nexport function aiSiteDatasetNote(records: number): string {\n return `${records} ${records === 1 ? 'record' : 'records'} to start, in Data. Edit them there and every page that lists them follows.`\n}\n\n/** The note a record template's row adds: the binding is the member's to save (rule 13). */\nexport const AI_SITE_RECORD_PAGE_NOTE =\n 'A page per record is drafted, not live: open Page Properties → Record pages to save it.'\n\n/** ASSUMED: what one dataset pass reads and writes beside its generation: the site, the writer's reads and its transaction. */\nexport const AI_SITE_DATASET_WRITES_MS = 2_000\n\n/** One dataset's pass: its generation and re-ask at its ceiling, and its writes. */\nexport const AI_SITE_DATASET_BUDGET = aiJobStepBudget({\n tier: AI_STEP_TIERS[AI_DATASET_STEP],\n maxTokens: AI_DATASET_MAX_TOKENS,\n lookups: 0,\n ownReadsMs: AI_SITE_DATASET_WRITES_MS,\n})\n\nconst str = (value: unknown): string => (typeof value === 'string' ? value.trim() : '')\n\n/** The plan's reference to a dataset as a section names it: `new:<name>`, compared lowercased. */\nfunction namesDataset(ref: string, name: string): boolean {\n return isAiPlanNewRef(ref) && ref.slice(ref.indexOf(':') + 1).trim().toLowerCase() === name.trim().toLowerCase()\n}\n\n/** The plan's datasets, in plan order, at most the most a start creates. */\nexport function aiSitePlanDatasets(plan: Pick<AiJobPlan, 'create'>): AiBuildPlanCreate[] {\n return plan.create.filter((entry) => entry.kind === 'dataset').slice(0, AI_SITE_DATASETS_MAX)\n}\n\n/** Where the plan lists a dataset, in words its design reads, whether a page is its record template, and the form that writes to it. */\nexport function aiSiteDatasetInputOf(\n dataset: Pick<AiBuildPlanCreate, 'name'>,\n screens: readonly AiBuildPlanScreen[],\n create: readonly AiBuildPlanCreate[] = [],\n): AiSiteDatasetInput {\n const shownIn: string[] = []\n const sectionNames: string[] = []\n for (const screen of screens) {\n for (const section of screen.sections) {\n if (!section.uses.some((ref) => namesDataset(ref, dataset.name))) continue\n shownIn.push(`${screen.title} › ${section.name}${section.items ? ` (${section.items} items)` : ''}`)\n sectionNames.push(section.name)\n }\n }\n const recordPages = screens.some((screen) => !!screen.record && namesDataset(screen.record.dataset, dataset.name))\n const form = create.find((entry) => entry.kind === 'form' && !!entry.writesTo && namesDataset(entry.writesTo, dataset.name))\n // A form's dataset holds its submissions: nobody's photo.\n const pictures = form ? null : aiSiteDatasetPicturesOf(dataset, sectionNames)\n return {\n shownIn: shownIn.slice(0, 8),\n recordPages,\n ...(form ? { forForm: { name: form.name, fields: form.fields.slice(0, AI_SITE_FORM_DATASET_FIELDS_MAX) } } : {}),\n ...(pictures ? { pictures } : {}),\n }\n}\n\n/** Whether a plan screen is the record template of a dataset the plan creates, and which. */\nexport function aiSiteRecordTemplateOf(screen: Pick<AiBuildPlanScreen, 'record'>): string | null {\n const ref = screen.record?.dataset\n return ref && isAiPlanNewRef(ref) ? ref.slice(ref.indexOf(':') + 1).trim() : null\n}\n\nfunction datasetInputOf(job: Pick<AiJob, 'inputs'>): AiSiteDatasetInput {\n const raw = (job.inputs?.[AI_SITE_DATASET_INPUT] ?? {}) as Partial<AiSiteDatasetInput>\n const form = raw.forForm && typeof raw.forForm === 'object' ? raw.forForm : null\n return {\n shownIn: Array.isArray(raw.shownIn) ? raw.shownIn.map(str).filter(Boolean).slice(0, 8) : [],\n recordPages: raw.recordPages === true,\n ...(form && str(form.name)\n ? {\n forForm: {\n name: str(form.name),\n fields: Array.isArray(form.fields) ? form.fields.map(str).filter(Boolean).slice(0, AI_SITE_FORM_DATASET_FIELDS_MAX) : [],\n },\n }\n : {}),\n ...(raw.pictures === 'things' || raw.pictures === 'people' ? { pictures: raw.pictures } : {}),\n }\n}\n\n/** The most fields a form's dataset is designed with: the data plugin writer's own ceiling is higher. */\nexport const AI_SITE_FORM_DATASET_FIELDS_MAX = 12\n\n/** The field types a planned `Name:type` may name, as the data plugin's writer takes them. */\nconst FORM_DATASET_FIELD_TYPES = ['text', 'number', 'integer', 'boolean', 'list'] as const\n\n/** A planned field as a person reads it: `fullName` and `full_name` are \"Full name\", `fechaDeÚltimaVisita` \"Fecha de última visita\". */\nexport function aiSiteDatasetFieldName(planned: string): string {\n const words = planned\n .replace(/([\\p{Ll}\\p{N}])(\\p{Lu})/gu, '$1 $2')\n .replace(/[_-]+/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim()\n return words ? words.charAt(0).toUpperCase() + words.slice(1).toLowerCase() : ''\n}\n\n/**\n * A dataset a form writes to, as the data plugin's writer takes it\n * (AGL-3616): designed with no model, since its records are the\n * submissions. Its fields are its planned ones — or, where the plan gave it\n * none, the form's — each a person's words for it, text unless the plan\n * typed it as `Name:type`, never required, so a submission that leaves one\n * blank is still a record. It starts with no records. Pure.\n */\nexport function aiSiteFormDatasetContent(\n name: string,\n planned: readonly string[],\n form: { fields: readonly string[] },\n): Record<string, unknown> {\n const specs = (planned.length ? planned : form.fields).slice(0, AI_SITE_FORM_DATASET_FIELDS_MAX)\n const seen = new Set<string>()\n const fields: Array<{ name: string; type: string }> = []\n for (const spec of specs) {\n const at = spec.lastIndexOf(':')\n const typed = at > 0 ? spec.slice(at + 1).trim().toLowerCase() : ''\n const type = (FORM_DATASET_FIELD_TYPES as readonly string[]).includes(typed) ? typed : 'text'\n const fieldName = aiSiteDatasetFieldName(type === typed ? spec.slice(0, at) : spec).slice(0, 60)\n if (!fieldName || seen.has(fieldName.toLowerCase())) continue\n seen.add(fieldName.toLowerCase())\n fields.push({ name: fieldName, type })\n }\n return { name, fields, records: [] }\n}\n\n/** The note a form's dataset carries on the job's page. */\nexport function aiSiteFormDatasetNote(form: string): string {\n return `Empty to start: each submission of the form “${form}” is added here, in Data.`\n}\n\nconst limitReview = (message: string) => ({ reason: 'limit' as const, message, findings: [] })\n\n/** The wall clock a dataset's photos may take inside its pass: the 20 seconds a page's pictures had (AGL-3660). */\nexport const AI_SITE_DATASET_PHOTOS_BUDGET_MS = 20_000\n\n/** The field a pictured dataset's photo is kept in, where the plan gave it none. */\nexport const AI_SITE_DATASET_IMAGE_FIELD = 'Image'\n\n/** A planned field that already names a record's photo. */\nconst IMAGE_FIELD_NAME =\n /^(?:main |cover |hero |featured? )?(?:image|photo|picture|photograph|thumbnail|headshot|portrait|cover)s?$/i\n\n/** One record's photo: the address its Image shows, and the library asset placed, which no page shows again. */\nexport interface AiSiteDatasetRecordPhoto {\n /** The media library's CDN path, or a starter's site path; `null` for none. */\n src: string | null\n /** The `media:` reference of the stock photo placed, or `null` for a starter. */\n placed: string | null\n}\n\n/**\n * A photo for each record of a pictured dataset (AGL-3616), in order: a stock\n * photo of the record's own name, in the site's craft (\"ceramic speckled\n * serving bowl\"), copied into the site's library, where the deployment has a\n * stock library — never twice in the dataset nor one another part of the job\n * placed, inside {@link AI_SITE_DATASET_PHOTOS_BUDGET_MS} — else a starter\n * photo, as a page's empty picture takes one. A team is searched as the\n * business's people. The photo is kept as the asset's CDN path, the form a\n * product keeps (`aiSiteProductPhotoSrc`), so a replace in the library still\n * reaches it. No AI model is asked, so no credits; never throws.\n */\nexport async function aiSiteDatasetRecordPhotos(input: {\n job: Pick<AiJob, '$id' | 'hostId' | 'createdBy' | 'inputs' | 'brief' | 'plan'>\n /** The dataset, as the plan named it. */\n name: string\n /** Each record's name, by position. */\n names: readonly string[]\n pictures: AiSiteDatasetPictures\n signal?: AbortSignal\n stockPhotos?: typeof aiLayoutStockPhotoSource\n}): Promise<AiSiteDatasetRecordPhoto[]> {\n const { job } = input\n if (!input.names.length || !job.hostId) return input.names.map(() => ({ src: null, placed: null }))\n const people = input.pictures === 'people'\n const slots: AiLayoutPictureSlot[] = input.names.map((name, index) => ({\n imageId: `record${index}`,\n frameId: null,\n iconId: null,\n alt: name.trim() || input.name,\n // The record card's own shape: a team's portraits stand, pieces sit wide.\n aspect: people ? 4 / 5 : 4 / 3,\n sectionIndex: 0,\n role: people ? ('about' as const) : ('gallery' as const),\n }))\n const seed = `${job.$id}:records`\n let found: ReadonlyArray<AiLayoutPicturePhoto | null> = []\n try {\n const source = (input.stockPhotos ?? aiLayoutStockPhotoSource)(\n {\n hostId: job.hostId,\n uid: job.createdBy,\n seed,\n business: aiSiteWords(job.inputs).about || job.brief,\n ...aiStockPhotoWordsOf(job),\n sectionNames: [input.name],\n jobId: aiOriginJobId(job),\n // Each record may try its name, its object and the site's world.\n searches: slots.length * 3,\n ...(input.signal ? { signal: input.signal } : {}),\n },\n { budgetMs: AI_SITE_DATASET_PHOTOS_BUDGET_MS },\n )\n if (source) found = await source(slots)\n } catch (error) {\n console.warn('ai site dataset: the stock photos failed; starter photos fill them', { error: String(error) })\n }\n const starters = aiLayoutStarterPhotos(slots, seed)\n const hostId = job.hostId\n return slots.map((_slot, index) => {\n const stock = aiSiteProductPhotoSrc(found[index]?.src, hostId)\n if (stock) return { src: stock, placed: found[index]?.src ?? null }\n return { src: aiSiteProductPhotoSrc(starters[index]?.src, hostId), placed: null }\n })\n}\n\n/**\n * A designed dataset's content with its records' photos (AGL-3616): the\n * planned field that names a photo (\"Image\", \"Photo\") becomes the data\n * plugin's `image` field, else one called \"Image\" is added after the others,\n * and each record holds its photo there; a record with none holds nothing.\n * Pure.\n */\nexport function aiSiteDatasetContentWithPhotos(\n content: Record<string, unknown>,\n photos: ReadonlyArray<string | null>,\n): Record<string, unknown> {\n const fields = (Array.isArray(content['fields']) ? content['fields'] : []) as Array<{ name: string; type?: string }>\n const named = fields.find((field) => IMAGE_FIELD_NAME.test(str(field.name)))\n const fieldName = named ? named.name : AI_SITE_DATASET_IMAGE_FIELD\n const nextFields = named\n ? fields.map((field) => (field === named ? { ...field, type: 'image' } : field))\n : [...fields, { name: AI_SITE_DATASET_IMAGE_FIELD, type: 'image' }]\n const records = (Array.isArray(content['records']) ? content['records'] : []) as Array<Record<string, unknown>>\n return {\n ...content,\n fields: nextFields,\n records: records.map((record, index) => {\n const next = { ...record }\n delete next[fieldName]\n const photo = photos[index]\n return photo ? { ...next, [fieldName]: photo } : next\n }),\n }\n}\n\nexport interface AiSiteDatasetRunnerDeps {\n generate?: typeof generateAiDataset\n writerFor?: typeof pluginResourceDraftWriter\n /** Where a pictured dataset's photos come from; the stock library, else the starters, otherwise. */\n photos?: typeof aiSiteDatasetRecordPhotos\n}\n\n/** The fields and record names a written dataset reports, as its output's proposal keeps them. */\ninterface AiSiteDatasetProposal {\n fields: AiLayoutListingField[]\n /** Each record's name: its first field's value. */\n recordNames: string[]\n addressField: string | null\n /** The field each record's photo is in, where it has one (AGL-3616). */\n imageField?: string | null\n /** The library photos its records show (`media:` references), which no page places again. */\n photos?: string[]\n /**\n * The fields most of its first records leave empty, by id (AGL-3616): a\n * tour's venues not yet known. A card never binds one — it would print\n * nothing on most records — so its listing leaves them out.\n */\n sparseFields?: string[]\n}\n\n/**\n * The fields of a designed dataset that its records leave empty on most of\n * them — every record, or more than half — by the id the data plugin gave\n * each (AGL-3616). Its first field is the record's name and is never one. The\n * live low-tide-hollow start (beta.239) seeded its tour dates with no venue,\n * rightly inventing none, and its cards bound the venue as their eyebrow.\n */\nexport function aiDatasetSparseFields(\n dataset: { fields: ReadonlyArray<{ name: string }>; records: ReadonlyArray<ReadonlyArray<string | undefined>> },\n written: readonly AiLayoutListingField[],\n): string[] {\n if (!dataset.records.length) return []\n const idOf = (name: string, column: number) =>\n written.find((field) => field.name.trim().toLowerCase() === name.trim().toLowerCase())?.id ?? written[column]?.id ?? null\n return dataset.fields.flatMap((field, column) => {\n if (column === 0) return []\n const filled = dataset.records.filter((values) => (values[column] ?? '').trim()).length\n const id = idOf(field.name, column)\n return id && filled * 2 <= dataset.records.length ? [id] : []\n })\n}\n\nfunction proposalOf(output: Pick<AiJobOutput, 'proposal'>): AiSiteDatasetProposal {\n const raw = (output.proposal ?? {}) as Partial<AiSiteDatasetProposal>\n return {\n fields: Array.isArray(raw.fields)\n ? raw.fields.filter((field) => field && typeof field.id === 'string' && field.id).map((field) => ({ id: field.id, name: str(field.name) || field.id, type: str(field.type) || 'text' }))\n : [],\n recordNames: Array.isArray(raw.recordNames) ? raw.recordNames.map(str).filter(Boolean).slice(0, 12) : [],\n addressField: str(raw.addressField) || null,\n imageField: str(raw.imageField) || null,\n photos: Array.isArray(raw.photos) ? raw.photos.map(str).filter((src) => src.startsWith('media:')).slice(0, 24) : [],\n sparseFields: Array.isArray(raw.sparseFields) ? raw.sparseFields.map(str).filter(Boolean) : [],\n }\n}\n\n/**\n * The dataset unit's runner, on the job the scaffold derived for it: the one\n * creation its plan carries, designed by the model and written by the data\n * plugin, under the creation's own id. A pass repeated after its write finds\n * the dataset the writer wrote and reports it again, spending nothing.\n */\nexport function createAiSiteDatasetRunner(deps: AiSiteDatasetRunnerDeps = {}): AiJobStepRunner {\n const generate = deps.generate ?? generateAiDataset\n const writerFor = deps.writerFor ?? pluginResourceDraftWriter\n const photosFor = deps.photos ?? aiSiteDatasetRecordPhotos\n return async (context): Promise<AiJobStepOutcome> => {\n const { job, firestore, signal } = context\n const model = context.modelFor?.(AI_DATASET_STEP) ?? aiModelForStep(AI_DATASET_STEP)\n const creation = (job.plan as AiJobPlan | null)?.create?.find((entry) => entry.kind === 'dataset')\n const keeper = writerFor(AI_SITE_DATASET_RESOURCE)\n if (!job.hostId || !creation) return { ...aiUnspentOutcome(model), failure: 'Open the site before adding its data.' }\n if (!keeper) return { ...aiUnspentOutcome(model), failure: 'Datasets are not available on this site.' }\n const host = await firestore.collection('hosts').doc(job.hostId).get()\n const hostSubdomain = str(host.get('subdomain')) || null\n const output = (id: string, name: string, proposal: AiSiteDatasetProposal, records: number): AiJobOutput => ({\n resource: 'draft',\n draftResource: AI_SITE_DATASET_RESOURCE,\n id,\n hostId: job.hostId ?? null,\n hostSubdomain,\n label: name,\n note: aiSiteDatasetNote(records),\n proposal: proposal as unknown as Record<string, unknown>,\n })\n const input = datasetInputOf(job)\n // Asked again under the same id: the dataset already written.\n const written = await keeper.writer.read({ hostId: job.hostId, id: job.$id })\n if (written) {\n const facts = written.facts as { fields?: AiLayoutListingField[]; addressField?: string | null; imageField?: string | null }\n const again = output(\n written.id,\n written.name || creation.name,\n { fields: facts.fields ?? [], recordNames: [], addressField: facts.addressField ?? null, imageField: facts.imageField ?? null },\n 0,\n )\n return aiUnspentOutcome(model, {\n outputs: [input.forForm ? { ...again, note: aiSiteFormDatasetNote(input.forForm.name) } : again],\n })\n }\n // A form's dataset (AGL-3616): its records are the submissions, so it is\n // designed from the plan with no model, and starts empty.\n if (input.forForm) {\n const content = aiSiteFormDatasetContent(creation.name, creation.fields, input.forForm)\n const checked = keeper.writer.check(content, { hostId: job.hostId })\n if (checked.ok === false) {\n console.error('ai site dataset: the dataset writer refused a form dataset we made', { orgId: job.orgId, jobId: job.$id, problems: checked.problems })\n return { ...aiUnspentOutcome(model), failure: AI_SITE_DATASET_NOT_WRITTEN_COPY }\n }\n const result = await keeper.writer.write({\n orgId: job.orgId,\n hostId: job.hostId,\n uid: job.createdBy,\n org: (context.org ?? null) as Readonly<Record<string, unknown>> | null,\n now: context.now,\n id: job.$id,\n name: creation.name,\n content,\n })\n if (result.ok === false) {\n if (result.status === 400) return { ...aiUnspentOutcome(model), failure: AI_SITE_DATASET_NOT_WRITTEN_COPY }\n return { ...aiUnspentOutcome(model), review: limitReview(result.error) }\n }\n const facts = result.facts as { fields?: AiLayoutListingField[]; addressField?: string | null }\n return aiUnspentOutcome(model, {\n outputs: [\n {\n ...output(result.id, result.name, { fields: facts.fields ?? [], recordNames: [], addressField: null }, 0),\n note: aiSiteFormDatasetNote(input.forForm.name),\n },\n ],\n })\n }\n const generation = await generate({\n brief: job.brief,\n merchantWords: job.brief,\n name: creation.name,\n why: creation.why,\n fields: creation.fields,\n shownIn: input.shownIn,\n recordPages: input.recordPages,\n model,\n maxTokens: AI_SITE_DATASET_BUDGET.maxTokens(model),\n ...(signal ? { signal } : {}),\n })\n const spent = aiGenerationSpent(generation)\n if (generation.status === 'refused') return { ...spent, refused: true }\n if (generation.status === 'needs_input') return { ...spent, failure: generation.message }\n const designed = aiDatasetDraftContent(creation.name, generation.value, { recordPages: input.recordPages })\n // A list a visitor looks at keeps its records' photos (AGL-3616): searched\n // in code, never asked of the model, so they cost no credits.\n const photos = input.pictures\n ? await photosFor({\n job,\n name: creation.name,\n names: generation.value.records.map((values) => values[0] ?? ''),\n pictures: input.pictures,\n ...(signal ? { signal } : {}),\n }).catch(() => [] as AiSiteDatasetRecordPhoto[])\n : []\n const content = input.pictures\n ? aiSiteDatasetContentWithPhotos(designed, generation.value.records.map((_values, index) => photos[index]?.src ?? null))\n : designed\n // The data plugin's own rules, before anything is written: content we\n // made that its model refuses is our failure, refunded.\n const checked = keeper.writer.check(content, { hostId: job.hostId })\n if (checked.ok === false) {\n console.error('ai site dataset: the dataset writer refused a dataset we made', { orgId: job.orgId, jobId: job.$id, problems: checked.problems })\n return { ...spent, failure: AI_SITE_DATASET_NOT_WRITTEN_COPY }\n }\n const result = await keeper.writer.write({\n orgId: job.orgId,\n hostId: job.hostId,\n uid: job.createdBy,\n org: (context.org ?? null) as Readonly<Record<string, unknown>> | null,\n now: context.now,\n id: job.$id,\n name: creation.name,\n content,\n })\n if (result.ok === false) {\n if (result.status === 400) return { ...spent, failure: AI_SITE_DATASET_NOT_WRITTEN_COPY }\n // The allowance, the role, the plan or the flag: the workspace's to change.\n return { ...spent, review: limitReview(result.error) }\n }\n const facts = result.facts as {\n fields?: AiLayoutListingField[]\n records?: number\n addressField?: string | null\n imageField?: string | null\n }\n const placed = photos.flatMap((photo) => (photo.placed ? [photo.placed] : []))\n const proposal: AiSiteDatasetProposal = {\n fields: facts.fields ?? [],\n recordNames: generation.value.records.map((values) => values[0] ?? '').filter(Boolean).slice(0, 12),\n addressField: facts.addressField ?? null,\n ...(facts.imageField ? { imageField: facts.imageField } : {}),\n ...(placed.length ? { photos: placed } : {}),\n sparseFields: aiDatasetSparseFields(generation.value, facts.fields ?? []),\n }\n return { ...spent, outputs: [output(result.id, result.name, proposal, facts.records ?? generation.value.records.length)] }\n }\n}\n\nexport const runAiSiteDatasetUnit = createAiSiteDatasetRunner()\n\n/**\n * Whether a dataset may be created for this member on this site, asked before\n * its first pass so a refusal spends nothing; `null` admits. The data plugin\n * must run here (on for the workspace and the site, past its release flag),\n * and its writer says whether this member may make one now: the role, the\n * plan, the flag, the allowance.\n */\nexport async function aiSiteDatasetRefusal(\n context: Pick<AiJobStepContext, 'firestore' | 'org' | 'now'> & { job: Pick<AiJob, 'orgId' | 'hostId' | 'createdBy'> },\n deps: { admission?: typeof aiPluginDraftAdmissionRefusal; writerFor?: (resource: string) => ReturnType<typeof pluginResourceDraftWriter> } = {},\n): Promise<string | null> {\n const { job } = context\n if (!job.hostId) return 'Open the site first.'\n const writerFor = deps.writerFor ?? pluginResourceDraftWriter\n const admission: AiJobAdmissionContext = {\n firestore: context.firestore,\n orgId: job.orgId,\n hostId: job.hostId,\n inputs: {},\n org: context.org ?? null,\n uid: job.createdBy,\n }\n const refused = await (deps.admission ?? aiPluginDraftAdmissionRefusal)(admission, {\n kind: 'site',\n drafts: [{ resource: AI_SITE_DATASET_RESOURCE, label: DATA_PLUGIN_LABEL }],\n writerFor: (resource) => writerFor(resource)?.writer ?? null,\n ownerFor: (resource) => writerFor(resource)?.pluginId ?? null,\n now: context.now,\n })\n return refused?.error ?? null\n}\n\n/**\n * A site plan's dataset capability on this workspace (AGL-3616): where the\n * workspace's plan includes datasets, whether the data plugin runs here and\n * this member may create one now, and how many a start may make. A clause the\n * plan's turn completes is the reason where it may not.\n */\nexport async function aiSitePlanDatasetCapability(\n capabilities: AiPlanCapabilities,\n context: Parameters<typeof aiSiteDatasetRefusal>[0],\n deps: Parameters<typeof aiSiteDatasetRefusal>[1] = {},\n): Promise<AiPlanCapabilities> {\n if (!capabilities.create.dataset.allowed) return capabilities\n const refusal = await aiSiteDatasetRefusal(context, deps).catch((error: unknown) => {\n console.error('ai site plan: the dataset admission failed', { orgId: context.job.orgId, error })\n return 'datasets could not be checked just now'\n })\n const left = Math.min(AI_SITE_DATASETS_MAX, checkDatasetQuota(context.org as never, 0).limit)\n const dataset = refusal\n ? { allowed: false, left: 0, reason: `datasets cannot be created here: ${refusal.replace(/\\.$/, '')}` }\n : { allowed: true, left, reason: null }\n return { ...capabilities, create: { ...capabilities.create, dataset } }\n}\n\n/**\n * A `records` listing for each dataset that was made and that a section of the\n * plan names (AGL-3616). Its fields, where none are given, are read off the\n * site's inventory when the page is designed (`aiLayoutListingsWithDatasets`).\n */\nexport function aiDatasetListingsOf(\n datasets: ReadonlyArray<{\n id: string\n name: string\n records?: string[]\n fields?: AiLayoutListingField[]\n imageField?: string | null\n /** The record's page-address field, where the writer added one (AGL-3727). */\n addressField?: string | null\n }>,\n screens: readonly AiLayoutListingScreen[],\n): AiLayoutListing[] {\n return datasets.flatMap((dataset) => {\n const placements = aiLayoutRecordsPlacements(dataset, screens)\n if (!placements.length) return []\n // Each card links its record's own page where the plan makes one (AGL-3727).\n const recordBase = aiLayoutRecordBaseOf(dataset, screens)\n return [\n {\n id: aiLayoutListingId('records', dataset.id),\n kind: 'records' as const,\n name: dataset.name,\n records: dataset.records ?? [],\n datasetId: dataset.id,\n ...(dataset.fields?.length ? { fields: dataset.fields } : {}),\n // Its card leads with the record's photo (AGL-3616).\n ...(dataset.imageField ? { imageField: dataset.imageField } : {}),\n // The address is read off the site's inventory where the build does not know it yet.\n ...(recordBase ? { recordBase, ...(dataset.addressField ? { addressField: dataset.addressField } : {}) } : {}),\n placements,\n },\n ]\n })\n}\n\n/**\n * A `records` listing for each dataset the workspace already keeps that a\n * site start's plan reuses and a section names (AGL-3771), as a build lists\n * the ones it reuses (AGL-3747). A second site in a workspace reuses the\n * first one's menu: its plan names the dataset by id, the start listed only\n * the datasets it made, and the page was asked to \"place\" a dataset no block\n * can draw — the home's \"Del menú\" section was refused for showing none of\n * its six items, and the Menú page published with no menu. A dataset one of\n * the plan's forms writes into holds the site's submissions, and is never\n * listed on a page.\n */\nexport function aiSiteReusedDatasetListings(input: {\n plan: Pick<AiJobPlan, 'reuse' | 'create' | 'labels'>\n screens: readonly AiLayoutListingScreen[]\n /** The listings the start already has, whose datasets are not listed twice. */\n listed: ReadonlyArray<Pick<AiLayoutListing, 'datasetId'>>\n}): AiLayoutListing[] {\n const submissions = new Set(\n input.plan.create.flatMap((entry) => (entry.kind === 'form' && entry.writesTo && !isAiPlanNewRef(entry.writesTo) ? [entry.writesTo] : [])),\n )\n const listed = new Set(input.listed.map((listing) => listing.datasetId).filter(Boolean))\n const datasets = input.plan.reuse\n .filter((entry) => entry.kind === 'dataset' && !submissions.has(entry.id) && !listed.has(entry.id))\n .map((entry) => ({ id: entry.id, name: input.plan.labels?.[entry.id] || entry.id }))\n return aiDatasetListingsOf(datasets, input.screens)\n}\n\n/**\n * The site's datasets a layout or a page unit is handed (AGL-3616), each a\n * `records` listing with the sections of the plan's pages that name it, once\n * its unit wrote it. A dataset not yet written, or one that failed, lists\n * nowhere: the pages built without it write the items out.\n */\nexport function aiSiteDatasetListings(input: {\n outputs: readonly AiJobOutput[]\n datasets: ReadonlyArray<Pick<AiBuildPlanCreate, 'name'>>\n screens: readonly AiLayoutListingScreen[]\n /** The ids each dataset's unit delivered, by plan name lowercased. */\n delivered: ReadonlyMap<string, string>\n}): AiLayoutListing[] {\n const made = input.datasets.flatMap((dataset) => {\n const id = input.delivered.get(dataset.name.trim().toLowerCase())\n const output = id\n ? input.outputs.find((entry) => entry.resource === 'draft' && entry.draftResource === AI_SITE_DATASET_RESOURCE && entry.id === id)\n : undefined\n if (!id || !output) return []\n const proposal = proposalOf(output)\n return [\n {\n id,\n // Placed by the name the plan's sections gave it.\n name: dataset.name,\n records: proposal.recordNames,\n // The address field is the record page's, never a card's words; the\n // photo is the card's picture, never its words; a field most records\n // leave empty is no card's either (AGL-3616).\n fields: proposal.fields.filter(\n (field, index) =>\n field.id !== proposal.addressField &&\n field.id !== proposal.imageField &&\n (index === 0 || !proposal.sparseFields?.includes(field.id)),\n ),\n imageField: proposal.imageField ?? null,\n addressField: proposal.addressField,\n },\n ]\n })\n return aiDatasetListingsOf(made, input.screens)\n}\n\n/** The library photos the site's datasets' records show (AGL-3616), which a page does not place again. */\nexport function aiSiteDatasetPlacedPhotos(outputs: readonly AiJobOutput[]): string[] {\n return [\n ...new Set(\n outputs\n .filter((output) => output.resource === 'draft' && output.draftResource === AI_SITE_DATASET_RESOURCE)\n .flatMap((output) => proposalOf(output).photos ?? []),\n ),\n ]\n}\n\n/** What a page is told about the datasets built before it. */\nexport function aiSiteDatasetBriefLines(outputs: readonly AiJobOutput[]): string[] {\n const datasets = outputs.filter((output) => output.resource === 'draft' && output.draftResource === AI_SITE_DATASET_RESOURCE)\n return datasets.flatMap((output) => {\n const names = proposalOf(output).recordNames\n return names.length\n ? [`This site's dataset “${output.label}” holds: ${names.map((name) => `“${name}”`).join(', ')}. Where a page names one, name it as written; never name one that is not in this list.`]\n : []\n })\n}\n"],"names":["checkDatasetQuota","pluginResourceDraftWriter","isAiPlanNewRef","AI_SITE_DATASETS_MAX","AI_STEP_TIERS","aiModelForStep","AI_DATASET_MAX_TOKENS","AI_DATASET_STEP","aiDatasetDraftContent","generateAiDataset","aiLayoutListingId","aiLayoutRecordBaseOf","aiLayoutRecordsPlacements","aiLayoutStarterPhotos","aiSiteWords","aiOriginJobId","aiSiteProductPhotoSrc","aiLayoutStockPhotoSource","aiStockPhotoWordsOf","AI_DATASET_DRAFT_RESOURCE","aiJobStepBudget","aiGenerationSpent","aiUnspentOutcome","aiPluginDraftAdmissionRefusal","AI_SITE_DATASET_RESOURCE","DATA_PLUGIN_LABEL","AI_SITE_DATASET_INPUT","READ_ONLY_LIST","PEOPLE_LIST","PICTURED_LIST","PICTURED_SECTION","aiSiteDatasetPicturesOf","dataset","sections","length","own","name","test","some","section","AI_SITE_DATASET_NOT_WRITTEN_COPY","aiSiteDatasetNote","records","AI_SITE_RECORD_PAGE_NOTE","AI_SITE_DATASET_WRITES_MS","AI_SITE_DATASET_BUDGET","tier","maxTokens","lookups","ownReadsMs","str","value","trim","namesDataset","ref","slice","indexOf","toLowerCase","aiSitePlanDatasets","plan","create","filter","entry","kind","aiSiteDatasetInputOf","screens","shownIn","sectionNames","screen","uses","push","title","items","recordPages","record","form","find","writesTo","pictures","forForm","fields","AI_SITE_FORM_DATASET_FIELDS_MAX","aiSiteRecordTemplateOf","datasetInputOf","job","raw","inputs","Array","isArray","map","Boolean","FORM_DATASET_FIELD_TYPES","aiSiteDatasetFieldName","planned","words","replace","charAt","toUpperCase","aiSiteFormDatasetContent","specs","seen","Set","spec","at","lastIndexOf","typed","type","includes","fieldName","has","add","aiSiteFormDatasetNote","limitReview","message","reason","findings","AI_SITE_DATASET_PHOTOS_BUDGET_MS","AI_SITE_DATASET_IMAGE_FIELD","IMAGE_FIELD_NAME","aiSiteDatasetRecordPhotos","input","names","hostId","src","placed","people","slots","index","imageId","frameId","iconId","alt","aspect","sectionIndex","role","seed","$id","found","source","stockPhotos","uid","createdBy","business","about","brief","jobId","searches","signal","budgetMs","error","console","warn","String","starters","_slot","stock","aiSiteDatasetContentWithPhotos","content","photos","named","field","nextFields","next","photo","aiDatasetSparseFields","written","idOf","column","id","flatMap","filled","values","proposalOf","output","proposal","recordNames","addressField","imageField","startsWith","sparseFields","createAiSiteDatasetRunner","deps","generate","writerFor","photosFor","context","facts","firestore","model","modelFor","creation","keeper","failure","host","collection","doc","get","hostSubdomain","resource","draftResource","label","note","writer","read","again","outputs","checked","check","ok","orgId","problems","result","write","org","now","status","review","generation","merchantWords","why","spent","refused","designed","catch","_values","runAiSiteDatasetUnit","aiSiteDatasetRefusal","admission","drafts","ownerFor","pluginId","aiSitePlanDatasetCapability","capabilities","allowed","refusal","left","Math","min","limit","aiDatasetListingsOf","datasets","placements","recordBase","datasetId","aiSiteReusedDatasetListings","submissions","listed","listing","reuse","labels","aiSiteDatasetListings","made","delivered","undefined","aiSiteDatasetPlacedPhotos","aiSiteDatasetBriefLines","join"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-job-site-datasets.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 { checkDatasetQuota } from '@aglyn/aglyn/app-utils/plan-entitlements'\nimport { pluginResourceDraftWriter } from '@aglyn/aglyn/plugin-manager/plugin-resource-drafts'\nimport { isAiPlanNewRef, type AiBuildPlanCreate, type AiBuildPlanScreen } from '../model/ai-build-plan'\nimport type { AiJob, AiJobOutput, AiJobPlan } from '../model/ai-jobs.types'\nimport type { AiPlanCapabilities } from '../model/ai-plan-capabilities'\nimport { AI_SITE_DATASETS_MAX } from '../model/ai-site-job'\nimport { AI_STEP_TIERS } from '../providers/catalog'\nimport { aiModelForStep } from '../providers/routing'\nimport {\n AI_DATASET_MAX_TOKENS,\n AI_DATASET_STEP,\n aiDatasetDraftContent,\n generateAiDataset,\n} from '../runtime/ai-dataset-generation'\nimport {\n aiLayoutListingId,\n aiLayoutRecordBaseOf,\n aiLayoutRecordsPlacements,\n type AiLayoutListing,\n type AiLayoutListingField,\n type AiLayoutListingScreen,\n} from '../layout-language/ai-layout-listings'\nimport {\n aiLayoutStarterPhotos,\n type AiLayoutPicturePhoto,\n type AiLayoutPictureSlot,\n} from '../layout-language/ai-layout-pictures'\nimport { aiSiteWords } from '../model/ai-site-job'\nimport type { AiJobAdmissionContext } from './ai-job-admission'\nimport { aiOriginJobId } from './ai-job-draft-ids'\nimport { aiSiteProductPhotoSrc } from './ai-job-site-content'\nimport { aiLayoutStockPhotoSource, aiStockPhotoWordsOf } from './ai-layout-stock-photos'\nimport { AI_DATASET_DRAFT_RESOURCE } from './ai-build-unit-outcome'\nimport { aiJobStepBudget } from './ai-job-budget'\nimport { aiGenerationSpent, aiUnspentOutcome } from './ai-job-generation'\nimport { aiPluginDraftAdmissionRefusal } from './ai-job-plugin-drafts'\nimport type { AiJobStepContext, AiJobStepOutcome, AiJobStepRunner } from './ai-job-text-step'\n\n/**\n * A SITE START'S DATASETS (AGL-3616): \"Aglyn AI can also use/create datasets\n * too for whatever it needs\" (Zach, 2026-10-10).\n *\n * A site whose content is a list of like things — a restaurant's menu, a\n * studio's team, a contractor's services, a photographer's portfolio, an\n * events list, its questions and answers — keeps it as a DATASET, the way the\n * docs teach a person to: the owner edits one record and every page listing\n * it follows. On a workspace that may create datasets, the site plan creates\n * one for such content (`create`, kind `dataset`) and names it in the `uses`\n * of each section that lists it. The scaffold then builds each dataset as a\n * unit of its own, after the layout and before the form (which may write\n * its submissions to one) and the pages:\n *\n * - DESIGNED by the `submit_dataset` generation (`ai-dataset-generation.ts`):\n * the planned fields typed, at most a few more, and 3 to 12 records seeded\n * from the brief. Nothing anybody did not say: no review, testimonial,\n * rating, quote or person's name, no price the brief does not state.\n * - WRITTEN by the data plugin's `dataset` writer — this plugin never names\n * the datasets collection — with every rule the console's datasets route\n * has: the member's role and `data.manage`, `release_data_store`,\n * `dataStore` (Starter and up), `datasetsPerOrg` counted inside the create,\n * `recordsPerDataset` and the storage band.\n * - PICTURED where the plan lists it the way a gallery is listed (Zach,\n * 2026-10-10: a ceramic artist's \"Selected work\" came back as text-only\n * cards, where it had been an image-led gallery): a portfolio's pieces, a\n * team, a menu, classes and events, and services or offerings whose\n * section says it shows them in pictures (`aiSiteDatasetPicturesOf`). Such\n * a dataset gets an Image field, and each record a stock photo of its own\n * name in the site's craft, copied into the site's library — never one the\n * job already placed, else a starter photo — searched in code, so it\n * costs no credits (`aiSiteDatasetRecordPhotos`).\n * - LISTED by the pages built after it: each section naming it repeats over\n * the dataset (`aiSiteDatasetListings`, a `records` listing the layout\n * compiler draws, its card led by the record's photo where it has one),\n * and a page the plan made its record template binds its fields by id,\n * its photo the record's, and keeps the address field the writer added.\n *\n * Where datasets cannot be created — the Free taste, Starter's two used up,\n * the data store not released — the plan is told so and creates none, so its\n * sections write the items out. A dataset unit that fails or is refused\n * leaves the pages that list it built without it (they say so), and its\n * record page is not built.\n */\n\n/** The most datasets one site start creates. */\nexport { AI_SITE_DATASETS_MAX } from '../model/ai-site-job'\n\n/** The resource the data plugin's writer is registered under. */\nexport const AI_SITE_DATASET_RESOURCE = AI_DATASET_DRAFT_RESOURCE\n\n/** What the site's plugin list calls the plugin, for \"Turn on Data for this site\". */\nconst DATA_PLUGIN_LABEL = 'Data'\n\n/** The input a dataset unit's own job carries what it needs in. */\nexport const AI_SITE_DATASET_INPUT = 'siteDataset'\n\n/** What a dataset unit's job is told beside its creation. */\nexport interface AiSiteDatasetInput {\n /** The sections that list it, by page: \"Menu › Our dishes (12 items)\". */\n shownIn: string[]\n /** Whether a page of the plan is its record template. */\n recordPages: boolean\n /**\n * The form of the plan that writes its submissions to it (AGL-3616), by\n * name, with that form's planned fields; absent where no form does.\n */\n forForm?: { name: string; fields: string[] }\n /**\n * Whether its records carry a photo, and of what (AGL-3616): `things` for a\n * portfolio's pieces, a menu, classes; `people` for a team. Absent for a\n * list a visitor reads rather than looks at: questions, steps, hours.\n */\n pictures?: AiSiteDatasetPictures\n}\n\n/** What a dataset's records are pictured as: things or people. */\nexport type AiSiteDatasetPictures = 'things' | 'people'\n\n/** A list of questions, voices or plain facts: read, never pictured. */\nconst READ_ONLY_LIST =\n /\\b(faqs?|questions?|q ?& ?a|answers?|testimonials?|reviews?|quotes?|voices|hours|opening|steps?|process|policies|policy|terms|stats?|numbers|figures|milestones|timeline|values|benefits|reasons|features|requirements|checklist|ingredients|donations?|needs|partners|sponsors|supporters|roles|positions|jobs|openings)\\b/i\n/** A list of people: its photos are of the business's people. */\nconst PEOPLE_LIST =\n /\\b(team|staff|people|crew|instructors?|teachers?|tutors?|stylists?|barbers?|therapists?|coaches?|trainers?|chefs?|doctors?|dentists?|hygienists?|practitioners?|artists?|musicians?|performers?|speakers?|founders?|members?)\\b/i\n/** A list a visitor looks at before reading: pictured wherever it is listed. */\nconst PICTURED_LIST =\n /\\b(portfolio|pieces?|works?|projects?|gallery|galleries|collections?|series|menus?|dishes|plates|drinks|cocktails|wines?|beers?|coffees?|pastries|cakes|products?|items|events?|classes|class|workshops?|courses?|retreats?|tours?|trips?|adventures?|experiences?|rooms?|suites?|cabins?|properties|listings|homes|venues?|spaces?|recipes?|artworks?|paintings?|prints?|photos?|photographs?|designs?|commissions?|builds?|vehicles?|animals?|pets?|plants?|flowers?|bouquets?|arrangements?|case studies)\\b/i\n/** A section that says it shows its items in pictures: a gallery, a grid of photos, tiles. */\nconst PICTURED_SECTION =\n /\\b(gallery|galleries|grid|images?|photos?|photographs?|pictures?|lightbox|portfolio|showcase|tiles?|visuals?|lookbook|carousel|slideshow|mosaic|thumbnails?)\\b/i\n\n/**\n * Whether a dataset's records carry a photo, read off the plan (AGL-3616):\n * its name and the names of the sections that list it. Questions, voices and\n * plain facts never; people as people; a list a visitor looks at — pieces,\n * dishes, classes, events, rooms — always; any other list (services,\n * offerings, programs) only where a section that lists it says it shows them\n * in pictures, or names one of those. A dataset no page lists is not\n * pictured. Pure.\n */\nexport function aiSiteDatasetPicturesOf(\n dataset: Pick<AiBuildPlanCreate, 'name'>,\n sections: readonly string[],\n): AiSiteDatasetPictures | null {\n if (!sections.length) return null\n const own = dataset.name\n if (READ_ONLY_LIST.test(own)) return null\n if (PEOPLE_LIST.test(own)) return 'people'\n if (PICTURED_LIST.test(own)) return 'things'\n if (sections.some((section) => READ_ONLY_LIST.test(section) && !PICTURED_SECTION.test(section))) return null\n if (sections.some((section) => PEOPLE_LIST.test(section))) return 'people'\n if (sections.some((section) => PICTURED_LIST.test(section) || PICTURED_SECTION.test(section))) return 'things'\n return null\n}\n\n/** What a dataset row says when its design could not be written: our failure, refunded. */\nexport const AI_SITE_DATASET_NOT_WRITTEN_COPY = 'This dataset could not be added this time.'\n\n/** The note a written dataset carries on the job's page. */\nexport function aiSiteDatasetNote(records: number): string {\n return `${records} ${records === 1 ? 'record' : 'records'} to start, in Data. Edit them there and every page that lists them follows.`\n}\n\n/** The note a record template's row adds: the binding is the member's to save (rule 13). */\nexport const AI_SITE_RECORD_PAGE_NOTE =\n 'A page per record is drafted, not live: open Page Properties → Record pages to save it.'\n\n/** ASSUMED: what one dataset pass reads and writes beside its generation: the site, the writer's reads and its transaction. */\nexport const AI_SITE_DATASET_WRITES_MS = 2_000\n\n/** One dataset's pass: its generation and re-ask at its ceiling, and its writes. */\nexport const AI_SITE_DATASET_BUDGET = aiJobStepBudget({\n tier: AI_STEP_TIERS[AI_DATASET_STEP],\n maxTokens: AI_DATASET_MAX_TOKENS,\n lookups: 0,\n ownReadsMs: AI_SITE_DATASET_WRITES_MS,\n})\n\nconst str = (value: unknown): string => (typeof value === 'string' ? value.trim() : '')\n\n/** The plan's reference to a dataset as a section names it: `new:<name>`, compared lowercased. */\nfunction namesDataset(ref: string, name: string): boolean {\n return isAiPlanNewRef(ref) && ref.slice(ref.indexOf(':') + 1).trim().toLowerCase() === name.trim().toLowerCase()\n}\n\n/** The plan's datasets, in plan order, at most the most a start creates. */\nexport function aiSitePlanDatasets(plan: Pick<AiJobPlan, 'create'>): AiBuildPlanCreate[] {\n return plan.create.filter((entry) => entry.kind === 'dataset').slice(0, AI_SITE_DATASETS_MAX)\n}\n\n/** Where the plan lists a dataset, in words its design reads, whether a page is its record template, and the form that writes to it. */\nexport function aiSiteDatasetInputOf(\n dataset: Pick<AiBuildPlanCreate, 'name'>,\n screens: readonly AiBuildPlanScreen[],\n create: readonly AiBuildPlanCreate[] = [],\n): AiSiteDatasetInput {\n const shownIn: string[] = []\n const sectionNames: string[] = []\n for (const screen of screens) {\n for (const section of screen.sections) {\n if (!section.uses.some((ref) => namesDataset(ref, dataset.name))) continue\n shownIn.push(`${screen.title} › ${section.name}${section.items ? ` (${section.items} items)` : ''}`)\n sectionNames.push(section.name)\n }\n }\n const recordPages = screens.some((screen) => !!screen.record && namesDataset(screen.record.dataset, dataset.name))\n const form = create.find((entry) => entry.kind === 'form' && !!entry.writesTo && namesDataset(entry.writesTo, dataset.name))\n // A form's dataset holds its submissions: nobody's photo.\n const pictures = form ? null : aiSiteDatasetPicturesOf(dataset, sectionNames)\n return {\n shownIn: shownIn.slice(0, 8),\n recordPages,\n ...(form ? { forForm: { name: form.name, fields: form.fields.slice(0, AI_SITE_FORM_DATASET_FIELDS_MAX) } } : {}),\n ...(pictures ? { pictures } : {}),\n }\n}\n\n/** Whether a plan screen is the record template of a dataset the plan creates, and which. */\nexport function aiSiteRecordTemplateOf(screen: Pick<AiBuildPlanScreen, 'record'>): string | null {\n const ref = screen.record?.dataset\n return ref && isAiPlanNewRef(ref) ? ref.slice(ref.indexOf(':') + 1).trim() : null\n}\n\nfunction datasetInputOf(job: Pick<AiJob, 'inputs'>): AiSiteDatasetInput {\n const raw = (job.inputs?.[AI_SITE_DATASET_INPUT] ?? {}) as Partial<AiSiteDatasetInput>\n const form = raw.forForm && typeof raw.forForm === 'object' ? raw.forForm : null\n return {\n shownIn: Array.isArray(raw.shownIn) ? raw.shownIn.map(str).filter(Boolean).slice(0, 8) : [],\n recordPages: raw.recordPages === true,\n ...(form && str(form.name)\n ? {\n forForm: {\n name: str(form.name),\n fields: Array.isArray(form.fields) ? form.fields.map(str).filter(Boolean).slice(0, AI_SITE_FORM_DATASET_FIELDS_MAX) : [],\n },\n }\n : {}),\n ...(raw.pictures === 'things' || raw.pictures === 'people' ? { pictures: raw.pictures } : {}),\n }\n}\n\n/** The most fields a form's dataset is designed with: the data plugin writer's own ceiling is higher. */\nexport const AI_SITE_FORM_DATASET_FIELDS_MAX = 12\n\n/** The field types a planned `Name:type` may name, as the data plugin's writer takes them. */\nconst FORM_DATASET_FIELD_TYPES = ['text', 'number', 'integer', 'boolean', 'list'] as const\n\n/** A planned field as a person reads it: `fullName` and `full_name` are \"Full name\", `fechaDeÚltimaVisita` \"Fecha de última visita\". */\nexport function aiSiteDatasetFieldName(planned: string): string {\n const words = planned\n .replace(/([\\p{Ll}\\p{N}])(\\p{Lu})/gu, '$1 $2')\n .replace(/[_-]+/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim()\n return words ? words.charAt(0).toUpperCase() + words.slice(1).toLowerCase() : ''\n}\n\n/**\n * A dataset a form writes to, as the data plugin's writer takes it\n * (AGL-3616): designed with no model, since its records are the\n * submissions. Its fields are its planned ones — or, where the plan gave it\n * none, the form's — each a person's words for it, text unless the plan\n * typed it as `Name:type`, never required, so a submission that leaves one\n * blank is still a record. It starts with no records. Pure.\n */\nexport function aiSiteFormDatasetContent(\n name: string,\n planned: readonly string[],\n form: { fields: readonly string[] },\n): Record<string, unknown> {\n const specs = (planned.length ? planned : form.fields).slice(0, AI_SITE_FORM_DATASET_FIELDS_MAX)\n const seen = new Set<string>()\n const fields: Array<{ name: string; type: string }> = []\n for (const spec of specs) {\n const at = spec.lastIndexOf(':')\n const typed = at > 0 ? spec.slice(at + 1).trim().toLowerCase() : ''\n const type = (FORM_DATASET_FIELD_TYPES as readonly string[]).includes(typed) ? typed : 'text'\n const fieldName = aiSiteDatasetFieldName(type === typed ? spec.slice(0, at) : spec).slice(0, 60)\n if (!fieldName || seen.has(fieldName.toLowerCase())) continue\n seen.add(fieldName.toLowerCase())\n fields.push({ name: fieldName, type })\n }\n return { name, fields, records: [] }\n}\n\n/** The note a form's dataset carries on the job's page. */\nexport function aiSiteFormDatasetNote(form: string): string {\n return `Empty to start: each submission of the form “${form}” is added here, in Data.`\n}\n\nconst limitReview = (message: string) => ({ reason: 'limit' as const, message, findings: [] })\n\n/** The wall clock a dataset's photos may take inside its pass: the 20 seconds a page's pictures had (AGL-3660). */\nexport const AI_SITE_DATASET_PHOTOS_BUDGET_MS = 20_000\n\n/** The field a pictured dataset's photo is kept in, where the plan gave it none. */\nexport const AI_SITE_DATASET_IMAGE_FIELD = 'Image'\n\n/**\n * The field a pictured dataset keeps what each record's photo shows in\n * (AGL-3856), which its card's and its page's Image take as their alt text:\n * a record's title is what it is called, never what its photo shows.\n */\nexport const AI_SITE_DATASET_IMAGE_ALT_FIELD = 'Image description'\n\n/** A planned field that already names a record's photo. */\nconst IMAGE_FIELD_NAME =\n /^(?:main |cover |hero |featured? )?(?:image|photo|picture|photograph|thumbnail|headshot|portrait|cover)s?$/i\n\n/** One record's photo: the address its Image shows, and the library asset placed, which no page shows again. */\nexport interface AiSiteDatasetRecordPhoto {\n /** The media library's CDN path, or a starter's site path; `null` for none. */\n src: string | null\n /** The `media:` reference of the stock photo placed, or `null` for a starter. */\n placed: string | null\n /** What the photo shows, in its own words (AGL-3856); `null` for none. */\n alt?: string | null\n}\n\n/**\n * A photo for each record of a pictured dataset (AGL-3616), in order: a stock\n * photo of the record's own name, in the site's craft (\"ceramic speckled\n * serving bowl\"), copied into the site's library, where the deployment has a\n * stock library — never twice in the dataset nor one another part of the job\n * placed, inside {@link AI_SITE_DATASET_PHOTOS_BUDGET_MS} — else a starter\n * photo, as a page's empty picture takes one. A team is searched as the\n * business's people. The photo is kept as the asset's CDN path, the form a\n * product keeps (`aiSiteProductPhotoSrc`), so a replace in the library still\n * reaches it. No AI model is asked, so no credits; never throws.\n */\nexport async function aiSiteDatasetRecordPhotos(input: {\n job: Pick<AiJob, '$id' | 'hostId' | 'createdBy' | 'inputs' | 'brief' | 'plan'>\n /** The dataset, as the plan named it. */\n name: string\n /** Each record's name, by position. */\n names: readonly string[]\n pictures: AiSiteDatasetPictures\n signal?: AbortSignal\n stockPhotos?: typeof aiLayoutStockPhotoSource\n}): Promise<AiSiteDatasetRecordPhoto[]> {\n const { job } = input\n if (!input.names.length || !job.hostId) return input.names.map(() => ({ src: null, placed: null }))\n const people = input.pictures === 'people'\n const slots: AiLayoutPictureSlot[] = input.names.map((name, index) => ({\n imageId: `record${index}`,\n frameId: null,\n iconId: null,\n alt: name.trim() || input.name,\n // The record card's own shape: a team's portraits stand, pieces sit wide.\n aspect: people ? 4 / 5 : 4 / 3,\n sectionIndex: 0,\n role: people ? ('about' as const) : ('gallery' as const),\n // A record's name is a search's words, never what its photo shows (AGL-3856).\n standIn: true,\n }))\n const seed = `${job.$id}:records`\n let found: ReadonlyArray<AiLayoutPicturePhoto | null> = []\n try {\n const source = (input.stockPhotos ?? aiLayoutStockPhotoSource)(\n {\n hostId: job.hostId,\n uid: job.createdBy,\n seed,\n business: aiSiteWords(job.inputs).about || job.brief,\n ...aiStockPhotoWordsOf(job),\n sectionNames: [input.name],\n jobId: aiOriginJobId(job),\n // Each record may try its name, its object and the site's world.\n searches: slots.length * 3,\n ...(input.signal ? { signal: input.signal } : {}),\n },\n { budgetMs: AI_SITE_DATASET_PHOTOS_BUDGET_MS },\n )\n if (source) found = await source(slots)\n } catch (error) {\n console.warn('ai site dataset: the stock photos failed; starter photos fill them', { error: String(error) })\n }\n const starters = aiLayoutStarterPhotos(slots, seed)\n const hostId = job.hostId\n return slots.map((_slot, index) => {\n const stock = aiSiteProductPhotoSrc(found[index]?.src, hostId)\n if (stock) return { src: stock, placed: found[index]?.src ?? null, alt: found[index]?.alt?.trim() || null }\n return { src: aiSiteProductPhotoSrc(starters[index]?.src, hostId), placed: null, alt: starters[index]?.alt?.trim() || null }\n })\n}\n\n/**\n * A designed dataset's content with its records' photos (AGL-3616): the\n * planned field that names a photo (\"Image\", \"Photo\") becomes the data\n * plugin's `image` field, else one called \"Image\" is added after the others,\n * and each record holds its photo there; a record with none holds nothing.\n * Pure.\n */\nexport function aiSiteDatasetContentWithPhotos(\n content: Record<string, unknown>,\n photos: ReadonlyArray<string | null>,\n /** What each record's photo shows (AGL-3856), kept in {@link AI_SITE_DATASET_IMAGE_ALT_FIELD}; none adds no field. */\n alts: ReadonlyArray<string | null> = [],\n): Record<string, unknown> {\n const fields = (Array.isArray(content['fields']) ? content['fields'] : []) as Array<{ name: string; type?: string }>\n const named = fields.find((field) => IMAGE_FIELD_NAME.test(str(field.name)))\n const fieldName = named ? named.name : AI_SITE_DATASET_IMAGE_FIELD\n const withImage = named\n ? fields.map((field) => (field === named ? { ...field, type: 'image' } : field))\n : [...fields, { name: AI_SITE_DATASET_IMAGE_FIELD, type: 'image' }]\n const described = alts.some((alt, index) => Boolean(alt && photos[index]))\n const altName = AI_SITE_DATASET_IMAGE_ALT_FIELD\n const nextFields =\n described && !withImage.some((field) => str(field.name).toLowerCase() === altName.toLowerCase())\n ? [...withImage, { name: altName, type: 'text' }]\n : withImage\n const records = (Array.isArray(content['records']) ? content['records'] : []) as Array<Record<string, unknown>>\n return {\n ...content,\n fields: nextFields,\n records: records.map((record, index) => {\n const next = { ...record }\n delete next[fieldName]\n const photo = photos[index]\n const alt = photo && described ? alts[index] : null\n return photo ? { ...next, [fieldName]: photo, ...(alt ? { [altName]: alt } : {}) } : next\n }),\n }\n}\n\nexport interface AiSiteDatasetRunnerDeps {\n generate?: typeof generateAiDataset\n writerFor?: typeof pluginResourceDraftWriter\n /** Where a pictured dataset's photos come from; the stock library, else the starters, otherwise. */\n photos?: typeof aiSiteDatasetRecordPhotos\n}\n\n/** The fields and record names a written dataset reports, as its output's proposal keeps them. */\ninterface AiSiteDatasetProposal {\n fields: AiLayoutListingField[]\n /** Each record's name: its first field's value. */\n recordNames: string[]\n addressField: string | null\n /** The field each record's photo is in, where it has one (AGL-3616). */\n imageField?: string | null\n /** The library photos its records show (`media:` references), which no page places again. */\n photos?: string[]\n /**\n * The fields most of its first records leave empty, by id (AGL-3616): a\n * tour's venues not yet known. A card never binds one — it would print\n * nothing on most records — so its listing leaves them out.\n */\n sparseFields?: string[]\n}\n\n/**\n * The fields of a designed dataset that its records leave empty on most of\n * them — every record, or more than half — by the id the data plugin gave\n * each (AGL-3616). Its first field is the record's name and is never one. The\n * live low-tide-hollow start (beta.239) seeded its tour dates with no venue,\n * rightly inventing none, and its cards bound the venue as their eyebrow.\n */\nexport function aiDatasetSparseFields(\n dataset: { fields: ReadonlyArray<{ name: string }>; records: ReadonlyArray<ReadonlyArray<string | undefined>> },\n written: readonly AiLayoutListingField[],\n): string[] {\n if (!dataset.records.length) return []\n const idOf = (name: string, column: number) =>\n written.find((field) => field.name.trim().toLowerCase() === name.trim().toLowerCase())?.id ?? written[column]?.id ?? null\n return dataset.fields.flatMap((field, column) => {\n if (column === 0) return []\n const filled = dataset.records.filter((values) => (values[column] ?? '').trim()).length\n const id = idOf(field.name, column)\n return id && filled * 2 <= dataset.records.length ? [id] : []\n })\n}\n\nfunction proposalOf(output: Pick<AiJobOutput, 'proposal'>): AiSiteDatasetProposal {\n const raw = (output.proposal ?? {}) as Partial<AiSiteDatasetProposal>\n return {\n fields: Array.isArray(raw.fields)\n ? raw.fields.filter((field) => field && typeof field.id === 'string' && field.id).map((field) => ({ id: field.id, name: str(field.name) || field.id, type: str(field.type) || 'text' }))\n : [],\n recordNames: Array.isArray(raw.recordNames) ? raw.recordNames.map(str).filter(Boolean).slice(0, 12) : [],\n addressField: str(raw.addressField) || null,\n imageField: str(raw.imageField) || null,\n photos: Array.isArray(raw.photos) ? raw.photos.map(str).filter((src) => src.startsWith('media:')).slice(0, 24) : [],\n sparseFields: Array.isArray(raw.sparseFields) ? raw.sparseFields.map(str).filter(Boolean) : [],\n }\n}\n\n/**\n * The dataset unit's runner, on the job the scaffold derived for it: the one\n * creation its plan carries, designed by the model and written by the data\n * plugin, under the creation's own id. A pass repeated after its write finds\n * the dataset the writer wrote and reports it again, spending nothing.\n */\nexport function createAiSiteDatasetRunner(deps: AiSiteDatasetRunnerDeps = {}): AiJobStepRunner {\n const generate = deps.generate ?? generateAiDataset\n const writerFor = deps.writerFor ?? pluginResourceDraftWriter\n const photosFor = deps.photos ?? aiSiteDatasetRecordPhotos\n return async (context): Promise<AiJobStepOutcome> => {\n const { job, firestore, signal } = context\n const model = context.modelFor?.(AI_DATASET_STEP) ?? aiModelForStep(AI_DATASET_STEP)\n const creation = (job.plan as AiJobPlan | null)?.create?.find((entry) => entry.kind === 'dataset')\n const keeper = writerFor(AI_SITE_DATASET_RESOURCE)\n if (!job.hostId || !creation) return { ...aiUnspentOutcome(model), failure: 'Open the site before adding its data.' }\n if (!keeper) return { ...aiUnspentOutcome(model), failure: 'Datasets are not available on this site.' }\n const host = await firestore.collection('hosts').doc(job.hostId).get()\n const hostSubdomain = str(host.get('subdomain')) || null\n const output = (id: string, name: string, proposal: AiSiteDatasetProposal, records: number): AiJobOutput => ({\n resource: 'draft',\n draftResource: AI_SITE_DATASET_RESOURCE,\n id,\n hostId: job.hostId ?? null,\n hostSubdomain,\n label: name,\n note: aiSiteDatasetNote(records),\n proposal: proposal as unknown as Record<string, unknown>,\n })\n const input = datasetInputOf(job)\n // Asked again under the same id: the dataset already written.\n const written = await keeper.writer.read({ hostId: job.hostId, id: job.$id })\n if (written) {\n const facts = written.facts as { fields?: AiLayoutListingField[]; addressField?: string | null; imageField?: string | null }\n const again = output(\n written.id,\n written.name || creation.name,\n { fields: facts.fields ?? [], recordNames: [], addressField: facts.addressField ?? null, imageField: facts.imageField ?? null },\n 0,\n )\n return aiUnspentOutcome(model, {\n outputs: [input.forForm ? { ...again, note: aiSiteFormDatasetNote(input.forForm.name) } : again],\n })\n }\n // A form's dataset (AGL-3616): its records are the submissions, so it is\n // designed from the plan with no model, and starts empty.\n if (input.forForm) {\n const content = aiSiteFormDatasetContent(creation.name, creation.fields, input.forForm)\n const checked = keeper.writer.check(content, { hostId: job.hostId })\n if (checked.ok === false) {\n console.error('ai site dataset: the dataset writer refused a form dataset we made', { orgId: job.orgId, jobId: job.$id, problems: checked.problems })\n return { ...aiUnspentOutcome(model), failure: AI_SITE_DATASET_NOT_WRITTEN_COPY }\n }\n const result = await keeper.writer.write({\n orgId: job.orgId,\n hostId: job.hostId,\n uid: job.createdBy,\n org: (context.org ?? null) as Readonly<Record<string, unknown>> | null,\n now: context.now,\n id: job.$id,\n name: creation.name,\n content,\n })\n if (result.ok === false) {\n if (result.status === 400) return { ...aiUnspentOutcome(model), failure: AI_SITE_DATASET_NOT_WRITTEN_COPY }\n return { ...aiUnspentOutcome(model), review: limitReview(result.error) }\n }\n const facts = result.facts as { fields?: AiLayoutListingField[]; addressField?: string | null }\n return aiUnspentOutcome(model, {\n outputs: [\n {\n ...output(result.id, result.name, { fields: facts.fields ?? [], recordNames: [], addressField: null }, 0),\n note: aiSiteFormDatasetNote(input.forForm.name),\n },\n ],\n })\n }\n const generation = await generate({\n brief: job.brief,\n merchantWords: job.brief,\n name: creation.name,\n why: creation.why,\n fields: creation.fields,\n shownIn: input.shownIn,\n recordPages: input.recordPages,\n model,\n maxTokens: AI_SITE_DATASET_BUDGET.maxTokens(model),\n ...(signal ? { signal } : {}),\n })\n const spent = aiGenerationSpent(generation)\n if (generation.status === 'refused') return { ...spent, refused: true }\n if (generation.status === 'needs_input') return { ...spent, failure: generation.message }\n const designed = aiDatasetDraftContent(creation.name, generation.value, { recordPages: input.recordPages })\n // A list a visitor looks at keeps its records' photos (AGL-3616): searched\n // in code, never asked of the model, so they cost no credits.\n const photos = input.pictures\n ? await photosFor({\n job,\n name: creation.name,\n names: generation.value.records.map((values) => values[0] ?? ''),\n pictures: input.pictures,\n ...(signal ? { signal } : {}),\n }).catch(() => [] as AiSiteDatasetRecordPhoto[])\n : []\n const content = input.pictures\n ? aiSiteDatasetContentWithPhotos(\n designed,\n generation.value.records.map((_values, index) => photos[index]?.src ?? null),\n generation.value.records.map((_values, index) => photos[index]?.alt ?? null),\n )\n : designed\n // The data plugin's own rules, before anything is written: content we\n // made that its model refuses is our failure, refunded.\n const checked = keeper.writer.check(content, { hostId: job.hostId })\n if (checked.ok === false) {\n console.error('ai site dataset: the dataset writer refused a dataset we made', { orgId: job.orgId, jobId: job.$id, problems: checked.problems })\n return { ...spent, failure: AI_SITE_DATASET_NOT_WRITTEN_COPY }\n }\n const result = await keeper.writer.write({\n orgId: job.orgId,\n hostId: job.hostId,\n uid: job.createdBy,\n org: (context.org ?? null) as Readonly<Record<string, unknown>> | null,\n now: context.now,\n id: job.$id,\n name: creation.name,\n content,\n })\n if (result.ok === false) {\n if (result.status === 400) return { ...spent, failure: AI_SITE_DATASET_NOT_WRITTEN_COPY }\n // The allowance, the role, the plan or the flag: the workspace's to change.\n return { ...spent, review: limitReview(result.error) }\n }\n const facts = result.facts as {\n fields?: AiLayoutListingField[]\n records?: number\n addressField?: string | null\n imageField?: string | null\n }\n const placed = photos.flatMap((photo) => (photo.placed ? [photo.placed] : []))\n const proposal: AiSiteDatasetProposal = {\n fields: facts.fields ?? [],\n recordNames: generation.value.records.map((values) => values[0] ?? '').filter(Boolean).slice(0, 12),\n addressField: facts.addressField ?? null,\n ...(facts.imageField ? { imageField: facts.imageField } : {}),\n ...(placed.length ? { photos: placed } : {}),\n sparseFields: aiDatasetSparseFields(generation.value, facts.fields ?? []),\n }\n return { ...spent, outputs: [output(result.id, result.name, proposal, facts.records ?? generation.value.records.length)] }\n }\n}\n\nexport const runAiSiteDatasetUnit = createAiSiteDatasetRunner()\n\n/**\n * Whether a dataset may be created for this member on this site, asked before\n * its first pass so a refusal spends nothing; `null` admits. The data plugin\n * must run here (on for the workspace and the site, past its release flag),\n * and its writer says whether this member may make one now: the role, the\n * plan, the flag, the allowance.\n */\nexport async function aiSiteDatasetRefusal(\n context: Pick<AiJobStepContext, 'firestore' | 'org' | 'now'> & { job: Pick<AiJob, 'orgId' | 'hostId' | 'createdBy'> },\n deps: { admission?: typeof aiPluginDraftAdmissionRefusal; writerFor?: (resource: string) => ReturnType<typeof pluginResourceDraftWriter> } = {},\n): Promise<string | null> {\n const { job } = context\n if (!job.hostId) return 'Open the site first.'\n const writerFor = deps.writerFor ?? pluginResourceDraftWriter\n const admission: AiJobAdmissionContext = {\n firestore: context.firestore,\n orgId: job.orgId,\n hostId: job.hostId,\n inputs: {},\n org: context.org ?? null,\n uid: job.createdBy,\n }\n const refused = await (deps.admission ?? aiPluginDraftAdmissionRefusal)(admission, {\n kind: 'site',\n drafts: [{ resource: AI_SITE_DATASET_RESOURCE, label: DATA_PLUGIN_LABEL }],\n writerFor: (resource) => writerFor(resource)?.writer ?? null,\n ownerFor: (resource) => writerFor(resource)?.pluginId ?? null,\n now: context.now,\n })\n return refused?.error ?? null\n}\n\n/**\n * A site plan's dataset capability on this workspace (AGL-3616): where the\n * workspace's plan includes datasets, whether the data plugin runs here and\n * this member may create one now, and how many a start may make. A clause the\n * plan's turn completes is the reason where it may not.\n */\nexport async function aiSitePlanDatasetCapability(\n capabilities: AiPlanCapabilities,\n context: Parameters<typeof aiSiteDatasetRefusal>[0],\n deps: Parameters<typeof aiSiteDatasetRefusal>[1] = {},\n): Promise<AiPlanCapabilities> {\n if (!capabilities.create.dataset.allowed) return capabilities\n const refusal = await aiSiteDatasetRefusal(context, deps).catch((error: unknown) => {\n console.error('ai site plan: the dataset admission failed', { orgId: context.job.orgId, error })\n return 'datasets could not be checked just now'\n })\n const left = Math.min(AI_SITE_DATASETS_MAX, checkDatasetQuota(context.org as never, 0).limit)\n const dataset = refusal\n ? { allowed: false, left: 0, reason: `datasets cannot be created here: ${refusal.replace(/\\.$/, '')}` }\n : { allowed: true, left, reason: null }\n return { ...capabilities, create: { ...capabilities.create, dataset } }\n}\n\n/**\n * A `records` listing for each dataset that was made and that a section of the\n * plan names (AGL-3616). Its fields, where none are given, are read off the\n * site's inventory when the page is designed (`aiLayoutListingsWithDatasets`).\n */\nexport function aiDatasetListingsOf(\n datasets: ReadonlyArray<{\n id: string\n name: string\n records?: string[]\n fields?: AiLayoutListingField[]\n imageField?: string | null\n /** The record's page-address field, where the writer added one (AGL-3727). */\n addressField?: string | null\n }>,\n screens: readonly AiLayoutListingScreen[],\n): AiLayoutListing[] {\n return datasets.flatMap((dataset) => {\n const placements = aiLayoutRecordsPlacements(dataset, screens)\n if (!placements.length) return []\n // Each card links its record's own page where the plan makes one (AGL-3727).\n const recordBase = aiLayoutRecordBaseOf(dataset, screens)\n return [\n {\n id: aiLayoutListingId('records', dataset.id),\n kind: 'records' as const,\n name: dataset.name,\n records: dataset.records ?? [],\n datasetId: dataset.id,\n ...(dataset.fields?.length ? { fields: dataset.fields } : {}),\n // Its card leads with the record's photo (AGL-3616).\n ...(dataset.imageField ? { imageField: dataset.imageField } : {}),\n // The address is read off the site's inventory where the build does not know it yet.\n ...(recordBase ? { recordBase, ...(dataset.addressField ? { addressField: dataset.addressField } : {}) } : {}),\n placements,\n },\n ]\n })\n}\n\n/**\n * A `records` listing for each dataset the workspace already keeps that a\n * site start's plan reuses and a section names (AGL-3771), as a build lists\n * the ones it reuses (AGL-3747). A second site in a workspace reuses the\n * first one's menu: its plan names the dataset by id, the start listed only\n * the datasets it made, and the page was asked to \"place\" a dataset no block\n * can draw — the home's \"Del menú\" section was refused for showing none of\n * its six items, and the Menú page published with no menu. A dataset one of\n * the plan's forms writes into holds the site's submissions, and is never\n * listed on a page.\n */\nexport function aiSiteReusedDatasetListings(input: {\n plan: Pick<AiJobPlan, 'reuse' | 'create' | 'labels'>\n screens: readonly AiLayoutListingScreen[]\n /** The listings the start already has, whose datasets are not listed twice. */\n listed: ReadonlyArray<Pick<AiLayoutListing, 'datasetId'>>\n}): AiLayoutListing[] {\n const submissions = new Set(\n input.plan.create.flatMap((entry) => (entry.kind === 'form' && entry.writesTo && !isAiPlanNewRef(entry.writesTo) ? [entry.writesTo] : [])),\n )\n const listed = new Set(input.listed.map((listing) => listing.datasetId).filter(Boolean))\n const datasets = input.plan.reuse\n .filter((entry) => entry.kind === 'dataset' && !submissions.has(entry.id) && !listed.has(entry.id))\n .map((entry) => ({ id: entry.id, name: input.plan.labels?.[entry.id] || entry.id }))\n return aiDatasetListingsOf(datasets, input.screens)\n}\n\n/**\n * The site's datasets a layout or a page unit is handed (AGL-3616), each a\n * `records` listing with the sections of the plan's pages that name it, once\n * its unit wrote it. A dataset not yet written, or one that failed, lists\n * nowhere: the pages built without it write the items out.\n */\nexport function aiSiteDatasetListings(input: {\n outputs: readonly AiJobOutput[]\n datasets: ReadonlyArray<Pick<AiBuildPlanCreate, 'name'>>\n screens: readonly AiLayoutListingScreen[]\n /** The ids each dataset's unit delivered, by plan name lowercased. */\n delivered: ReadonlyMap<string, string>\n}): AiLayoutListing[] {\n const made = input.datasets.flatMap((dataset) => {\n const id = input.delivered.get(dataset.name.trim().toLowerCase())\n const output = id\n ? input.outputs.find((entry) => entry.resource === 'draft' && entry.draftResource === AI_SITE_DATASET_RESOURCE && entry.id === id)\n : undefined\n if (!id || !output) return []\n const proposal = proposalOf(output)\n return [\n {\n id,\n // Placed by the name the plan's sections gave it.\n name: dataset.name,\n records: proposal.recordNames,\n // The address field is the record page's, never a card's words; the\n // photo is the card's picture, never its words; a field most records\n // leave empty is no card's either (AGL-3616).\n fields: proposal.fields.filter(\n (field, index) =>\n field.id !== proposal.addressField &&\n field.id !== proposal.imageField &&\n (index === 0 || !proposal.sparseFields?.includes(field.id)),\n ),\n imageField: proposal.imageField ?? null,\n addressField: proposal.addressField,\n },\n ]\n })\n return aiDatasetListingsOf(made, input.screens)\n}\n\n/** The library photos the site's datasets' records show (AGL-3616), which a page does not place again. */\nexport function aiSiteDatasetPlacedPhotos(outputs: readonly AiJobOutput[]): string[] {\n return [\n ...new Set(\n outputs\n .filter((output) => output.resource === 'draft' && output.draftResource === AI_SITE_DATASET_RESOURCE)\n .flatMap((output) => proposalOf(output).photos ?? []),\n ),\n ]\n}\n\n/** What a page is told about the datasets built before it. */\nexport function aiSiteDatasetBriefLines(outputs: readonly AiJobOutput[]): string[] {\n const datasets = outputs.filter((output) => output.resource === 'draft' && output.draftResource === AI_SITE_DATASET_RESOURCE)\n return datasets.flatMap((output) => {\n const names = proposalOf(output).recordNames\n return names.length\n ? [`This site's dataset “${output.label}” holds: ${names.map((name) => `“${name}”`).join(', ')}. Where a page names one, name it as written; never name one that is not in this list.`]\n : []\n })\n}\n"],"names":["checkDatasetQuota","pluginResourceDraftWriter","isAiPlanNewRef","AI_SITE_DATASETS_MAX","AI_STEP_TIERS","aiModelForStep","AI_DATASET_MAX_TOKENS","AI_DATASET_STEP","aiDatasetDraftContent","generateAiDataset","aiLayoutListingId","aiLayoutRecordBaseOf","aiLayoutRecordsPlacements","aiLayoutStarterPhotos","aiSiteWords","aiOriginJobId","aiSiteProductPhotoSrc","aiLayoutStockPhotoSource","aiStockPhotoWordsOf","AI_DATASET_DRAFT_RESOURCE","aiJobStepBudget","aiGenerationSpent","aiUnspentOutcome","aiPluginDraftAdmissionRefusal","AI_SITE_DATASET_RESOURCE","DATA_PLUGIN_LABEL","AI_SITE_DATASET_INPUT","READ_ONLY_LIST","PEOPLE_LIST","PICTURED_LIST","PICTURED_SECTION","aiSiteDatasetPicturesOf","dataset","sections","length","own","name","test","some","section","AI_SITE_DATASET_NOT_WRITTEN_COPY","aiSiteDatasetNote","records","AI_SITE_RECORD_PAGE_NOTE","AI_SITE_DATASET_WRITES_MS","AI_SITE_DATASET_BUDGET","tier","maxTokens","lookups","ownReadsMs","str","value","trim","namesDataset","ref","slice","indexOf","toLowerCase","aiSitePlanDatasets","plan","create","filter","entry","kind","aiSiteDatasetInputOf","screens","shownIn","sectionNames","screen","uses","push","title","items","recordPages","record","form","find","writesTo","pictures","forForm","fields","AI_SITE_FORM_DATASET_FIELDS_MAX","aiSiteRecordTemplateOf","datasetInputOf","job","raw","inputs","Array","isArray","map","Boolean","FORM_DATASET_FIELD_TYPES","aiSiteDatasetFieldName","planned","words","replace","charAt","toUpperCase","aiSiteFormDatasetContent","specs","seen","Set","spec","at","lastIndexOf","typed","type","includes","fieldName","has","add","aiSiteFormDatasetNote","limitReview","message","reason","findings","AI_SITE_DATASET_PHOTOS_BUDGET_MS","AI_SITE_DATASET_IMAGE_FIELD","AI_SITE_DATASET_IMAGE_ALT_FIELD","IMAGE_FIELD_NAME","aiSiteDatasetRecordPhotos","input","names","hostId","src","placed","people","slots","index","imageId","frameId","iconId","alt","aspect","sectionIndex","role","standIn","seed","$id","found","source","stockPhotos","uid","createdBy","business","about","brief","jobId","searches","signal","budgetMs","error","console","warn","String","starters","_slot","stock","aiSiteDatasetContentWithPhotos","content","photos","alts","named","field","withImage","described","altName","nextFields","next","photo","aiDatasetSparseFields","written","idOf","column","id","flatMap","filled","values","proposalOf","output","proposal","recordNames","addressField","imageField","startsWith","sparseFields","createAiSiteDatasetRunner","deps","generate","writerFor","photosFor","context","facts","firestore","model","modelFor","creation","keeper","failure","host","collection","doc","get","hostSubdomain","resource","draftResource","label","note","writer","read","again","outputs","checked","check","ok","orgId","problems","result","write","org","now","status","review","generation","merchantWords","why","spent","refused","designed","catch","_values","runAiSiteDatasetUnit","aiSiteDatasetRefusal","admission","drafts","ownerFor","pluginId","aiSitePlanDatasetCapability","capabilities","allowed","refusal","left","Math","min","limit","aiDatasetListingsOf","datasets","placements","recordBase","datasetId","aiSiteReusedDatasetListings","submissions","listed","listing","reuse","labels","aiSiteDatasetListings","made","delivered","undefined","aiSiteDatasetPlacedPhotos","aiSiteDatasetBriefLines","join"],"mappings":"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"}
@@ -130,6 +130,14 @@ import type { AiBuildPlan } from '../model/ai-build-plan';
130
130
  * ("wedding" of "a wedding and portrait photographer") is not the craft;
131
131
  * and a hero whose second tag names the world too leads one whose first
132
132
  * alone does.
133
+ * 9. **A world from the name** (the beta.261 Synchronicity Gym start,
134
+ * AGL-3856: its business type "a local service business" named no world,
135
+ * so its hero searched nothing and was left a black scrim, and its
136
+ * closing band's "Ready to train" took a subway train). A business type
137
+ * that names no world takes the craft its name, else its audience, names
138
+ * where this module lists it ("gym" of "Synchronicity Gym"); and a
139
+ * training word's other senses (a railway's train, an elevator's lift, a
140
+ * newspaper's press, a boat's row) never fill a gym's picture.
133
141
  *
134
142
  * A slot the library could not fill because it never answered — down, or
135
143
  * out of time before its first answer — or because the site's library
@@ -200,6 +208,8 @@ export interface AiStockSiteTerms {
200
208
  broad: string[];
201
209
  /** The searches for its maker at work, for a story of the craft (AGL-3660); empty for a craft not listed. */
202
210
  making: string[];
211
+ /** Whether a picture naming people at a moment is searched by its scene ({@link aiStockScene}, AGL-3856). */
212
+ scenes?: boolean;
203
213
  /** Every stem of the business type or brief: what lets a sensitive topic in ({@link SENSITIVE_TOPICS}). */
204
214
  named: string[];
205
215
  /** Rival crafts' words, each with the words that must then be named too ({@link CRAFT_KIN}). */
@@ -271,6 +281,14 @@ export interface AiStockSearch extends StockPhotoSearchRequest {
271
281
  first?: boolean;
272
282
  /** Phrases (as stems) of which one must be among the hit's first tags: a borrowed photo is OF the product's category (AGL-3660). */
273
283
  leadAny?: readonly string[];
284
+ /** Whether its hits must name its object, whatever the slot's role: a scene's people (AGL-3856). */
285
+ strict?: boolean;
286
+ /** Words its hits never carry, whatever the brief names: a bride in a family session ({@link aiStockScene}). */
287
+ refuse?: readonly string[];
288
+ /** Stems of which every hit names one, whatever else it names: a scene's people, never roses alone ({@link aiStockScene}). */
289
+ needs?: readonly string[];
290
+ /** Stems its own words name, which let a topic in as the brief's do: a family session's children ({@link aiStockScene}). */
291
+ allow?: readonly string[];
274
292
  /** Whether it fills a product: no room, no scene, no fragrance bottle ({@link PRODUCT_SCENES}, AGL-3660). */
275
293
  product?: boolean;
276
294
  /** Words its hits never carry unless the slot or the brief names them ({@link AiStockSiteTerms.shun}). */
@@ -291,6 +309,29 @@ export type AiStockSlotPart = 'collection' | 'story';
291
309
  * the craft, or of a thing made by hand, shows the maker at work.
292
310
  */
293
311
  export declare function aiStockSlotPart(slot: Pick<AiLayoutPictureSlot, 'role' | 'alt'>, sectionName: string): AiStockSlotPart | undefined;
312
+ /** What a picture of a moment shows ({@link aiStockScene}). */
313
+ export interface AiStockScene {
314
+ /** The searches that ask for it, the people and their setting first. */
315
+ queries: string[];
316
+ /** The words its photo is scored by: the people, and the setting. */
317
+ subject: string;
318
+ /** The thing a photo of it leads with, and its kin. */
319
+ object: string;
320
+ lead: string[];
321
+ /** Words of which a photo of it names one. */
322
+ people: string[];
323
+ shun: string[];
324
+ /** The stems of its words, which let in what they name: a family's children. */
325
+ named: string[];
326
+ }
327
+ /**
328
+ * The scene a picture's words name (AGL-3856): the people at a moment, and
329
+ * where — "Ridgetop Elopement" a couple in the mountains, "Mountain Wedding
330
+ * Day" a wedding couple in the mountains, "Family Session in the Fall" a
331
+ * family in autumn — read from every word, never only the first clause.
332
+ * `null` where it names no people.
333
+ */
334
+ export declare function aiStockScene(text: string): AiStockScene | null;
294
335
  /** What a product falls back to once its own searches find nothing ({@link aiStockProductSearches}). */
295
336
  export interface AiStockProductFallback {
296
337
  /** The site's broad searches ({@link AiStockSiteTerms.broad}): "handmade soap". */
@@ -346,7 +387,7 @@ export interface AiStockProductFallback {
346
387
  */
347
388
  export declare function aiStockProductSearches(slot: Pick<AiLayoutPictureSlot, 'aspect' | 'product'>, craft: string, domain?: readonly string[], fallback?: AiStockProductFallback): AiStockSearch[];
348
389
  /** The searches a slot tries, in order, most specific first, each distinct. */
349
- export declare function aiStockSearchesFor(slot: Pick<AiLayoutPictureSlot, 'role' | 'alt' | 'aspect'>, terms: Pick<AiStockSiteTerms, 'business' | 'craft' | 'domain' | 'broad'> & Partial<Pick<AiStockSiteTerms, 'making' | 'core'>>, subject: string, part?: AiStockSlotPart): AiStockSearch[];
390
+ export declare function aiStockSearchesFor(slot: Pick<AiLayoutPictureSlot, 'role' | 'alt' | 'aspect'>, terms: Pick<AiStockSiteTerms, 'business' | 'craft' | 'domain' | 'broad'> & Partial<Pick<AiStockSiteTerms, 'making' | 'core' | 'scenes'>>, subject: string, part?: AiStockSlotPart): AiStockSearch[];
350
391
  /** What a hit is judged by. */
351
392
  export interface AiStockJudgement {
352
393
  /** The words the picture is of; empty for a picture of the site's world. */
@@ -387,6 +428,10 @@ export interface AiStockJudgement {
387
428
  shun?: readonly string[];
388
429
  /** Words a hit's first tags never carry unless the subject or the brief names them ({@link AiStockSiteTerms.shunLead}). */
389
430
  shunLead?: readonly string[];
431
+ /** Words a hit never carries, whatever the brief names ({@link AiStockSearch.refuse}). */
432
+ refuse?: readonly string[];
433
+ /** Stems of which a hit names one ({@link AiStockSearch.needs}). */
434
+ needs?: readonly string[];
390
435
  }
391
436
  /**
392
437
  * Whether a hit carries a topic its site never named ({@link SENSITIVE_TOPICS}):
@@ -423,11 +468,14 @@ export declare function aiStockPlacedSrcs(nodes: NodesMap | null | undefined): s
423
468
  /** Forgets every job's placed photos; for specs. */
424
469
  export declare function aiStockForgetJobPhotos(): void;
425
470
  /**
426
- * A photo described from its own tags (AGL-3856): its first few that name a
427
- * thing, a phrase another one holds dropped ("wedding" beside "wedding
428
- * dress"), as an English phrase — "A wedding dress and a bride", "A hammer,
429
- * books and law" — never the comma-separated list the library keeps. `null`
430
- * where none names a thing.
471
+ * A photo described from its own tags (AGL-3856): a short English phrase of
472
+ * what its first tags show — one or two things, or a thing and where it is,
473
+ * one person at most — never the library's comma-separated list: "A train at
474
+ * a station", "A confident lawyer in court", "A portrait of a businessman",
475
+ * "A board and chalk". A tag of how it looks is said before the thing it
476
+ * qualifies; an idea ("law", "feedback") is left out; a word inside another
477
+ * ("law" of "lawyer", "man" of "businessman") gives way to it; a mass noun
478
+ * takes no article. `null` where no tag names a thing.
431
479
  */
432
480
  export declare function aiStockTagsAlt(tags: readonly string[], proper?: ReadonlySet<string>): string | null;
433
481
  /**
@@ -455,7 +503,8 @@ export declare function aiStockTagsAlt(tags: readonly string[], proper?: Readonl
455
503
  * description, and are never kept. Otherwise the photo is described by the
456
504
  * library's own words: its description where it writes one (a Pexels hit's
457
505
  * `alt`), else its first tags as an English phrase ({@link aiStockTagsAlt}),
458
- * never the library's tag list. The libraries write in English, and no model
506
+ * never the library's tag list, and where no tag names a thing, the slot's
507
+ * own subject: its words, else its section's name. The libraries write in English, and no model
459
508
  * translates them, so a site in another language takes the platform's own
460
509
  * words for an illustrative photo in its language (`aiLayoutLabel`), true of
461
510
  * any photo, as does a hit whose words name no thing.
@@ -491,6 +540,20 @@ export interface AiLayoutStockPhotoSourceInput {
491
540
  * gave no photo words, rather than its business type in its own language.
492
541
  */
493
542
  kindWords?: string;
543
+ /**
544
+ * The business's name, as the person typed it (AGL-3856): what an English
545
+ * site is searched by when its business type names no world ("a local
546
+ * service business") and its name names a craft this module lists
547
+ * ("Synchronicity Gym"). Never its world otherwise.
548
+ */
549
+ name?: string;
550
+ /** Who the site is for, as the person typed it: searched as the name is, after it (AGL-3856). */
551
+ audience?: string;
552
+ /**
553
+ * The id of the kind of site the person picked ("education"): what a site
554
+ * is searched by when nothing else names its world (AGL-3856).
555
+ */
556
+ kind?: string;
494
557
  /** The page's section names, by plan index. */
495
558
  sectionNames: readonly string[];
496
559
  /**
@@ -510,13 +573,14 @@ export interface AiLayoutStockPhotoDeps {
510
573
  budgetMs?: number;
511
574
  }
512
575
  /**
513
- * A job's language and English photo words (AGL-3760), and the English name
514
- * of its kind of site (AGL-3771), as a stock photo source takes them.
576
+ * A job's language and English photo words (AGL-3760), the English name of
577
+ * its kind of site (AGL-3771), and the business's name and audience as the
578
+ * person typed them (AGL-3856), as a stock photo source takes them.
515
579
  */
516
580
  export declare function aiStockPhotoWordsOf(job: {
517
581
  plan?: Pick<AiBuildPlan, 'language' | 'photoWords'> | null;
518
582
  inputs?: Readonly<Record<string, unknown>> | null;
519
- }): Pick<AiLayoutStockPhotoSourceInput, 'language' | 'photoWords' | 'kindWords'>;
583
+ }): Pick<AiLayoutStockPhotoSourceInput, 'language' | 'photoWords' | 'kindWords' | 'name' | 'audience' | 'kind'>;
520
584
  /**
521
585
  * The subject a plan's photo words lead with (AGL-3769): its first word that
522
586
  * is not filler, with the place or person words that follow it — "bakery" of
@@ -537,7 +601,23 @@ export declare function aiStockPhotoWordsSubject(photoWords: string): string;
537
601
  * every slot of every source — hero, background, gallery, card, product,
538
602
  * post — so no slot searches by words another slot is held against.
539
603
  */
540
- export declare function aiStockSourceTerms(input: Pick<AiLayoutStockPhotoSourceInput, 'business' | 'language' | 'photoWords' | 'kindWords'>): AiStockSiteTerms;
604
+ export declare function aiStockSourceTerms(input: Pick<AiLayoutStockPhotoSourceInput, 'business' | 'language' | 'photoWords' | 'kindWords' | 'name' | 'audience' | 'kind'>): AiStockSiteTerms;
605
+ /**
606
+ * Whether a business type is only an abbreviation the libraries do not know
607
+ * (AGL-3856): "LMS", "CRM", "B2B". Its letters are no world to search.
608
+ */
609
+ export declare function aiStockIsAbbreviation(businessType: string): boolean;
610
+ /** The kind of site a business's name or audience names ({@link NAMED_KINDS}), or empty. */
611
+ export declare function aiStockNamedKind(text: string): string;
612
+ /** What a kind of site's pictures are searched and judged by ({@link KIND_SUBJECTS}); `null` for a kind not listed. */
613
+ export declare function aiStockKindTerms(kind: string): AiStockSiteTerms | null;
614
+ /**
615
+ * The first word of a text that names a craft {@link CRAFT_KIN} lists, as
616
+ * its table writes it: "gym" of "Synchronicity Gym", "law" of "Hartwell
617
+ * Reyes Family Law". Empty where it names none, so a name that is only a
618
+ * name ("Hillside") never becomes a world.
619
+ */
620
+ export declare function aiStockListedCraft(text: string): string;
541
621
  /**
542
622
  * The source for one page, or `null` when this deployment has no stock
543
623
  * photo library or no media door, which leaves every slot to the starters.