@aglyn/plugins-ai 1.0.0-beta.292 → 1.0.0-beta.296
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +17 -17
- package/src/lib/components/ai-job-links.d.ts +15 -2
- package/src/lib/components/ai-job-links.js +24 -3
- package/src/lib/components/ai-job-links.js.map +1 -1
- package/src/lib/components/ai-job-requests.d.ts +9 -0
- package/src/lib/components/ai-job-requests.js +34 -0
- package/src/lib/components/ai-job-requests.js.map +1 -1
- package/src/lib/components/ai-site-build-page.component.js +28 -2
- package/src/lib/components/ai-site-build-page.component.js.map +1 -1
- package/src/lib/components/ai-site-import-job.component.js +5 -4
- package/src/lib/components/ai-site-import-job.component.js.map +1 -1
- package/src/lib/components/ai-site-import-start.component.js +3 -3
- package/src/lib/components/ai-site-import-start.component.js.map +1 -1
- package/src/lib/components/ai-site-start-card.component.d.ts +1 -1
- package/src/lib/components/ai-site-start-card.component.js +129 -29
- package/src/lib/components/ai-site-start-card.component.js.map +1 -1
- package/src/lib/components/ai-site-start-steps.component.d.ts +15 -3
- package/src/lib/components/ai-site-start-steps.component.js +42 -25
- package/src/lib/components/ai-site-start-steps.component.js.map +1 -1
- package/src/lib/components/ai-site-style-previews.d.ts +17 -0
- package/src/lib/components/ai-site-style-previews.js +26 -95
- package/src/lib/components/ai-site-style-previews.js.map +1 -1
- package/src/lib/components/assist-jobs-drawer.component.d.ts +7 -1
- package/src/lib/components/assist-jobs-drawer.component.js +20 -6
- package/src/lib/components/assist-jobs-drawer.component.js.map +1 -1
- package/src/lib/components/assist-page-change-card.component.d.ts +44 -0
- package/src/lib/components/assist-page-change-card.component.js +166 -0
- package/src/lib/components/assist-page-change-card.component.js.map +1 -0
- package/src/lib/components/assist-panel.component.d.ts +105 -1
- package/src/lib/components/assist-panel.component.js +224 -29
- package/src/lib/components/assist-panel.component.js.map +1 -1
- package/src/lib/declarations.server.js +22 -0
- package/src/lib/declarations.server.js.map +1 -1
- package/src/lib/jobs/ai-job-edit-step.d.ts +62 -16
- package/src/lib/jobs/ai-job-edit-step.js +172 -61
- package/src/lib/jobs/ai-job-edit-step.js.map +1 -1
- package/src/lib/jobs/ai-job-import-step.d.ts +21 -2
- package/src/lib/jobs/ai-job-import-step.js +179 -49
- package/src/lib/jobs/ai-job-import-step.js.map +1 -1
- package/src/lib/jobs/ai-job-layout-language.d.ts +27 -3
- package/src/lib/jobs/ai-job-layout-language.js +156 -113
- package/src/lib/jobs/ai-job-layout-language.js.map +1 -1
- package/src/lib/jobs/ai-job-layout-step.js +56 -17
- package/src/lib/jobs/ai-job-layout-step.js.map +1 -1
- package/src/lib/jobs/ai-job-navigation-step.js +4 -2
- package/src/lib/jobs/ai-job-navigation-step.js.map +1 -1
- package/src/lib/jobs/ai-job-page-language.d.ts +25 -15
- package/src/lib/jobs/ai-job-page-language.js +120 -66
- package/src/lib/jobs/ai-job-page-language.js.map +1 -1
- package/src/lib/jobs/ai-job-page-step.js +27 -7
- package/src/lib/jobs/ai-job-page-step.js.map +1 -1
- package/src/lib/jobs/ai-job-site-datasets.d.ts +12 -4
- package/src/lib/jobs/ai-job-site-datasets.js +36 -16
- package/src/lib/jobs/ai-job-site-datasets.js.map +1 -1
- package/src/lib/jobs/ai-jobs.js +6 -2
- package/src/lib/jobs/ai-jobs.js.map +1 -1
- package/src/lib/jobs/ai-layout-stock-photos.d.ts +50 -1
- package/src/lib/jobs/ai-layout-stock-photos.js +586 -35
- package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -1
- package/src/lib/jobs/ai-site-import-compile.d.ts +147 -0
- package/src/lib/jobs/ai-site-import-compile.js +1143 -0
- package/src/lib/jobs/ai-site-import-compile.js.map +1 -0
- package/src/lib/jobs/ai-site-import-document.d.ts +9 -36
- package/src/lib/jobs/ai-site-import-document.js +23 -489
- package/src/lib/jobs/ai-site-import-document.js.map +1 -1
- package/src/lib/jobs/ai-site-import-look.d.ts +54 -7
- package/src/lib/jobs/ai-site-import-look.js +163 -52
- package/src/lib/jobs/ai-site-import-look.js.map +1 -1
- package/src/lib/jobs/ai-site-import-publish.d.ts +7 -1
- package/src/lib/jobs/ai-site-import-publish.js +19 -5
- package/src/lib/jobs/ai-site-import-publish.js.map +1 -1
- package/src/lib/jobs/ai-site-late-photos.js +4 -2
- package/src/lib/jobs/ai-site-late-photos.js.map +1 -1
- package/src/lib/jobs/ai-site-publish.d.ts +10 -1
- package/src/lib/jobs/ai-site-publish.js +8 -3
- package/src/lib/jobs/ai-site-publish.js.map +1 -1
- package/src/lib/jobs/fixtures/ai-stock-photo-agl4092-1029-recordings.d.ts +23 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl4092-1029-recordings.js +677 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl4092-1029-recordings.js.map +1 -0
- package/src/lib/layout-language/ai-layout-compiler.d.ts +26 -0
- package/src/lib/layout-language/ai-layout-compiler.js +677 -33
- package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
- package/src/lib/layout-language/ai-layout-frame-hollows.js +5 -1
- package/src/lib/layout-language/ai-layout-frame-hollows.js.map +1 -1
- package/src/lib/layout-language/ai-layout-frame-source.d.ts +196 -0
- package/src/lib/layout-language/ai-layout-frame-source.js +726 -0
- package/src/lib/layout-language/ai-layout-frame-source.js.map +1 -0
- package/src/lib/layout-language/ai-layout-frame.d.ts +22 -0
- package/src/lib/layout-language/ai-layout-frame.js +121 -29
- package/src/lib/layout-language/ai-layout-frame.js.map +1 -1
- package/src/lib/layout-language/ai-layout-language.d.ts +103 -37
- package/src/lib/layout-language/ai-layout-language.js +85 -120
- package/src/lib/layout-language/ai-layout-language.js.map +1 -1
- package/src/lib/model/ai-credit-estimate.d.ts +11 -7
- package/src/lib/model/ai-credit-estimate.js +11 -7
- package/src/lib/model/ai-credit-estimate.js.map +1 -1
- package/src/lib/model/ai-edit-job.d.ts +33 -16
- package/src/lib/model/ai-edit-job.js +50 -34
- package/src/lib/model/ai-edit-job.js.map +1 -1
- package/src/lib/model/ai-job-activity.d.ts +6 -11
- package/src/lib/model/ai-job-activity.js +8 -15
- package/src/lib/model/ai-job-activity.js.map +1 -1
- package/src/lib/model/ai-jobs.types.d.ts +6 -0
- package/src/lib/model/ai-jobs.types.js.map +1 -1
- package/src/lib/model/ai-site-import.d.ts +307 -13
- package/src/lib/model/ai-site-import.js +227 -19
- package/src/lib/model/ai-site-import.js.map +1 -1
- package/src/lib/model/ai-site-inventory.d.ts +6 -0
- package/src/lib/model/ai-site-inventory.js.map +1 -1
- package/src/lib/model/ai-site-look.d.ts +65 -1
- package/src/lib/model/ai-site-look.js +141 -23
- package/src/lib/model/ai-site-look.js.map +1 -1
- package/src/lib/model/ai-site-photos.d.ts +2 -0
- package/src/lib/model/ai-site-photos.js.map +1 -1
- package/src/lib/model/ai-site-start-steps.d.ts +4 -3
- package/src/lib/model/ai-site-start-steps.js +11 -3
- package/src/lib/model/ai-site-start-steps.js.map +1 -1
- package/src/lib/model/ai-site-start.d.ts +23 -2
- package/src/lib/model/ai-site-start.js +25 -3
- package/src/lib/model/ai-site-start.js.map +1 -1
- package/src/lib/model/assist-edit.d.ts +18 -1
- package/src/lib/model/assist-edit.js +7 -0
- package/src/lib/model/assist-edit.js.map +1 -1
- package/src/lib/model/assist-page-change.d.ts +86 -0
- package/src/lib/model/assist-page-change.js +86 -0
- package/src/lib/model/assist-page-change.js.map +1 -0
- package/src/lib/providers/routing.d.ts +11 -0
- package/src/lib/providers/routing.js +23 -0
- package/src/lib/providers/routing.js.map +1 -1
- package/src/lib/runtime/ai-doctrine-validators.d.ts +4 -2
- package/src/lib/runtime/ai-doctrine-validators.js +7 -2
- package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
- package/src/lib/runtime/ai-eval.js +3 -1
- package/src/lib/runtime/ai-eval.js.map +1 -1
- package/src/lib/runtime/ai-icon-library.d.ts +4 -0
- package/src/lib/runtime/ai-icon-library.js +4 -0
- package/src/lib/runtime/ai-icon-library.js.map +1 -1
- package/src/lib/runtime/ai-node-tree.d.ts +5 -0
- package/src/lib/runtime/ai-node-tree.js +23 -4
- package/src/lib/runtime/ai-node-tree.js.map +1 -1
- package/src/lib/runtime/ai-palette.d.ts +2 -0
- package/src/lib/runtime/ai-palette.generated.js +19 -3
- package/src/lib/runtime/ai-palette.generated.js.map +1 -1
- package/src/lib/runtime/ai-palette.js +2 -1
- package/src/lib/runtime/ai-palette.js.map +1 -1
- package/src/lib/runtime/site-inventory.d.ts +8 -1
- package/src/lib/runtime/site-inventory.js +18 -0
- package/src/lib/runtime/site-inventory.js.map +1 -1
- package/src/lib/server/assist-build.js +2 -0
- package/src/lib/server/assist-build.js.map +1 -1
- package/src/lib/server/assist-chat.js +51 -2
- package/src/lib/server/assist-chat.js.map +1 -1
- package/src/lib/server/assist-edit.d.ts +54 -2
- package/src/lib/server/assist-edit.js +219 -30
- package/src/lib/server/assist-edit.js.map +1 -1
- package/src/lib/server/assist-page-change.d.ts +62 -0
- package/src/lib/server/assist-page-change.js +140 -0
- package/src/lib/server/assist-page-change.js.map +1 -0
- package/src/lib/site-import/fixtures/site-layout-recordings.d.ts +50 -0
- package/src/lib/site-import/fixtures/site-layout-recordings.js +86 -0
- package/src/lib/site-import/fixtures/site-layout-recordings.js.map +1 -0
- package/src/lib/site-import/site-import-crawl.d.ts +18 -1
- package/src/lib/site-import/site-import-crawl.js +70 -10
- package/src/lib/site-import/site-import-crawl.js.map +1 -1
- package/src/lib/site-import/site-import-css.d.ts +110 -0
- package/src/lib/site-import/site-import-css.js +826 -0
- package/src/lib/site-import/site-import-css.js.map +1 -0
- package/src/lib/site-import/site-import-html.d.ts +116 -1
- package/src/lib/site-import/site-import-html.js +538 -46
- package/src/lib/site-import/site-import-html.js.map +1 -1
- package/src/lib/site-import/site-import-layout.d.ts +79 -0
- package/src/lib/site-import/site-import-layout.js +1608 -0
- package/src/lib/site-import/site-import-layout.js.map +1 -0
- package/src/lib/site-import/site-import-nav.d.ts +40 -0
- package/src/lib/site-import/site-import-nav.js +437 -0
- package/src/lib/site-import/site-import-nav.js.map +1 -0
- package/src/lib/site-import/site-import-page.d.ts +8 -1
- package/src/lib/site-import/site-import-page.js +24 -2
- package/src/lib/site-import/site-import-page.js.map +1 -1
- package/src/lib/assets/site-styles/beauty.webp +0 -0
- package/src/lib/assets/site-styles/blog.webp +0 -0
- package/src/lib/assets/site-styles/business.webp +0 -0
- package/src/lib/assets/site-styles/coming-soon.webp +0 -0
- package/src/lib/assets/site-styles/education.webp +0 -0
- package/src/lib/assets/site-styles/events.webp +0 -0
- package/src/lib/assets/site-styles/fitness.webp +0 -0
- package/src/lib/assets/site-styles/landing.webp +0 -0
- package/src/lib/assets/site-styles/music.webp +0 -0
- package/src/lib/assets/site-styles/nonprofit.webp +0 -0
- package/src/lib/assets/site-styles/personal.webp +0 -0
- package/src/lib/assets/site-styles/photography.webp +0 -0
- package/src/lib/assets/site-styles/portfolio.webp +0 -0
- package/src/lib/assets/site-styles/professional.webp +0 -0
- package/src/lib/assets/site-styles/realestate.webp +0 -0
- package/src/lib/assets/site-styles/restaurant.webp +0 -0
- package/src/lib/assets/site-styles/store.webp +0 -0
- package/src/lib/assets/site-styles/studio.webp +0 -0
- package/src/lib/assets/site-styles/trades.webp +0 -0
- package/src/lib/assets/site-styles/wellness.webp +0 -0
- package/src/lib/assets/site-styles/yoga.webp +0 -0
- package/src/lib/site-import/site-import-review.d.ts +0 -40
- package/src/lib/site-import/site-import-review.js +0 -149
- package/src/lib/site-import/site-import-review.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-job-layout-step.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { throwIfAiJobCanceled } from './ai-job-cancel'\nimport { aiSiteStyleTokens } from '../model/ai-site-kinds'\nimport { CANVAS_ROOT_ELEMENT_ID } from '@aglyn/aglyn/foundation/constants/canvas'\nimport type { AglynOrgBilling } from '@aglyn/aglyn/foundation/definitions/org-billing.types'\nimport { duplicateResource } from '@aglyn/tenant-data-admin/server/duplicate-resource'\nimport type { AiJob, AiJobOutput, AiJobPlan, AiJobReview } from '../model/ai-jobs.types'\nimport { aiHomeScreenIds, type AiSiteInventory } from '../model/ai-site-inventory'\nimport { AI_STEP_TIERS } from '../providers/catalog'\nimport { AI_ROUTING_TABLE, aiModelForStep } from '../providers/routing'\nimport {\n aiDoctrineTreeTool,\n runValidatedGeneration,\n type AiValidatedTree,\n} from '../runtime/ai-doctrine'\nimport {\n walkTree,\n type AiDoctrineNode,\n type AiDoctrineTree,\n type AiDoctrineViolation,\n} from '../runtime/ai-doctrine-validators'\nimport type { AiLoadEstimate } from '../runtime/ai-palette'\nimport type { AiSystemBlock } from '../runtime/ai-runtime'\nimport { readSiteInventory } from '../runtime/site-inventory'\nimport { registerAiJobAdmission, type AiJobAdmission } from './ai-job-admission'\nimport {\n aiBuildingPlanCreations,\n aiJobPlanCreationsRefusal,\n aiPlanCreationsRunMinimumMs,\n} from './ai-job-plan-creations'\nimport { aiJobDraftId, aiOriginJobId } from './ai-job-draft-ids'\nimport {\n aiDraftAdmissionRefusal,\n aiDraftAllowanceRefusal,\n aiSiteSubdomain,\n readAiDraft,\n readAiDraftNodes,\n writeAiDraft,\n type AiDraftRecord,\n} from './ai-job-drafts'\nimport {\n aiBracketedFactsNote,\n aiCopySourceLines,\n aiConfirmedPlan,\n aiDoctrineReview,\n aiGenerationSpent,\n aiJobBriefLine,\n aiLimitReview,\n aiModelNodeIds,\n aiPlacedComponentIds,\n aiPlanCreation,\n aiPlanReferenceLines,\n aiPlanReuseViolations,\n aiUnspentOutcome,\n} from './ai-job-generation'\nimport { aiPlanRegionViolations, aiPlannedLayoutRegions } from './ai-job-plan-conformance'\nimport { aiLayoutSitePages, aiLayoutSitePagesLines, aiLayoutWithSitePages } from './ai-job-layout-site-pages'\nimport { aiLayoutInventedContactViolations, aiLayoutWithSiteName } from './ai-layout-site-facts'\nimport { aiLayoutWithFullHeight } from './ai-layout-full-height'\nimport type { AiJobStepRunner } from './ai-job-text-step'\nimport { AI_LAYOUT_FRAME_TOOL } from '../layout-language/ai-layout-language'\nimport {\n AI_JOB_LAYOUT_LANGUAGE_BUDGET,\n AI_LAYOUT_FRAME_KIND,\n aiJobLayoutLanguageInstructions,\n aiLayoutFrameCheck,\n aiLayoutFramePrompt,\n aiLayoutFrameTargets,\n aiLayoutHomeId,\n aiLayoutNavPages,\n aiLayoutSiteBrandOf,\n aiLayoutSiteFactsText,\n aiLayoutSiteName,\n type AiLayoutFrameBuilt,\n} from './ai-job-layout-language'\nimport { AI_LAYOUT_LANGUAGE_THINKING, aiJobUsesLayoutLanguage, aiLayoutDesignOf } from './ai-job-page-language'\nimport { aiJobStepBudget } from './ai-job-budget'\nimport { registerAiJobStep } from './ai-jobs'\nimport { aiStoreFrameLinksOf } from '../model/ai-site-store-pages'\n\n/**\n * The layout step (AGL-2909): the generation step of a `layout` job, run once\n * a member confirmed the job's plan.\n *\n * It builds ONE shared layout — a header with the site's navigation, the\n * Layout Slot each page renders in, a footer — through\n * `runValidatedGeneration('layout', …)`, so every building rule holds on the\n * tree before it is kept, and adds three checks of its own through `extend`: a\n * component the confirmed plan reuses is placed (rule 7), every region the\n * plan gives the layout is built (AGL-3024), and a navigation or menu\n * component the site already has is placed rather than drawn again (rule 1).\n *\n * The layout lands as a new draft (`ai-job-drafts.ts`): no screen uses it and\n * no layout nests it, so nothing on the live site changes until a member\n * assigns it. A plan that starts from a copy of a layout the site has gets\n * that copy, through the platform's duplicate module, and nothing generated —\n * so the copy is read back and held to the plan's regions the same way\n * (`aiCopiedLayoutReview`), because a branch that generates nothing is the one\n * branch where a promise can go unmet with no model to answer for it. A\n * source that already lacks a region the plan gives the layout is not copied\n * at all: the layout is built from it (AGL-3143 §14).\n *\n * A generation step runs on the job beat, never at an inline door: it\n * registers the least time its lookup rounds, its answer and its re-ask need\n * (AGL-3035), runs without extended thinking — the plan was reasoned out and\n * confirmed before it — and asks for no more of a tighter ceiling than the\n * doctrine's default for a layout than fits that time on the model it runs.\n */\n\n/** The longest answer a layout may run to; the tree is held to the layout budget either way. */\nexport const AI_JOB_LAYOUT_MAX_TOKENS = AI_ROUTING_TABLE['job.layout'].maxTokens\n\n/**\n * The layout step's time (AGL-3035, AGL-3036): its two inventory-lookup\n * rounds, its answer and its re-ask at the routing table's ceiling on the tier\n * `job.layout` is served from, fitted to what a beat can give a step.\n */\nexport const AI_JOB_LAYOUT_STEP_BUDGET = aiJobStepBudget({\n tier: AI_STEP_TIERS['job.layout'],\n maxTokens: AI_JOB_LAYOUT_MAX_TOKENS,\n})\n\n/** The least time one layout step needs before it starts. */\nexport const AI_JOB_LAYOUT_STEP_MINIMUM_MS = AI_JOB_LAYOUT_STEP_BUDGET.minimumMs\n\n/** A layout's name when the plan names none. */\nexport const AI_JOB_LAYOUT_DEFAULT_NAME = 'Site layout'\n\n/** The layout step's own instructions, cached after the doctrine. */\nexport const AI_JOB_LAYOUT_INSTRUCTIONS: readonly AiSystemBlock[] = [\n {\n text: [\n 'You build one shared layout for a website: the frame every page of the site renders inside. Answer with submit_layout: the whole layout as one flat node map.',\n 'A layout is a header, one Layout Slot and a footer, top to bottom. The header is an App Bar (muiAppBar) holding a Toolbar Content (muiToolbar) with the site’s name as text and its navigation. The footer is a Section (section) whose element is footer.',\n 'Navigation links the site’s own pages by id: a Page Link (muiScreenLink) whose screenId is a page id from the site inventory, in the order the brief and the confirmed plan give, seven at most in the header. Never invent a page id, and never link a page by its address.',\n 'When the site inventory lists a component whose name says it is navigation, a menu or a mega menu, place it in the header as an instance instead of building the navigation again. Place every component the confirmed plan reuses.',\n 'The Layout Slot (layoutSlot) is where each page renders and is the page’s main landmark: leave its component unset or main, and put nothing inside it. A layout carries no h1, because every page brings its own.',\n ].join('\\n'),\n },\n]\n\n/**\n * The layout job as the generation's user turn: the name, the brief, the\n * confirmed plan, and the layout a short copy would have started from\n * (`aiCopySourceLines`, AGL-3143 §14).\n */\nexport function aiJobLayoutPrompt(\n job: Pick<AiJob, 'brief'> & Partial<Pick<AiJob, 'inputs'>>,\n plan: AiJobPlan | null,\n name: string,\n source: readonly string[] = [],\n): string {\n return [\n `Layout name: ${name}`,\n aiJobBriefLine(job),\n ...aiPlanReferenceLines(plan),\n // A scaffold's layout is built before its pages, whose navigation the platform writes (AGL-3596).\n ...aiLayoutSitePagesLines(aiLayoutSitePages(job.inputs)),\n ...source,\n ].join('\\n')\n}\n\n/** A component name that says it is the site's navigation; a footer's links are not. */\nconst NAVIGATION_NAME = /\\b(?:nav|navigation|navbar|menu|mega ?menu)\\b/i\nconst FOOTER_NAME = /\\bfooter\\b/i\n\n/** A node that links somewhere: a Screen Link, or a Button pointed at a screen or an address. */\nfunction isLink(node: AiDoctrineNode): boolean {\n if (node.componentId === 'muiScreenLink') return true\n return (\n node.componentId === 'muiButton' &&\n (typeof node.props?.['screenId'] === 'string' || typeof node.props?.['href'] === 'string')\n )\n}\n\n/**\n * The layout door's checks on a tree the doctrine admitted: every component\n * the confirmed plan reuses is placed, every region the confirmed plan gives\n * the layout is built (AGL-3024), and navigation the site already keeps as a\n * component is placed rather than drawn again in the header.\n */\nexport function aiLayoutReuseCheck(\n inventory: AiSiteInventory | null,\n plan: AiJobPlan | null,\n): (tree: AiValidatedTree) => AiDoctrineViolation[] {\n const components = inventory?.components ?? []\n const navigation = components.filter(\n (component) => NAVIGATION_NAME.test(component.name) && !FOOTER_NAME.test(component.name),\n )\n return (tree) => {\n const placed = aiPlacedComponentIds(tree)\n const violations: AiDoctrineViolation[] = [\n ...aiPlanReuseViolations(inventory, plan, placed, 'layout'),\n ...aiPlanRegionViolations(plan, {\n rootId: tree.rootId,\n nodes: tree.nodes as unknown as Record<string, AiDoctrineNode>,\n }),\n ]\n if (navigation.length && !navigation.some((component) => placed.has(component.id))) {\n const visits = walkTree({\n rootId: tree.rootId,\n nodes: tree.nodes as unknown as Record<string, AiDoctrineNode>,\n })\n const slot = visits.findIndex(({ node }) => node.componentId === 'layoutSlot')\n const header = slot === -1 ? visits : visits.slice(0, slot)\n const links = header.filter(({ node }) => isLink(node)).map(({ id }) => id)\n if (links.length >= 2) {\n violations.push({\n rule: 1,\n code: 'navigation-rebuilt',\n message: `The site already has the \"${navigation[0].name}\" component. Place it in the header instead of building the navigation again.`,\n nodeIds: aiModelNodeIds(links, tree.sourceIds),\n })\n }\n }\n return violations\n }\n}\n\n/**\n * Every check the layout door adds to the doctrine's: the reuse and region\n * checks above, and no contact detail the brief does not give (AGL-3596).\n */\nexport function aiLayoutChecks(\n inventory: AiSiteInventory | null,\n plan: AiJobPlan | null,\n brief: string,\n): (tree: AiValidatedTree) => AiDoctrineViolation[] {\n const reuse = aiLayoutReuseCheck(inventory, plan)\n return (tree) => [\n ...reuse(tree),\n ...aiLayoutInventedContactViolations(\n { rootId: tree.rootId, nodes: tree.nodes as unknown as Record<string, AiDoctrineNode> },\n brief,\n ).map((violation) => ({ ...violation, nodeIds: aiModelNodeIds(violation.nodeIds ?? [], tree.sourceIds) })),\n ]\n}\n\n/**\n * The regions the confirmed plan gives the layout, against the layout a COPY\n * actually produced (AGL-3024); `null` when the copy keeps the plan, or when\n * the plan promised no region to keep.\n *\n * The duplicate branch generates nothing, so it is the one place a plan's\n * promise can go unmet without a model ever answering for it. A copy that\n * cannot be read — deleted between the write and this read, or stored under a\n * root this check does not know — settles nothing, and a promise this step\n * cannot settle is reviewed by a person rather than reported as kept.\n */\nexport async function aiCopiedLayoutReview(\n firestore: FirebaseFirestore.Firestore,\n input: { hostId: string; id: string; name: string; plan: AiJobPlan | null },\n): Promise<AiJobReview | null> {\n const planned = aiPlannedLayoutRegions(input.plan)\n if (!planned.regions.length && !planned.unreadable.length) return null\n const stored = await readAiDraftNodes(firestore, {\n kind: 'layout',\n hostId: input.hostId,\n id: input.id,\n })\n const nodes = (stored?.nodes ?? {}) as unknown as Record<string, AiDoctrineNode>\n if (!nodes[CANVAS_ROOT_ELEMENT_ID]) {\n return {\n reason: 'doctrine',\n message: `\"${input.name}\" was copied from the layout the plan names, and this job could not read the copy back to check it has the regions the plan gives it. Open the layout and check it before you put a page in it.`,\n findings: [],\n }\n }\n const violations = aiPlanRegionViolations(input.plan, { rootId: CANVAS_ROOT_ELEMENT_ID, nodes })\n if (!violations.length) return null\n return aiDoctrineReview({\n message: `\"${input.name}\" is a copy of the layout the plan names, and a copy is all it is: ${violations[0].message}`,\n violations,\n })\n}\n\n/**\n * A layout job is admitted for a site of the job's own org with a shared\n * layout to spare, and confirmed only for a plan whose other creations it\n * builds (AGL-3143 §15).\n */\nexport const aiLayoutJobAdmission: AiJobAdmission = (context) =>\n aiDraftAdmissionRefusal(context.firestore, {\n orgId: context.orgId,\n hostId: context.hostId,\n kind: 'layout',\n org: context.org,\n ownCheck: (hostId) => aiJobPlanCreationsRefusal('layout', context, hostId),\n })\n\nexport interface AiJobLayoutStepDeps {\n /** The inventory reader; specs hand in a fake. */\n readInventory?: typeof readSiteInventory\n /** The platform's duplicate module, for a plan that starts from a copy. */\n duplicate?: typeof duplicateResource\n}\n\nexport function createAiJobLayoutStep(deps: AiJobLayoutStepDeps = {}): AiJobStepRunner {\n const readInventory = deps.readInventory ?? readSiteInventory\n const duplicate = deps.duplicate ?? duplicateResource\n return async ({ job, now, signal, firestore, modelFor }) => {\n const hostId = job.hostId\n if (!hostId) throw new Error('a layout job names no site, and its admission refuses one')\n const output = (draft: AiDraftRecord, load?: AiLoadEstimate | null, note?: string | null): AiJobOutput => ({\n resource: 'layout',\n id: draft.id,\n versionId: draft.versionId,\n hostId,\n hostSubdomain: draft.hostSubdomain,\n label: draft.name,\n ...(load ? { load } : {}),\n ...(note ? { note } : {}),\n })\n // The switch's answer for this job, else the routing table's (AGL-2942).\n const model = modelFor?.('job.layout') ?? aiModelForStep('job.layout')\n\n // A run cut off after its draft was written reports that draft, found by the id the job recorded.\n const draftId = aiJobDraftId(job, 'layout')\n const written = await readAiDraft(firestore, { kind: 'layout', hostId, id: draftId })\n if (written) return aiUnspentOutcome(model, { outputs: [output(written)] })\n\n const [inventory, orgSnapshot] = await Promise.all([\n readInventory(job.orgId, hostId, { firestore }),\n firestore.collection('orgs').doc(job.orgId).get(),\n ])\n const org = (orgSnapshot.data() ?? null) as Partial<AglynOrgBilling> | null\n const plan = aiConfirmedPlan(job)\n const creation = aiPlanCreation(plan, 'layout')\n const name = creation?.name || AI_JOB_LAYOUT_DEFAULT_NAME\n\n // The plan starts from a copy of a layout the site has (rule 15): the copy\n // is the draft, and nothing is generated. A source gone since the plan\n // was made is built from the brief instead. A source that cannot keep the\n // plan's regions is built FROM instead (AGL-3143 §14), as the page step\n // builds from a short source: copying it could only end in the review\n // below, and Try again would copy the same thing. Only a source read and\n // found short diverts; one this step cannot read still copies, and the\n // review after the copy answers for it.\n const source = creation?.duplicateOf\n ? inventory.layouts.find((layout) => layout.id === creation.duplicateOf)\n : undefined\n const sourceReview = source\n ? await aiCopiedLayoutReview(firestore, { hostId, id: source.id, plan, name: source.name })\n : null\n const sourceShort = Boolean(sourceReview?.findings.length)\n const sourceTree =\n source && sourceShort ? await readAiDraftNodes(firestore, { kind: 'layout', hostId, id: source.id }) : null\n const sourceLines =\n source && sourceShort ? aiCopySourceLines('layout', source.name, sourceTree?.nodes ?? null) : []\n if (creation?.duplicateOf && source && !sourceShort) {\n const copy = await duplicate('layout', {\n orgId: job.orgId,\n hostId,\n sourceId: creation.duplicateOf,\n name,\n uid: job.createdBy,\n org: org as Record<string, unknown> | null,\n // The same claim the page step makes (AGL-3024): a copy core mints is\n // written under core's own id, never `draftId`, so a step that runs\n // again — a pass resumed, a run cut off after the copy — would mint a\n // second. The job's recorded id makes core replay the one it made.\n attemptKey: draftId,\n })\n if (copy.ok) {\n // A copy is not a build (AGL-3024). This branch generates nothing, so\n // whatever the plan promised BEYOND the source is not in the draft\n // unless the source already had it: a plan reading \"from a copy of the\n // base layout, adding a sidebar\" gets the base layout, the sidebar\n // nowhere in it, and until now reported Done. The copy's own regions\n // answer the plan's, and a copy that cannot be read answers nothing —\n // which is a stop for a person, never a Done.\n const review = await aiCopiedLayoutReview(firestore, { hostId, id: copy.id, plan, name })\n if (review) return aiUnspentOutcome(model, { review })\n const hostSubdomain = await aiSiteSubdomain(firestore, hostId)\n return aiUnspentOutcome(model, {\n outputs: [output({ id: copy.id, versionId: copy.versionId, name: copy.name, hostSubdomain })],\n })\n }\n if (copy.ok === false && copy.status === 403) {\n return aiUnspentOutcome(model, { review: aiLimitReview(copy.error) })\n }\n }\n\n const allowance = await aiDraftAllowanceRefusal(firestore, { kind: 'layout', hostId, org })\n if (allowance) return aiUnspentOutcome(model, { review: aiLimitReview(allowance) })\n\n if (aiJobUsesLayoutLanguage(job)) {\n // ── The header and footer designed in the layout language (AGL-3660) ──\n const siteName = aiLayoutSiteName(job)\n const pages = aiLayoutNavPages(job, inventory)\n const targets = aiLayoutFrameTargets(job, inventory)\n const result = await runValidatedGeneration<AiLayoutFrameBuilt>(AI_LAYOUT_FRAME_KIND, {\n step: 'job.layout',\n model,\n instructions: aiJobLayoutLanguageInstructions(job),\n inventory,\n messages: [{ role: 'user', content: aiLayoutFramePrompt({ job, siteName, pages, targets }) }],\n tool: AI_LAYOUT_FRAME_TOOL,\n maxTokens: AI_JOB_LAYOUT_LANGUAGE_BUDGET.maxTokens(model),\n ...AI_LAYOUT_LANGUAGE_THINKING,\n check: aiLayoutFrameCheck({\n ...aiSiteStyleTokens(job.inputs),\n siteName,\n homeId: aiLayoutHomeId(pages, inventory),\n pages,\n targets,\n // A site brought in may state what its own header and footer state (AGL-4084).\n extend: aiLayoutChecks(inventory, plan, [job.brief, aiLayoutSiteFactsText(job.inputs)].filter(Boolean).join('\\n')),\n design: aiLayoutDesignOf(job, '/'),\n brand: aiLayoutSiteBrandOf(job.inputs),\n storeLinks: aiStoreFrameLinksOf(job.inputs),\n // The frame's own words in the site's language (AGL-3760).\n ...(job.plan?.language ? { language: job.plan.language } : {}),\n }),\n ...(signal ? { signal } : {}),\n })\n const spent = aiGenerationSpent(result)\n if (result.status === 'refused') return { ...spent, refused: true }\n if (result.status === 'needs_input') return { ...spent, review: aiDoctrineReview(result) }\n // Never written once the job is canceled (AGL-3616).\n throwIfAiJobCanceled(signal)\n const draft = await writeAiDraft(firestore, {\n kind: 'layout',\n hostId,\n id: draftId,\n uid: job.createdBy,\n org,\n name,\n nodes: result.value.nodes,\n aiJobId: aiOriginJobId(job),\n now,\n })\n if (draft.ok === false) {\n if (draft.status === 404) throw new Error(`site ${hostId} vanished while its layout was generated`)\n return { ...spent, review: aiLimitReview(draft.error) }\n }\n const note = aiBracketedFactsNote({\n tree: { rootId: result.value.rootId, nodes: result.value.nodes as unknown as AiDoctrineTree['nodes'] },\n inventory,\n })\n return { ...spent, outputs: [output(draft, result.value.load, note)] }\n }\n\n // The pages a site scaffold builds after this layout (AGL-3596): their\n // ids are the plan's, so the header links them by id, written by the\n // platform before the doctrine checks the tree.\n const sitePages = aiLayoutSitePages(job.inputs)\n const result = await runValidatedGeneration('layout', {\n step: 'job.layout',\n model,\n instructions: AI_JOB_LAYOUT_INSTRUCTIONS,\n inventory,\n messages: [{ role: 'user', content: aiJobLayoutPrompt(job, plan, name, sourceLines) }],\n tool: aiDoctrineTreeTool('layout'),\n maxTokens: AI_JOB_LAYOUT_STEP_BUDGET.maxTokens(model),\n ...(AI_ROUTING_TABLE['job.layout'].thinking ? { thinking: AI_ROUTING_TABLE['job.layout'].thinking } : {}),\n ...(AI_ROUTING_TABLE['job.layout'].effort ? { effort: AI_ROUTING_TABLE['job.layout'].effort } : {}),\n extend: aiLayoutChecks(inventory, plan, job.brief),\n // The site's name is written as the token that reads it, and the\n // layout fills the window so a short page keeps its footer at the\n // bottom (AGL-3596).\n complete: (tree: unknown) =>\n aiLayoutWithFullHeight(\n aiLayoutWithSiteName(\n sitePages.length ? aiLayoutWithSitePages(tree, sitePages, { homeScreenIds: aiHomeScreenIds(inventory) }) : tree,\n typeof job.inputs?.['businessName'] === 'string' ? job.inputs['businessName'] : null,\n ),\n ),\n ...(sitePages.length\n ? { context: { screenIds: [...inventory.screens.map((screen) => screen.id), ...sitePages.map((page) => page.id)] } }\n : {}),\n ...(signal ? { signal } : {}),\n })\n const spent = aiGenerationSpent(result)\n if (result.status === 'refused') return { ...spent, refused: true }\n if (result.status === 'needs_input') return { ...spent, review: aiDoctrineReview(result) }\n\n // Never written once the job is canceled (AGL-3616).\n throwIfAiJobCanceled(signal)\n const draft = await writeAiDraft(firestore, {\n kind: 'layout',\n hostId,\n id: draftId,\n uid: job.createdBy,\n org,\n name,\n nodes: result.value.nodes,\n aiJobId: aiOriginJobId(job),\n now,\n })\n if (draft.ok === false) {\n if (draft.status === 404) throw new Error(`site ${hostId} vanished while its layout was generated`)\n return { ...spent, review: aiLimitReview(draft.error) }\n }\n // The facts the brief did not give, which the member fills before publishing (AGL-3056).\n const note = aiBracketedFactsNote({\n tree: { rootId: result.value.rootId, nodes: result.value.nodes as unknown as AiDoctrineTree['nodes'] },\n inventory,\n })\n return { ...spent, outputs: [output(draft, result.value.load, note)] }\n }\n}\n\n/** The layout step, building the components and forms its plan creates before the layout (AGL-3143 §15). */\nexport const runAiJobLayoutStep = aiBuildingPlanCreations('layout', 'job.layout', createAiJobLayoutStep())\n\n/** Registers the layout step and the check a layout job passes before it is created or resumed. */\nexport function registerAiLayoutJob(): void {\n registerAiJobStep('layout', runAiJobLayoutStep, {\n minimumMs: AI_JOB_LAYOUT_STEP_MINIMUM_MS,\n minimumMsFor: aiPlanCreationsRunMinimumMs('layout'),\n })\n registerAiJobAdmission('layout', aiLayoutJobAdmission)\n}\n"],"names":["throwIfAiJobCanceled","aiSiteStyleTokens","CANVAS_ROOT_ELEMENT_ID","duplicateResource","aiHomeScreenIds","AI_STEP_TIERS","AI_ROUTING_TABLE","aiModelForStep","aiDoctrineTreeTool","runValidatedGeneration","walkTree","readSiteInventory","registerAiJobAdmission","aiBuildingPlanCreations","aiJobPlanCreationsRefusal","aiPlanCreationsRunMinimumMs","aiJobDraftId","aiOriginJobId","aiDraftAdmissionRefusal","aiDraftAllowanceRefusal","aiSiteSubdomain","readAiDraft","readAiDraftNodes","writeAiDraft","aiBracketedFactsNote","aiCopySourceLines","aiConfirmedPlan","aiDoctrineReview","aiGenerationSpent","aiJobBriefLine","aiLimitReview","aiModelNodeIds","aiPlacedComponentIds","aiPlanCreation","aiPlanReferenceLines","aiPlanReuseViolations","aiUnspentOutcome","aiPlanRegionViolations","aiPlannedLayoutRegions","aiLayoutSitePages","aiLayoutSitePagesLines","aiLayoutWithSitePages","aiLayoutInventedContactViolations","aiLayoutWithSiteName","aiLayoutWithFullHeight","AI_LAYOUT_FRAME_TOOL","AI_JOB_LAYOUT_LANGUAGE_BUDGET","AI_LAYOUT_FRAME_KIND","aiJobLayoutLanguageInstructions","aiLayoutFrameCheck","aiLayoutFramePrompt","aiLayoutFrameTargets","aiLayoutHomeId","aiLayoutNavPages","aiLayoutSiteBrandOf","aiLayoutSiteFactsText","aiLayoutSiteName","AI_LAYOUT_LANGUAGE_THINKING","aiJobUsesLayoutLanguage","aiLayoutDesignOf","aiJobStepBudget","registerAiJobStep","aiStoreFrameLinksOf","AI_JOB_LAYOUT_MAX_TOKENS","maxTokens","AI_JOB_LAYOUT_STEP_BUDGET","tier","AI_JOB_LAYOUT_STEP_MINIMUM_MS","minimumMs","AI_JOB_LAYOUT_DEFAULT_NAME","AI_JOB_LAYOUT_INSTRUCTIONS","text","join","aiJobLayoutPrompt","job","plan","name","source","inputs","NAVIGATION_NAME","FOOTER_NAME","isLink","node","componentId","props","aiLayoutReuseCheck","inventory","components","navigation","filter","component","test","tree","placed","violations","rootId","nodes","length","some","has","id","visits","slot","findIndex","header","slice","links","map","push","rule","code","message","nodeIds","sourceIds","aiLayoutChecks","brief","reuse","violation","aiCopiedLayoutReview","firestore","input","planned","regions","unreadable","stored","kind","hostId","reason","findings","aiLayoutJobAdmission","context","orgId","org","ownCheck","createAiJobLayoutStep","deps","readInventory","duplicate","now","signal","modelFor","orgSnapshot","Error","output","draft","load","note","resource","versionId","hostSubdomain","label","model","draftId","written","outputs","Promise","all","collection","doc","get","data","creation","duplicateOf","layouts","find","layout","undefined","sourceReview","sourceShort","Boolean","sourceTree","sourceLines","copy","sourceId","uid","createdBy","attemptKey","ok","review","status","error","allowance","siteName","pages","targets","result","step","instructions","messages","role","content","tool","check","homeId","extend","design","brand","storeLinks","language","spent","refused","value","aiJobId","sitePages","thinking","effort","complete","homeScreenIds","screenIds","screens","screen","page","runAiJobLayoutStep","registerAiLayoutJob","minimumMsFor"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-job-layout-step.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { throwIfAiJobCanceled } from './ai-job-cancel'\nimport { aiSiteStyleTokens } from '../model/ai-site-kinds'\nimport { CANVAS_ROOT_ELEMENT_ID } from '@aglyn/aglyn/foundation/constants/canvas'\nimport type { AglynOrgBilling } from '@aglyn/aglyn/foundation/definitions/org-billing.types'\nimport { duplicateResource } from '@aglyn/tenant-data-admin/server/duplicate-resource'\nimport type { AiJob, AiJobOutput, AiJobPlan, AiJobReview } from '../model/ai-jobs.types'\nimport { aiHomeScreenIds, type AiSiteInventory } from '../model/ai-site-inventory'\nimport { AI_STEP_TIERS } from '../providers/catalog'\nimport { AI_ROUTING_TABLE, aiModelForStep } from '../providers/routing'\nimport {\n aiDoctrineTreeTool,\n runValidatedGeneration,\n type AiValidatedTree,\n} from '../runtime/ai-doctrine'\nimport {\n walkTree,\n type AiDoctrineNode,\n type AiDoctrineTree,\n type AiDoctrineViolation,\n} from '../runtime/ai-doctrine-validators'\nimport type { AiLoadEstimate } from '../runtime/ai-palette'\nimport type { AiSystemBlock } from '../runtime/ai-runtime'\nimport { readSiteInventory } from '../runtime/site-inventory'\nimport { registerAiJobAdmission, type AiJobAdmission } from './ai-job-admission'\nimport {\n aiBuildingPlanCreations,\n aiJobPlanCreationsRefusal,\n aiPlanCreationsRunMinimumMs,\n} from './ai-job-plan-creations'\nimport { aiJobDraftId, aiOriginJobId } from './ai-job-draft-ids'\nimport {\n aiDraftAdmissionRefusal,\n aiDraftAllowanceRefusal,\n aiSiteSubdomain,\n readAiDraft,\n readAiDraftNodes,\n writeAiDraft,\n type AiDraftRecord,\n} from './ai-job-drafts'\nimport {\n aiBracketedFactsNote,\n aiCopySourceLines,\n aiConfirmedPlan,\n aiDoctrineReview,\n aiGenerationSpent,\n aiJobBriefLine,\n aiLimitReview,\n aiModelNodeIds,\n aiPlacedComponentIds,\n aiPlanCreation,\n aiPlanReferenceLines,\n aiPlanReuseViolations,\n aiUnspentOutcome,\n} from './ai-job-generation'\nimport { aiPlanRegionViolations, aiPlannedLayoutRegions } from './ai-job-plan-conformance'\nimport { aiLayoutSitePages, aiLayoutSitePagesLines, aiLayoutWithSitePages } from './ai-job-layout-site-pages'\nimport { aiLayoutInventedContactViolations, aiLayoutWithSiteName } from './ai-layout-site-facts'\nimport { aiLayoutWithFullHeight } from './ai-layout-full-height'\nimport type { AiJobStepRunner } from './ai-job-text-step'\nimport { AI_LAYOUT_FRAME_TOOL } from '../layout-language/ai-layout-language'\nimport {\n AI_JOB_LAYOUT_LANGUAGE_BUDGET,\n AI_LAYOUT_FRAME_KIND,\n aiJobLayoutLanguageInstructions,\n aiLayoutFrameCheck,\n aiLayoutFramePrompt,\n aiLayoutFrameTargets,\n aiLayoutHomeId,\n aiLayoutNavPages,\n aiLayoutSiteBrandOf,\n aiLayoutSiteFactsText,\n aiLayoutSiteFrameOf,\n aiLayoutSiteName,\n aiLayoutSourceFrameBuild,\n type AiLayoutFrameBuilt,\n type AiLayoutFrameInput,\n} from './ai-job-layout-language'\nimport { AI_LAYOUT_LANGUAGE_THINKING, aiJobUsesLayoutLanguage, aiLayoutDesignOf } from './ai-job-page-language'\nimport { aiJobStepBudget } from './ai-job-budget'\nimport { registerAiJobStep } from './ai-jobs'\nimport { aiStoreFrameLinksOf } from '../model/ai-site-store-pages'\n\n/**\n * The layout step (AGL-2909): the generation step of a `layout` job, run once\n * a member confirmed the job's plan.\n *\n * It builds ONE shared layout — a header with the site's navigation, the\n * Layout Slot each page renders in, a footer — through\n * `runValidatedGeneration('layout', …)`, so every building rule holds on the\n * tree before it is kept, and adds three checks of its own through `extend`: a\n * component the confirmed plan reuses is placed (rule 7), every region the\n * plan gives the layout is built (AGL-3024), and a navigation or menu\n * component the site already has is placed rather than drawn again (rule 1).\n *\n * The layout lands as a new draft (`ai-job-drafts.ts`): no screen uses it and\n * no layout nests it, so nothing on the live site changes until a member\n * assigns it. A plan that starts from a copy of a layout the site has gets\n * that copy, through the platform's duplicate module, and nothing generated —\n * so the copy is read back and held to the plan's regions the same way\n * (`aiCopiedLayoutReview`), because a branch that generates nothing is the one\n * branch where a promise can go unmet with no model to answer for it. A\n * source that already lacks a region the plan gives the layout is not copied\n * at all: the layout is built from it (AGL-3143 §14).\n *\n * A generation step runs on the job beat, never at an inline door: it\n * registers the least time its lookup rounds, its answer and its re-ask need\n * (AGL-3035), runs without extended thinking — the plan was reasoned out and\n * confirmed before it — and asks for no more of a tighter ceiling than the\n * doctrine's default for a layout than fits that time on the model it runs.\n */\n\n/** The longest answer a layout may run to; the tree is held to the layout budget either way. */\nexport const AI_JOB_LAYOUT_MAX_TOKENS = AI_ROUTING_TABLE['job.layout'].maxTokens\n\n/**\n * The layout step's time (AGL-3035, AGL-3036): its two inventory-lookup\n * rounds, its answer and its re-ask at the routing table's ceiling on the tier\n * `job.layout` is served from, fitted to what a beat can give a step.\n */\nexport const AI_JOB_LAYOUT_STEP_BUDGET = aiJobStepBudget({\n tier: AI_STEP_TIERS['job.layout'],\n maxTokens: AI_JOB_LAYOUT_MAX_TOKENS,\n})\n\n/** The least time one layout step needs before it starts. */\nexport const AI_JOB_LAYOUT_STEP_MINIMUM_MS = AI_JOB_LAYOUT_STEP_BUDGET.minimumMs\n\n/** A layout's name when the plan names none. */\nexport const AI_JOB_LAYOUT_DEFAULT_NAME = 'Site layout'\n\n/** The layout step's own instructions, cached after the doctrine. */\nexport const AI_JOB_LAYOUT_INSTRUCTIONS: readonly AiSystemBlock[] = [\n {\n text: [\n 'You build one shared layout for a website: the frame every page of the site renders inside. Answer with submit_layout: the whole layout as one flat node map.',\n 'A layout is a header, one Layout Slot and a footer, top to bottom. The header is an App Bar (muiAppBar) holding a Toolbar Content (muiToolbar) with the site’s name as text and its navigation. The footer is a Section (section) whose element is footer.',\n 'Navigation links the site’s own pages by id: a Page Link (muiScreenLink) whose screenId is a page id from the site inventory, in the order the brief and the confirmed plan give, seven at most in the header. Never invent a page id, and never link a page by its address.',\n 'When the site inventory lists a component whose name says it is navigation, a menu or a mega menu, place it in the header as an instance instead of building the navigation again. Place every component the confirmed plan reuses.',\n 'The Layout Slot (layoutSlot) is where each page renders and is the page’s main landmark: leave its component unset or main, and put nothing inside it. A layout carries no h1, because every page brings its own.',\n ].join('\\n'),\n },\n]\n\n/**\n * The layout job as the generation's user turn: the name, the brief, the\n * confirmed plan, and the layout a short copy would have started from\n * (`aiCopySourceLines`, AGL-3143 §14).\n */\nexport function aiJobLayoutPrompt(\n job: Pick<AiJob, 'brief'> & Partial<Pick<AiJob, 'inputs'>>,\n plan: AiJobPlan | null,\n name: string,\n source: readonly string[] = [],\n): string {\n return [\n `Layout name: ${name}`,\n aiJobBriefLine(job),\n ...aiPlanReferenceLines(plan),\n // A scaffold's layout is built before its pages, whose navigation the platform writes (AGL-3596).\n ...aiLayoutSitePagesLines(aiLayoutSitePages(job.inputs)),\n ...source,\n ].join('\\n')\n}\n\n/** A component name that says it is the site's navigation; a footer's links are not. */\nconst NAVIGATION_NAME = /\\b(?:nav|navigation|navbar|menu|mega ?menu)\\b/i\nconst FOOTER_NAME = /\\bfooter\\b/i\n\n/** A node that links somewhere: a Screen Link, or a Button pointed at a screen or an address. */\nfunction isLink(node: AiDoctrineNode): boolean {\n if (node.componentId === 'muiScreenLink') return true\n return (\n node.componentId === 'muiButton' &&\n (typeof node.props?.['screenId'] === 'string' || typeof node.props?.['href'] === 'string')\n )\n}\n\n/**\n * The layout door's checks on a tree the doctrine admitted: every component\n * the confirmed plan reuses is placed, every region the confirmed plan gives\n * the layout is built (AGL-3024), and navigation the site already keeps as a\n * component is placed rather than drawn again in the header.\n */\nexport function aiLayoutReuseCheck(\n inventory: AiSiteInventory | null,\n plan: AiJobPlan | null,\n): (tree: AiValidatedTree) => AiDoctrineViolation[] {\n const components = inventory?.components ?? []\n const navigation = components.filter(\n (component) => NAVIGATION_NAME.test(component.name) && !FOOTER_NAME.test(component.name),\n )\n return (tree) => {\n const placed = aiPlacedComponentIds(tree)\n const violations: AiDoctrineViolation[] = [\n ...aiPlanReuseViolations(inventory, plan, placed, 'layout'),\n ...aiPlanRegionViolations(plan, {\n rootId: tree.rootId,\n nodes: tree.nodes as unknown as Record<string, AiDoctrineNode>,\n }),\n ]\n if (navigation.length && !navigation.some((component) => placed.has(component.id))) {\n const visits = walkTree({\n rootId: tree.rootId,\n nodes: tree.nodes as unknown as Record<string, AiDoctrineNode>,\n })\n const slot = visits.findIndex(({ node }) => node.componentId === 'layoutSlot')\n const header = slot === -1 ? visits : visits.slice(0, slot)\n const links = header.filter(({ node }) => isLink(node)).map(({ id }) => id)\n if (links.length >= 2) {\n violations.push({\n rule: 1,\n code: 'navigation-rebuilt',\n message: `The site already has the \"${navigation[0].name}\" component. Place it in the header instead of building the navigation again.`,\n nodeIds: aiModelNodeIds(links, tree.sourceIds),\n })\n }\n }\n return violations\n }\n}\n\n/**\n * Every check the layout door adds to the doctrine's: the reuse and region\n * checks above, and no contact detail the brief does not give (AGL-3596).\n */\nexport function aiLayoutChecks(\n inventory: AiSiteInventory | null,\n plan: AiJobPlan | null,\n brief: string,\n): (tree: AiValidatedTree) => AiDoctrineViolation[] {\n const reuse = aiLayoutReuseCheck(inventory, plan)\n return (tree) => [\n ...reuse(tree),\n ...aiLayoutInventedContactViolations(\n { rootId: tree.rootId, nodes: tree.nodes as unknown as Record<string, AiDoctrineNode> },\n brief,\n ).map((violation) => ({ ...violation, nodeIds: aiModelNodeIds(violation.nodeIds ?? [], tree.sourceIds) })),\n ]\n}\n\n/**\n * The regions the confirmed plan gives the layout, against the layout a COPY\n * actually produced (AGL-3024); `null` when the copy keeps the plan, or when\n * the plan promised no region to keep.\n *\n * The duplicate branch generates nothing, so it is the one place a plan's\n * promise can go unmet without a model ever answering for it. A copy that\n * cannot be read — deleted between the write and this read, or stored under a\n * root this check does not know — settles nothing, and a promise this step\n * cannot settle is reviewed by a person rather than reported as kept.\n */\nexport async function aiCopiedLayoutReview(\n firestore: FirebaseFirestore.Firestore,\n input: { hostId: string; id: string; name: string; plan: AiJobPlan | null },\n): Promise<AiJobReview | null> {\n const planned = aiPlannedLayoutRegions(input.plan)\n if (!planned.regions.length && !planned.unreadable.length) return null\n const stored = await readAiDraftNodes(firestore, {\n kind: 'layout',\n hostId: input.hostId,\n id: input.id,\n })\n const nodes = (stored?.nodes ?? {}) as unknown as Record<string, AiDoctrineNode>\n if (!nodes[CANVAS_ROOT_ELEMENT_ID]) {\n return {\n reason: 'doctrine',\n message: `\"${input.name}\" was copied from the layout the plan names, and this job could not read the copy back to check it has the regions the plan gives it. Open the layout and check it before you put a page in it.`,\n findings: [],\n }\n }\n const violations = aiPlanRegionViolations(input.plan, { rootId: CANVAS_ROOT_ELEMENT_ID, nodes })\n if (!violations.length) return null\n return aiDoctrineReview({\n message: `\"${input.name}\" is a copy of the layout the plan names, and a copy is all it is: ${violations[0].message}`,\n violations,\n })\n}\n\n/**\n * A layout job is admitted for a site of the job's own org with a shared\n * layout to spare, and confirmed only for a plan whose other creations it\n * builds (AGL-3143 §15).\n */\nexport const aiLayoutJobAdmission: AiJobAdmission = (context) =>\n aiDraftAdmissionRefusal(context.firestore, {\n orgId: context.orgId,\n hostId: context.hostId,\n kind: 'layout',\n org: context.org,\n ownCheck: (hostId) => aiJobPlanCreationsRefusal('layout', context, hostId),\n })\n\nexport interface AiJobLayoutStepDeps {\n /** The inventory reader; specs hand in a fake. */\n readInventory?: typeof readSiteInventory\n /** The platform's duplicate module, for a plan that starts from a copy. */\n duplicate?: typeof duplicateResource\n}\n\nexport function createAiJobLayoutStep(deps: AiJobLayoutStepDeps = {}): AiJobStepRunner {\n const readInventory = deps.readInventory ?? readSiteInventory\n const duplicate = deps.duplicate ?? duplicateResource\n return async ({ job, now, signal, firestore, modelFor }) => {\n const hostId = job.hostId\n if (!hostId) throw new Error('a layout job names no site, and its admission refuses one')\n const output = (draft: AiDraftRecord, load?: AiLoadEstimate | null, note?: string | null): AiJobOutput => ({\n resource: 'layout',\n id: draft.id,\n versionId: draft.versionId,\n hostId,\n hostSubdomain: draft.hostSubdomain,\n label: draft.name,\n ...(load ? { load } : {}),\n ...(note ? { note } : {}),\n })\n // The switch's answer for this job, else the routing table's (AGL-2942).\n const model = modelFor?.('job.layout') ?? aiModelForStep('job.layout')\n\n // A run cut off after its draft was written reports that draft, found by the id the job recorded.\n const draftId = aiJobDraftId(job, 'layout')\n const written = await readAiDraft(firestore, { kind: 'layout', hostId, id: draftId })\n if (written) return aiUnspentOutcome(model, { outputs: [output(written)] })\n\n const [inventory, orgSnapshot] = await Promise.all([\n readInventory(job.orgId, hostId, { firestore }),\n firestore.collection('orgs').doc(job.orgId).get(),\n ])\n const org = (orgSnapshot.data() ?? null) as Partial<AglynOrgBilling> | null\n const plan = aiConfirmedPlan(job)\n const creation = aiPlanCreation(plan, 'layout')\n const name = creation?.name || AI_JOB_LAYOUT_DEFAULT_NAME\n\n // The plan starts from a copy of a layout the site has (rule 15): the copy\n // is the draft, and nothing is generated. A source gone since the plan\n // was made is built from the brief instead. A source that cannot keep the\n // plan's regions is built FROM instead (AGL-3143 §14), as the page step\n // builds from a short source: copying it could only end in the review\n // below, and Try again would copy the same thing. Only a source read and\n // found short diverts; one this step cannot read still copies, and the\n // review after the copy answers for it.\n const source = creation?.duplicateOf\n ? inventory.layouts.find((layout) => layout.id === creation.duplicateOf)\n : undefined\n const sourceReview = source\n ? await aiCopiedLayoutReview(firestore, { hostId, id: source.id, plan, name: source.name })\n : null\n const sourceShort = Boolean(sourceReview?.findings.length)\n const sourceTree =\n source && sourceShort ? await readAiDraftNodes(firestore, { kind: 'layout', hostId, id: source.id }) : null\n const sourceLines =\n source && sourceShort ? aiCopySourceLines('layout', source.name, sourceTree?.nodes ?? null) : []\n if (creation?.duplicateOf && source && !sourceShort) {\n const copy = await duplicate('layout', {\n orgId: job.orgId,\n hostId,\n sourceId: creation.duplicateOf,\n name,\n uid: job.createdBy,\n org: org as Record<string, unknown> | null,\n // The same claim the page step makes (AGL-3024): a copy core mints is\n // written under core's own id, never `draftId`, so a step that runs\n // again — a pass resumed, a run cut off after the copy — would mint a\n // second. The job's recorded id makes core replay the one it made.\n attemptKey: draftId,\n })\n if (copy.ok) {\n // A copy is not a build (AGL-3024). This branch generates nothing, so\n // whatever the plan promised BEYOND the source is not in the draft\n // unless the source already had it: a plan reading \"from a copy of the\n // base layout, adding a sidebar\" gets the base layout, the sidebar\n // nowhere in it, and until now reported Done. The copy's own regions\n // answer the plan's, and a copy that cannot be read answers nothing —\n // which is a stop for a person, never a Done.\n const review = await aiCopiedLayoutReview(firestore, { hostId, id: copy.id, plan, name })\n if (review) return aiUnspentOutcome(model, { review })\n const hostSubdomain = await aiSiteSubdomain(firestore, hostId)\n return aiUnspentOutcome(model, {\n outputs: [output({ id: copy.id, versionId: copy.versionId, name: copy.name, hostSubdomain })],\n })\n }\n if (copy.ok === false && copy.status === 403) {\n return aiUnspentOutcome(model, { review: aiLimitReview(copy.error) })\n }\n }\n\n const allowance = await aiDraftAllowanceRefusal(firestore, { kind: 'layout', hostId, org })\n if (allowance) return aiUnspentOutcome(model, { review: aiLimitReview(allowance) })\n\n if (aiJobUsesLayoutLanguage(job)) {\n // ── The header and footer designed in the layout language (AGL-3660) ──\n const siteName = aiLayoutSiteName(job)\n const pages = aiLayoutNavPages(job, inventory)\n const targets = aiLayoutFrameTargets(job, inventory)\n const frameInput: AiLayoutFrameInput = {\n ...aiSiteStyleTokens(job.inputs),\n siteName,\n homeId: aiLayoutHomeId(pages, inventory),\n pages,\n targets,\n // A site brought in may state what its own header and footer state (AGL-4084).\n extend: aiLayoutChecks(inventory, plan, [job.brief, aiLayoutSiteFactsText(job.inputs)].filter(Boolean).join('\\n')),\n design: aiLayoutDesignOf(job, '/'),\n brand: aiLayoutSiteBrandOf(job.inputs),\n storeLinks: aiStoreFrameLinksOf(job.inputs),\n // The frame's own words in the site's language (AGL-3760).\n ...(job.plan?.language ? { language: job.plan.language } : {}),\n }\n // A site brought in whose menu the reader found (AGL-4108): its own\n // header and footer, drawn by code, and no model asked. One that does\n // not pass the layout's checks is designed by the model instead.\n const source = aiLayoutSiteFrameOf(job.inputs)\n if (source) {\n const drawn = aiLayoutSourceFrameBuild({ ...frameInput, source })\n if (drawn.value) {\n throwIfAiJobCanceled(signal)\n const draft = await writeAiDraft(firestore, {\n kind: 'layout',\n hostId,\n id: draftId,\n uid: job.createdBy,\n org,\n name,\n nodes: drawn.value.nodes,\n aiJobId: aiOriginJobId(job),\n now,\n })\n if (draft.ok === false) {\n if (draft.status === 404) throw new Error(`site ${hostId} vanished while its layout was built`)\n return aiUnspentOutcome(model, { review: aiLimitReview(draft.error) })\n }\n return aiUnspentOutcome(model, { outputs: [output(draft, drawn.value.load)] })\n }\n console.error('ai layout: a source frame did not pass its checks; designing it instead', {\n jobId: job.$id,\n violations: drawn.violations.map((violation) => violation.code),\n })\n }\n const result = await runValidatedGeneration<AiLayoutFrameBuilt>(AI_LAYOUT_FRAME_KIND, {\n step: 'job.layout',\n model,\n instructions: aiJobLayoutLanguageInstructions(job),\n inventory,\n messages: [{ role: 'user', content: aiLayoutFramePrompt({ job, siteName, pages, targets }) }],\n tool: AI_LAYOUT_FRAME_TOOL,\n maxTokens: AI_JOB_LAYOUT_LANGUAGE_BUDGET.maxTokens(model),\n ...AI_LAYOUT_LANGUAGE_THINKING,\n check: aiLayoutFrameCheck(frameInput),\n ...(signal ? { signal } : {}),\n })\n const spent = aiGenerationSpent(result)\n if (result.status === 'refused') return { ...spent, refused: true }\n if (result.status === 'needs_input') return { ...spent, review: aiDoctrineReview(result) }\n // Never written once the job is canceled (AGL-3616).\n throwIfAiJobCanceled(signal)\n const draft = await writeAiDraft(firestore, {\n kind: 'layout',\n hostId,\n id: draftId,\n uid: job.createdBy,\n org,\n name,\n nodes: result.value.nodes,\n aiJobId: aiOriginJobId(job),\n now,\n })\n if (draft.ok === false) {\n if (draft.status === 404) throw new Error(`site ${hostId} vanished while its layout was generated`)\n return { ...spent, review: aiLimitReview(draft.error) }\n }\n const note = aiBracketedFactsNote({\n tree: { rootId: result.value.rootId, nodes: result.value.nodes as unknown as AiDoctrineTree['nodes'] },\n inventory,\n })\n return { ...spent, outputs: [output(draft, result.value.load, note)] }\n }\n\n // The pages a site scaffold builds after this layout (AGL-3596): their\n // ids are the plan's, so the header links them by id, written by the\n // platform before the doctrine checks the tree.\n const sitePages = aiLayoutSitePages(job.inputs)\n const result = await runValidatedGeneration('layout', {\n step: 'job.layout',\n model,\n instructions: AI_JOB_LAYOUT_INSTRUCTIONS,\n inventory,\n messages: [{ role: 'user', content: aiJobLayoutPrompt(job, plan, name, sourceLines) }],\n tool: aiDoctrineTreeTool('layout'),\n maxTokens: AI_JOB_LAYOUT_STEP_BUDGET.maxTokens(model),\n ...(AI_ROUTING_TABLE['job.layout'].thinking ? { thinking: AI_ROUTING_TABLE['job.layout'].thinking } : {}),\n ...(AI_ROUTING_TABLE['job.layout'].effort ? { effort: AI_ROUTING_TABLE['job.layout'].effort } : {}),\n extend: aiLayoutChecks(inventory, plan, job.brief),\n // The site's name is written as the token that reads it, and the\n // layout fills the window so a short page keeps its footer at the\n // bottom (AGL-3596).\n complete: (tree: unknown) =>\n aiLayoutWithFullHeight(\n aiLayoutWithSiteName(\n sitePages.length ? aiLayoutWithSitePages(tree, sitePages, { homeScreenIds: aiHomeScreenIds(inventory) }) : tree,\n typeof job.inputs?.['businessName'] === 'string' ? job.inputs['businessName'] : null,\n ),\n ),\n ...(sitePages.length\n ? { context: { screenIds: [...inventory.screens.map((screen) => screen.id), ...sitePages.map((page) => page.id)] } }\n : {}),\n ...(signal ? { signal } : {}),\n })\n const spent = aiGenerationSpent(result)\n if (result.status === 'refused') return { ...spent, refused: true }\n if (result.status === 'needs_input') return { ...spent, review: aiDoctrineReview(result) }\n\n // Never written once the job is canceled (AGL-3616).\n throwIfAiJobCanceled(signal)\n const draft = await writeAiDraft(firestore, {\n kind: 'layout',\n hostId,\n id: draftId,\n uid: job.createdBy,\n org,\n name,\n nodes: result.value.nodes,\n aiJobId: aiOriginJobId(job),\n now,\n })\n if (draft.ok === false) {\n if (draft.status === 404) throw new Error(`site ${hostId} vanished while its layout was generated`)\n return { ...spent, review: aiLimitReview(draft.error) }\n }\n // The facts the brief did not give, which the member fills before publishing (AGL-3056).\n const note = aiBracketedFactsNote({\n tree: { rootId: result.value.rootId, nodes: result.value.nodes as unknown as AiDoctrineTree['nodes'] },\n inventory,\n })\n return { ...spent, outputs: [output(draft, result.value.load, note)] }\n }\n}\n\n/** The layout step, building the components and forms its plan creates before the layout (AGL-3143 §15). */\nexport const runAiJobLayoutStep = aiBuildingPlanCreations('layout', 'job.layout', createAiJobLayoutStep())\n\n/** Registers the layout step and the check a layout job passes before it is created or resumed. */\nexport function registerAiLayoutJob(): void {\n registerAiJobStep('layout', runAiJobLayoutStep, {\n minimumMs: AI_JOB_LAYOUT_STEP_MINIMUM_MS,\n minimumMsFor: aiPlanCreationsRunMinimumMs('layout'),\n })\n registerAiJobAdmission('layout', aiLayoutJobAdmission)\n}\n"],"names":["throwIfAiJobCanceled","aiSiteStyleTokens","CANVAS_ROOT_ELEMENT_ID","duplicateResource","aiHomeScreenIds","AI_STEP_TIERS","AI_ROUTING_TABLE","aiModelForStep","aiDoctrineTreeTool","runValidatedGeneration","walkTree","readSiteInventory","registerAiJobAdmission","aiBuildingPlanCreations","aiJobPlanCreationsRefusal","aiPlanCreationsRunMinimumMs","aiJobDraftId","aiOriginJobId","aiDraftAdmissionRefusal","aiDraftAllowanceRefusal","aiSiteSubdomain","readAiDraft","readAiDraftNodes","writeAiDraft","aiBracketedFactsNote","aiCopySourceLines","aiConfirmedPlan","aiDoctrineReview","aiGenerationSpent","aiJobBriefLine","aiLimitReview","aiModelNodeIds","aiPlacedComponentIds","aiPlanCreation","aiPlanReferenceLines","aiPlanReuseViolations","aiUnspentOutcome","aiPlanRegionViolations","aiPlannedLayoutRegions","aiLayoutSitePages","aiLayoutSitePagesLines","aiLayoutWithSitePages","aiLayoutInventedContactViolations","aiLayoutWithSiteName","aiLayoutWithFullHeight","AI_LAYOUT_FRAME_TOOL","AI_JOB_LAYOUT_LANGUAGE_BUDGET","AI_LAYOUT_FRAME_KIND","aiJobLayoutLanguageInstructions","aiLayoutFrameCheck","aiLayoutFramePrompt","aiLayoutFrameTargets","aiLayoutHomeId","aiLayoutNavPages","aiLayoutSiteBrandOf","aiLayoutSiteFactsText","aiLayoutSiteFrameOf","aiLayoutSiteName","aiLayoutSourceFrameBuild","AI_LAYOUT_LANGUAGE_THINKING","aiJobUsesLayoutLanguage","aiLayoutDesignOf","aiJobStepBudget","registerAiJobStep","aiStoreFrameLinksOf","AI_JOB_LAYOUT_MAX_TOKENS","maxTokens","AI_JOB_LAYOUT_STEP_BUDGET","tier","AI_JOB_LAYOUT_STEP_MINIMUM_MS","minimumMs","AI_JOB_LAYOUT_DEFAULT_NAME","AI_JOB_LAYOUT_INSTRUCTIONS","text","join","aiJobLayoutPrompt","job","plan","name","source","inputs","NAVIGATION_NAME","FOOTER_NAME","isLink","node","componentId","props","aiLayoutReuseCheck","inventory","components","navigation","filter","component","test","tree","placed","violations","rootId","nodes","length","some","has","id","visits","slot","findIndex","header","slice","links","map","push","rule","code","message","nodeIds","sourceIds","aiLayoutChecks","brief","reuse","violation","aiCopiedLayoutReview","firestore","input","planned","regions","unreadable","stored","kind","hostId","reason","findings","aiLayoutJobAdmission","context","orgId","org","ownCheck","createAiJobLayoutStep","deps","readInventory","duplicate","now","signal","modelFor","orgSnapshot","Error","output","draft","load","note","resource","versionId","hostSubdomain","label","model","draftId","written","outputs","Promise","all","collection","doc","get","data","creation","duplicateOf","layouts","find","layout","undefined","sourceReview","sourceShort","Boolean","sourceTree","sourceLines","copy","sourceId","uid","createdBy","attemptKey","ok","review","status","error","allowance","siteName","pages","targets","frameInput","homeId","extend","design","brand","storeLinks","language","drawn","value","aiJobId","console","jobId","$id","result","step","instructions","messages","role","content","tool","check","spent","refused","sitePages","thinking","effort","complete","homeScreenIds","screenIds","screens","screen","page","runAiJobLayoutStep","registerAiLayoutJob","minimumMsFor"],"mappings":"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"}
|
|
@@ -297,7 +297,8 @@ export function createAiJobNavigationStep(deps = {}) {
|
|
|
297
297
|
inputs: {
|
|
298
298
|
target: plan.layoutId,
|
|
299
299
|
targetKind: 'layout',
|
|
300
|
-
versionId: null
|
|
300
|
+
versionId: null,
|
|
301
|
+
newVersion: false
|
|
301
302
|
},
|
|
302
303
|
jobId: versionId
|
|
303
304
|
});
|
|
@@ -409,7 +410,8 @@ export const runAiJobNavigationStep = createAiJobNavigationStep();
|
|
|
409
410
|
inputs: {
|
|
410
411
|
target: plan.layoutId,
|
|
411
412
|
targetKind: 'layout',
|
|
412
|
-
versionId: null
|
|
413
|
+
versionId: null,
|
|
414
|
+
newVersion: false
|
|
413
415
|
},
|
|
414
416
|
jobId: null
|
|
415
417
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-job-navigation-step.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { checkEntitlement } from '@aglyn/aglyn/app-utils/plan-entitlements'\nimport { holdsSiteKey } from '@aglyn/aglyn/app-utils/host-permissions'\nimport { orgPermissionLabel } from '@aglyn/aglyn/app-utils/org-permissions'\nimport { decodeStoredNodes, encodeStoredNodes } from '@aglyn/aglyn/app-utils/stored-nodes'\nimport { getLockdownVerdict } from '@aglyn/tenant-data-admin/server/lockdown'\nimport { resolveOrgIdForHost } from '@aglyn/tenant-data-admin/server/organizations'\nimport type { Firestore } from 'firebase-admin/firestore'\nimport { AI_EDIT_GONE_COPY, AI_EDIT_NEEDS_VERSIONING_COPY, AI_EDIT_NO_NODES_COPY, AI_EDIT_VERSION_GONE_COPY } from '../model/ai-edit-job'\nimport { isAiPlanNewRef } from '../model/ai-build-plan'\nimport { AI_BUILD_MADE_INPUT, type AiBuildMade } from '../model/ai-build-job'\nimport { aiBuildStoreLayoutOf } from '../model/ai-build-store-pages'\nimport type { AiJob, AiJobOutput } from '../model/ai-jobs.types'\nimport {\n aiLayoutWithMenuChanges,\n aiMenuChangesEmpty,\n aiMenuChangesOf,\n aiMenusOf,\n type AiMenuChanges,\n type AiMenuName,\n type AiMenuTarget,\n} from '../model/ai-layout-menus'\nimport { registerAiJobAdmission, type AiJobAdmission, type AiJobAdmissionRefusal } from './ai-job-admission'\nimport { aiOriginJobId } from './ai-job-draft-ids'\nimport { aiEditPlacement, aiEditVersionId, aiJobEditModel, readAiEditTarget } from './ai-job-edit-step'\nimport { aiLimitReview, aiUnspentOutcome } from './ai-job-generation'\nimport type { AiJobStepOutcome, AiJobStepRunner } from './ai-job-text-step'\nimport { registerAiJobStep } from './ai-jobs'\n\n/**\n * The `navigation` step (AGL-3728): a change to a site's header or footer\n * menu — add, take out, rename, relink or reorder its items — as a\n * first-class build operation, so Assist's one plan card can say \"add About\n * and Pricing to the menu, and take Blog out\" and have it done.\n *\n * NO MODEL. The planner already wrote the change as the item's arguments, in\n * words (`aiMenuChangesOf`); this applies it to the layout's own Besigner\n * elements in code (`aiLayoutWithMenuChanges`), so it costs no credits and\n * cannot invent a link: every destination is one of the site's pages, a page\n * this build made, a path on the site or an https address.\n *\n * ── Where it lands ───────────────────────────────────────────────────────\n *\n * As the `edit` step's change to a layout does: a NEW version beside the\n * layout's current one, which visitors keep seeing until a person publishes\n * the new one. A layout is always served, so without version history there is\n * nowhere for it to land and it is refused as a plan limit, charged nothing.\n * The version is named by the job's id, so a pass asked again finds what it\n * wrote.\n *\n * ── Who may ──────────────────────────────────────────────────────────────\n *\n * The editor's own rule for a layout's versions (`canWriteHostContent` and\n * `hostWritesFrozen` in the Firestore rules): a member with a write role on\n * the site (admin, editor or author), while no lockdown freezes the site, its\n * org or the platform. Asked at the door, again before the write, and the\n * role once more inside the transaction that writes.\n *\n * ── Audit ────────────────────────────────────────────────────────────────\n *\n * The layout it wrote is the job's output, which the job machine records as\n * an `ai.job.output` activity row on the site, as every other operation's is.\n */\n\nexport const AI_NAVIGATION_KIND = 'navigation' as const\n\n/**\n * ASSUMED: the least time the step needs — the site's pages, the layout and\n * its version, the org, and the one transaction that writes. No model, so it\n * fits an inline door.\n */\nexport const AI_JOB_NAVIGATION_STEP_MINIMUM_MS = 5_000\n\nexport const AI_NAVIGATION_NO_SITE_COPY = 'Open the site whose menu should change.'\n/** Names \"Edit site content\" (`site.edit`, AGL-4047), never a role. */\nexport const AI_NAVIGATION_ROLE_COPY = `Changing the site’s menus needs the \"${orgPermissionLabel('site.edit')}\" permission on this site — ask an organization admin.`\nexport const AI_NAVIGATION_LOCKED_COPY = 'This site is not accepting changes right now.'\nexport const AI_NAVIGATION_NO_LAYOUT_COPY = 'This site has no layout with a header or footer to change. Make one in Layouts first.'\nexport const AI_NAVIGATION_NOTHING_COPY = 'The request named no menu change this could make.'\n\n/** The name the new version carries in the layout's versions. */\nexport const AI_NAVIGATION_VERSION_NAME = 'Menu changes'\n\nconst text = (value: unknown): string => (typeof value === 'string' ? value.trim() : '')\n\n/** A path on the site, as a menu item may link it. */\nconst SITE_PATH = /^\\/(?:[A-Za-z0-9._~!$&'()*+,;=:@%-]+(?:\\/[A-Za-z0-9._~!$&'()*+,;=:@%-]+)*)?\\/?(?:[?#][^\\s]*)?$/\nconst SCREEN_ID = /^[A-Za-z0-9_-]{1,128}$/\n\nfunction buildMadeOf(inputs: Readonly<Record<string, unknown>> | null | undefined): AiBuildMade {\n const raw = (inputs?.[AI_BUILD_MADE_INPUT] ?? {}) as Partial<Record<'pages' | 'layouts', unknown>>\n const rows = (value: unknown, name: 'title' | 'name') =>\n (Array.isArray(value) ? value : []).flatMap((entry) => {\n const row = (entry ?? {}) as Record<string, unknown>\n return text(row[name]) && SCREEN_ID.test(text(row['id'])) ? [{ [name]: text(row[name]), id: text(row['id']) }] : []\n })\n return { pages: rows(raw.pages, 'title') as AiBuildMade['pages'], layouts: rows(raw.layouts, 'name') as AiBuildMade['layouts'] }\n}\n\n/** The site's pages a menu may link, by id, with the layout each renders inside. */\nexport interface AiNavigationSitePage {\n id: string\n title: string\n slug: string\n template: boolean\n layoutId: string | null\n}\n\n/** The site's pages: not deleted, not an email design. */\nexport async function readAiNavigationSitePages(firestore: Firestore, hostId: string): Promise<AiNavigationSitePage[]> {\n const snapshot = await firestore.collection('hosts').doc(hostId).collection('screens').select('displayName', 'slug', 'kind', 'deletedAt', 'layoutId').get()\n return snapshot.docs.flatMap((doc) => {\n const kind = doc.get('kind')\n if (doc.get('deletedAt') || (kind && kind !== 'template')) return []\n const layoutId = doc.get('layoutId')\n return [\n {\n id: doc.id,\n slug: String(doc.get('slug') ?? ''),\n title: String(doc.get('displayName') ?? ''),\n template: kind === 'template',\n layoutId: typeof layoutId === 'string' && layoutId ? layoutId : null,\n },\n ]\n })\n}\n\n/**\n * What a destination in an item's words links (AGL-3728): a page this build\n * made (`new:<title>`), one of the site's pages by id (`page:<id>` or the bare\n * id), a path on the site, or an https address; `null` for anything else.\n */\nexport function aiNavigationTarget(\n destination: string,\n context: { pages: readonly Pick<AiNavigationSitePage, 'id' | 'template'>[]; made: AiBuildMade },\n): AiMenuTarget | null {\n const value = destination.trim()\n const pageIds = new Set(context.pages.filter((page) => !page.template).map((page) => page.id))\n if (isAiPlanNewRef(value as string | null)) {\n const title = value.slice(value.indexOf(':') + 1).trim().toLowerCase()\n const made = context.made.pages.find((page) => page.title.trim().toLowerCase() === title)\n // A page this build was to make and did not is no destination.\n return made && pageIds.has(made.id) ? { screenId: made.id } : null\n }\n const id = value.replace(/^page:/i, '')\n if (pageIds.has(id)) return { screenId: id }\n if (value.startsWith('/') && !value.startsWith('//') && SITE_PATH.test(value)) return { href: value }\n if (/^https:\\/\\/[^\\s/?#]+\\.[^\\s/?#]+(?:[/?#]\\S*)?$/i.test(value)) return { href: value }\n return null\n}\n\n/** The layout an item changes: the one it names, else the one the site's pages render inside. */\nexport function aiNavigationLayoutOf(\n named: string,\n context: { pages: readonly AiNavigationSitePage[]; made: AiBuildMade },\n): string | null {\n if (isAiPlanNewRef(named as string | null)) {\n const name = named.slice(named.indexOf(':') + 1).trim().toLowerCase()\n return context.made.layouts.find((layout) => layout.name.trim().toLowerCase() === name)?.id ?? null\n }\n if (SCREEN_ID.test(named)) return named\n return aiBuildStoreLayoutOf(null, context.pages)\n}\n\n/** Why this member may not change this site's menus now, or `null`. */\nexport async function aiNavigationAccessRefusal(\n input: { host: FirebaseFirestore.DocumentSnapshot; uid: string; org: object | null },\n deps: { lockdown?: typeof getLockdownVerdict } = {},\n): Promise<string | null> {\n if (!holdsSiteKey(input.host, input.uid, 'site.edit')) return AI_NAVIGATION_ROLE_COPY\n const locked = await (deps.lockdown ?? getLockdownVerdict)({\n staff: false,\n uid: input.uid,\n org: input.org as never,\n host: input.host.data() as never,\n intent: 'write',\n })\n return locked ? AI_NAVIGATION_LOCKED_COPY : null\n}\n\n/** The new version's output note: what was done, what was not, and that it waits to be published. */\nexport function aiNavigationOutputNote(done: readonly string[], notDone: readonly string[]): string {\n const did = done.length ? `${done.join(' ')} ` : ''\n const not = notDone.length ? ` Not done: ${notDone.join(' ')}` : ''\n return `${did}Saved as a new version of the layout beside the one visitors see: open it to review it, and publish it when it is ready.${not}`.slice(0, 1_000)\n}\n\nexport type AiNavigationWrite =\n | { ok: true; versionId: string; done: string[]; notDone: string[] }\n | { ok: false; error: string }\n\n/**\n * The change written, in one transaction that reads the layout as it is\n * stored NOW: it still exists, its version is still there, the member still\n * holds a write role, and the plan still keeps version history. The change is\n * applied again to that version's nodes, so a save made since is kept.\n */\nexport async function writeAiNavigation(\n firestore: Firestore,\n input: {\n hostId: string\n layoutId: string\n sourceVersionId: string\n versionId: string\n menus: readonly AiMenuName[]\n changes: AiMenuChanges\n uid: string\n aiJobId: string\n versioning: boolean\n now: Date\n },\n): Promise<AiNavigationWrite> {\n const hostRef = firestore.collection('hosts').doc(input.hostId)\n const docRef = hostRef.collection('layouts').doc(input.layoutId)\n const sourceRef = docRef.collection('versions').doc(input.sourceVersionId)\n const newRef = docRef.collection('versions').doc(input.versionId)\n return firestore.runTransaction(async (tx): Promise<AiNavigationWrite> => {\n const [host, doc, source, already] = await Promise.all([tx.get(hostRef), tx.get(docRef), tx.get(sourceRef), tx.get(newRef)])\n if (already.exists) return { ok: true, versionId: input.versionId, done: [], notDone: [] }\n if (!doc.exists || doc.get('deletedAt') != null) return { ok: false, error: AI_EDIT_GONE_COPY }\n if (!source.exists) return { ok: false, error: AI_EDIT_VERSION_GONE_COPY }\n if (!holdsSiteKey(host, input.uid, 'site.edit')) return { ok: false, error: AI_NAVIGATION_ROLE_COPY }\n const pointer = text(doc.get('versionId')) || null\n const placement = aiEditPlacement({\n versioning: input.versioning,\n served: true,\n sourceIsPointer: pointer === input.sourceVersionId,\n sourceScheduled: false,\n })\n if (placement === 'refused') return { ok: false, error: AI_EDIT_NEEDS_VERSIONING_COPY }\n const nodes = decodeStoredNodes<Record<string, unknown>>(source.get('nodes'))\n if (!nodes) return { ok: false, error: AI_EDIT_NO_NODES_COPY }\n const applied = aiLayoutWithMenuChanges(nodes, input.menus, input.changes)\n if (!applied.nodes) return { ok: false, error: applied.notDone.join(' ') || AI_NAVIGATION_NOTHING_COPY }\n const packed = encodeStoredNodes(applied.nodes as never)\n if (!packed) return { ok: false, error: AI_EDIT_NO_NODES_COPY }\n // A copy of the version it started from — everything the editor stored —\n // with the changed menus, as the versions route copies one.\n const copy = { ...(source.data() as Record<string, unknown>) }\n delete copy['aiEditJobId']\n tx.create(newRef, {\n ...copy,\n nodes: Buffer.from(packed),\n displayName: AI_NAVIGATION_VERSION_NAME,\n createdAt: input.now,\n updatedAt: input.now,\n createdBy: input.uid,\n aiJobId: input.aiJobId,\n })\n return { ok: true, versionId: input.versionId, done: applied.done, notDone: applied.notDone }\n })\n}\n\nexport interface AiJobNavigationStepDeps {\n readTarget?: typeof readAiEditTarget\n readPages?: typeof readAiNavigationSitePages\n write?: typeof writeAiNavigation\n lockdown?: typeof getLockdownVerdict\n}\n\n/** What the step decided before writing: the layout, its version, the change and what was read away. */\ninterface AiNavigationPlan {\n layoutId: string\n menus: AiMenuName[]\n changes: AiMenuChanges\n problems: string[]\n}\n\nasync function navigationPlanOf(\n firestore: Firestore,\n job: Pick<AiJob, 'hostId' | 'inputs'>,\n readPages: typeof readAiNavigationSitePages,\n): Promise<AiNavigationPlan | string> {\n if (!job.hostId) return AI_NAVIGATION_NO_SITE_COPY\n const inputs = job.inputs ?? {}\n const pages = await readPages(firestore, job.hostId)\n const made = buildMadeOf(inputs)\n const layoutId = aiNavigationLayoutOf(text(inputs['layout']), { pages, made })\n if (!layoutId) return AI_NAVIGATION_NO_LAYOUT_COPY\n const read = aiMenuChangesOf(inputs, (destination) => aiNavigationTarget(destination, { pages, made }))\n if (aiMenuChangesEmpty(read.changes)) return [AI_NAVIGATION_NOTHING_COPY, ...read.problems].join(' ')\n return { layoutId, menus: aiMenusOf(inputs['menu']), changes: read.changes, problems: read.problems }\n}\n\nexport function createAiJobNavigationStep(deps: AiJobNavigationStepDeps = {}): AiJobStepRunner {\n const readTarget = deps.readTarget ?? readAiEditTarget\n const readPages = deps.readPages ?? readAiNavigationSitePages\n const write = deps.write ?? writeAiNavigation\n return async ({ job, now, firestore, org, modelFor }): Promise<AiJobStepOutcome> => {\n // No model is asked: the outcome records the edit step's at no cost.\n const model = modelFor?.('job.edit') ?? aiJobEditModel()\n const unspent = (failure: string): AiJobStepOutcome => ({ ...aiUnspentOutcome(model), failure })\n const hostId = job.hostId\n if (!hostId) return unspent(AI_NAVIGATION_NO_SITE_COPY)\n const plan = await navigationPlanOf(firestore, job, readPages)\n if (typeof plan === 'string') return unspent(plan)\n const versionId = aiEditVersionId(job)\n const read = await readTarget(firestore, {\n orgId: job.orgId,\n hostId,\n inputs: { target: plan.layoutId, targetKind: 'layout', versionId: null },\n jobId: versionId,\n })\n if ('error' in read) return unspent(read.error)\n const output = (done: readonly string[], notDone: readonly string[]): AiJobOutput => ({\n resource: 'layout',\n id: read.id,\n versionId,\n hostId,\n hostSubdomain: read.hostSubdomain,\n label: read.name,\n note: aiNavigationOutputNote(done, notDone),\n })\n if (read.written) return aiUnspentOutcome(model, { outputs: [output([], [])] })\n const orgData = org ?? ((await firestore.collection('orgs').doc(job.orgId).get()).data() ?? null)\n const host = await firestore.collection('hosts').doc(hostId).get()\n const refused = await aiNavigationAccessRefusal({ host, uid: job.createdBy, org: orgData }, { lockdown: deps.lockdown })\n if (refused) return aiUnspentOutcome(model, { review: aiLimitReview(refused) })\n const versioning = checkEntitlement(orgData as never, 'versioning')\n const placement = aiEditPlacement({\n versioning,\n served: true,\n sourceIsPointer: read.sourceVersionId === read.pointerVersionId,\n sourceScheduled: read.scheduledVersionId === read.sourceVersionId,\n })\n if (placement === 'refused') return aiUnspentOutcome(model, { review: aiLimitReview(AI_EDIT_NEEDS_VERSIONING_COPY) })\n const written = await write(firestore, {\n hostId,\n layoutId: read.id,\n sourceVersionId: read.sourceVersionId,\n versionId,\n menus: plan.menus,\n changes: plan.changes,\n uid: job.createdBy,\n aiJobId: aiOriginJobId(job),\n versioning,\n now,\n })\n if (written.ok === false) return unspent(written.error)\n return aiUnspentOutcome(model, { outputs: [output(written.done, [...written.notDone, ...plan.problems])] })\n }\n}\n\nexport const runAiJobNavigationStep = createAiJobNavigationStep()\n\n// ── Admission ─────────────────────────────────────────────────────────────\n\nexport interface AiNavigationJobAdmissionDeps {\n ownerOf?: typeof resolveOrgIdForHost\n readTarget?: typeof readAiEditTarget\n readPages?: typeof readAiNavigationSitePages\n lockdown?: typeof getLockdownVerdict\n}\n\n/**\n * A navigation change is admitted on a site of the job's own org, for a\n * member who may write its content now, where the site has a layout and the\n * change has somewhere to land that no visitor sees on this plan. Refused in\n * those words before anything exists.\n */\nexport function createAiNavigationJobAdmission(deps: AiNavigationJobAdmissionDeps = {}): AiJobAdmission {\n const ownerOf = deps.ownerOf ?? resolveOrgIdForHost\n const readTarget = deps.readTarget ?? readAiEditTarget\n const readPages = deps.readPages ?? readAiNavigationSitePages\n return async (context): Promise<AiJobAdmissionRefusal | null> => {\n if (!context.hostId) return { status: 400, error: AI_NAVIGATION_NO_SITE_COPY }\n const owner = await ownerOf(context.hostId)\n if (!owner || owner !== context.orgId) return { status: 404, error: 'Unknown site' }\n const host = await context.firestore.collection('hosts').doc(context.hostId).get()\n const refused = await aiNavigationAccessRefusal({ host, uid: context.uid ?? '', org: context.org }, { lockdown: deps.lockdown })\n if (refused) return { status: 403, error: refused }\n const plan = await navigationPlanOf(context.firestore as Firestore, { hostId: context.hostId, inputs: context.inputs as Record<string, unknown> }, readPages)\n if (typeof plan === 'string') return { status: 400, error: plan }\n const read = await readTarget(context.firestore, {\n orgId: context.orgId,\n hostId: context.hostId,\n inputs: { target: plan.layoutId, targetKind: 'layout', versionId: null },\n jobId: null,\n })\n if ('error' in read) return read\n const placement = aiEditPlacement({\n versioning: checkEntitlement(context.org as never, 'versioning'),\n served: true,\n sourceIsPointer: read.sourceVersionId === read.pointerVersionId,\n sourceScheduled: read.scheduledVersionId === read.sourceVersionId,\n })\n return placement === 'refused' ? { status: 403, error: AI_EDIT_NEEDS_VERSIONING_COPY } : null\n }\n}\n\nexport const aiNavigationJobAdmission = createAiNavigationJobAdmission()\n\n/** Registers the navigation step and its door (AGL-3728). */\nexport function registerAiNavigationJob(): void {\n registerAiJobStep(AI_NAVIGATION_KIND, runAiJobNavigationStep, { minimumMs: AI_JOB_NAVIGATION_STEP_MINIMUM_MS })\n registerAiJobAdmission(AI_NAVIGATION_KIND, aiNavigationJobAdmission)\n}\n"],"names":["checkEntitlement","holdsSiteKey","orgPermissionLabel","decodeStoredNodes","encodeStoredNodes","getLockdownVerdict","resolveOrgIdForHost","AI_EDIT_GONE_COPY","AI_EDIT_NEEDS_VERSIONING_COPY","AI_EDIT_NO_NODES_COPY","AI_EDIT_VERSION_GONE_COPY","isAiPlanNewRef","AI_BUILD_MADE_INPUT","aiBuildStoreLayoutOf","aiLayoutWithMenuChanges","aiMenuChangesEmpty","aiMenuChangesOf","aiMenusOf","registerAiJobAdmission","aiOriginJobId","aiEditPlacement","aiEditVersionId","aiJobEditModel","readAiEditTarget","aiLimitReview","aiUnspentOutcome","registerAiJobStep","AI_NAVIGATION_KIND","AI_JOB_NAVIGATION_STEP_MINIMUM_MS","AI_NAVIGATION_NO_SITE_COPY","AI_NAVIGATION_ROLE_COPY","AI_NAVIGATION_LOCKED_COPY","AI_NAVIGATION_NO_LAYOUT_COPY","AI_NAVIGATION_NOTHING_COPY","AI_NAVIGATION_VERSION_NAME","text","value","trim","SITE_PATH","SCREEN_ID","buildMadeOf","inputs","raw","rows","name","Array","isArray","flatMap","entry","row","test","id","pages","layouts","readAiNavigationSitePages","firestore","hostId","snapshot","collection","doc","select","get","docs","kind","layoutId","slug","String","title","template","aiNavigationTarget","destination","context","pageIds","Set","filter","page","map","slice","indexOf","toLowerCase","made","find","has","screenId","replace","startsWith","href","aiNavigationLayoutOf","named","layout","aiNavigationAccessRefusal","input","deps","host","uid","locked","lockdown","staff","org","data","intent","aiNavigationOutputNote","done","notDone","did","length","join","not","writeAiNavigation","hostRef","docRef","sourceRef","sourceVersionId","newRef","versionId","runTransaction","tx","source","already","Promise","all","exists","ok","error","pointer","placement","versioning","served","sourceIsPointer","sourceScheduled","nodes","applied","menus","changes","packed","copy","create","Buffer","from","displayName","createdAt","now","updatedAt","createdBy","aiJobId","navigationPlanOf","job","readPages","read","problems","createAiJobNavigationStep","readTarget","write","modelFor","model","unspent","failure","plan","orgId","target","targetKind","jobId","output","resource","hostSubdomain","label","note","written","outputs","orgData","refused","review","pointerVersionId","scheduledVersionId","runAiJobNavigationStep","createAiNavigationJobAdmission","ownerOf","status","owner","aiNavigationJobAdmission","registerAiNavigationJob","minimumMs"],"mappings":";AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,gBAAgB,QAAQ,2CAA0C;AAC3E,SAASC,YAAY,QAAQ,0CAAyC;AACtE,SAASC,kBAAkB,QAAQ,yCAAwC;AAC3E,SAASC,iBAAiB,EAAEC,iBAAiB,QAAQ,sCAAqC;AAC1F,SAASC,kBAAkB,QAAQ,2CAA0C;AAC7E,SAASC,mBAAmB,QAAQ,gDAA+C;AAEnF,SAASC,iBAAiB,EAAEC,6BAA6B,EAAEC,qBAAqB,EAAEC,yBAAyB,QAAQ,0BAAsB;AACzI,SAASC,cAAc,QAAQ,4BAAwB;AACvD,SAASC,mBAAmB,QAA0B,2BAAuB;AAC7E,SAASC,oBAAoB,QAAQ,mCAA+B;AAEpE,SACEC,uBAAuB,EACvBC,kBAAkB,EAClBC,eAAe,EACfC,SAAS,QAIJ,8BAA0B;AACjC,SAASC,sBAAsB,QAAyD,wBAAoB;AAC5G,SAASC,aAAa,QAAQ,wBAAoB;AAClD,SAASC,eAAe,EAAEC,eAAe,EAAEC,cAAc,EAAEC,gBAAgB,QAAQ,wBAAoB;AACvG,SAASC,aAAa,EAAEC,gBAAgB,QAAQ,yBAAqB;AAErE,SAASC,iBAAiB,QAAQ,eAAW;AAE7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiCC,GAED,OAAO,MAAMC,qBAAqB,aAAqB;AAEvD;;;;CAIC,GACD,OAAO,MAAMC,oCAAoC,KAAK;AAEtD,OAAO,MAAMC,6BAA6B,0CAAyC;AACnF,qEAAqE,GACrE,OAAO,MAAMC,0BAA0B,CAAC,qCAAqC,EAAE5B,mBAAmB,aAAa,sDAAsD,CAAC,CAAA;AACtK,OAAO,MAAM6B,4BAA4B,gDAA+C;AACxF,OAAO,MAAMC,+BAA+B,wFAAuF;AACnI,OAAO,MAAMC,6BAA6B,oDAAmD;AAE7F,+DAA+D,GAC/D,OAAO,MAAMC,6BAA6B,eAAc;AAExD,MAAMC,OAAO,CAACC,QAA4B,OAAOA,UAAU,WAAWA,MAAMC,IAAI,KAAK;AAErF,oDAAoD,GACpD,MAAMC,YAAY;AAClB,MAAMC,YAAY;AAElB,SAASC,YAAYC,MAA4D;;IAC/E,MAAMC,cAAOD,0BAAAA,MAAQ,CAAC7B,oBAAoB,mBAAI,CAAC;IAC/C,MAAM+B,OAAO,CAACP,OAAgBQ,OAC5B,AAACC,CAAAA,MAAMC,OAAO,CAACV,SAASA,QAAQ,EAAE,AAAD,EAAGW,OAAO,CAAC,CAACC;YAC3C,MAAMC,MAAOD,gBAAAA,QAAS,CAAC;YACvB,OAAOb,KAAKc,GAAG,CAACL,KAAK,KAAKL,UAAUW,IAAI,CAACf,KAAKc,GAAG,CAAC,KAAK,KAAK;gBAAC;oBAAE,CAACL,KAAK,EAAET,KAAKc,GAAG,CAACL,KAAK;oBAAGO,IAAIhB,KAAKc,GAAG,CAAC,KAAK;gBAAE;aAAE,GAAG,EAAE;QACrH;IACF,OAAO;QAAEG,OAAOT,KAAKD,IAAIU,KAAK,EAAE;QAAkCC,SAASV,KAAKD,IAAIW,OAAO,EAAE;IAAkC;AACjI;AAWA,wDAAwD,GACxD,OAAO,eAAeC,0BAA0BC,SAAoB,EAAEC,MAAc;IAClF,MAAMC,WAAW,MAAMF,UAAUG,UAAU,CAAC,SAASC,GAAG,CAACH,QAAQE,UAAU,CAAC,WAAWE,MAAM,CAAC,eAAe,QAAQ,QAAQ,aAAa,YAAYC,GAAG;IACzJ,OAAOJ,SAASK,IAAI,CAACf,OAAO,CAAC,CAACY;YAOXA,UACCA;QAPlB,MAAMI,OAAOJ,IAAIE,GAAG,CAAC;QACrB,IAAIF,IAAIE,GAAG,CAAC,gBAAiBE,QAAQA,SAAS,YAAa,OAAO,EAAE;QACpE,MAAMC,WAAWL,IAAIE,GAAG,CAAC;QACzB,OAAO;YACL;gBACEV,IAAIQ,IAAIR,EAAE;gBACVc,MAAMC,QAAOP,WAAAA,IAAIE,GAAG,CAAC,mBAARF,WAAmB;gBAChCQ,OAAOD,QAAOP,YAAAA,IAAIE,GAAG,CAAC,0BAARF,YAA0B;gBACxCS,UAAUL,SAAS;gBACnBC,UAAU,OAAOA,aAAa,YAAYA,WAAWA,WAAW;YAClE;SACD;IACH;AACF;AAEA;;;;CAIC,GACD,OAAO,SAASK,mBACdC,WAAmB,EACnBC,OAA+F;IAE/F,MAAMnC,QAAQkC,YAAYjC,IAAI;IAC9B,MAAMmC,UAAU,IAAIC,IAAIF,QAAQnB,KAAK,CAACsB,MAAM,CAAC,CAACC,OAAS,CAACA,KAAKP,QAAQ,EAAEQ,GAAG,CAAC,CAACD,OAASA,KAAKxB,EAAE;IAC5F,IAAIxC,eAAeyB,QAAyB;QAC1C,MAAM+B,QAAQ/B,MAAMyC,KAAK,CAACzC,MAAM0C,OAAO,CAAC,OAAO,GAAGzC,IAAI,GAAG0C,WAAW;QACpE,MAAMC,OAAOT,QAAQS,IAAI,CAAC5B,KAAK,CAAC6B,IAAI,CAAC,CAACN,OAASA,KAAKR,KAAK,CAAC9B,IAAI,GAAG0C,WAAW,OAAOZ;QACnF,+DAA+D;QAC/D,OAAOa,QAAQR,QAAQU,GAAG,CAACF,KAAK7B,EAAE,IAAI;YAAEgC,UAAUH,KAAK7B,EAAE;QAAC,IAAI;IAChE;IACA,MAAMA,KAAKf,MAAMgD,OAAO,CAAC,WAAW;IACpC,IAAIZ,QAAQU,GAAG,CAAC/B,KAAK,OAAO;QAAEgC,UAAUhC;IAAG;IAC3C,IAAIf,MAAMiD,UAAU,CAAC,QAAQ,CAACjD,MAAMiD,UAAU,CAAC,SAAS/C,UAAUY,IAAI,CAACd,QAAQ,OAAO;QAAEkD,MAAMlD;IAAM;IACpG,IAAI,iDAAiDc,IAAI,CAACd,QAAQ,OAAO;QAAEkD,MAAMlD;IAAM;IACvF,OAAO;AACT;AAEA,+FAA+F,GAC/F,OAAO,SAASmD,qBACdC,KAAa,EACbjB,OAAsE;IAEtE,IAAI5D,eAAe6E,QAAyB;;YAEnCjB;QADP,MAAM3B,OAAO4C,MAAMX,KAAK,CAACW,MAAMV,OAAO,CAAC,OAAO,GAAGzC,IAAI,GAAG0C,WAAW;QACnE,gBAAOR,6BAAAA,QAAQS,IAAI,CAAC3B,OAAO,CAAC4B,IAAI,CAAC,CAACQ,SAAWA,OAAO7C,IAAI,CAACP,IAAI,GAAG0C,WAAW,OAAOnC,0BAA3E2B,2BAAkFpB,EAAE,mBAAI;IACjG;IACA,IAAIZ,UAAUW,IAAI,CAACsC,QAAQ,OAAOA;IAClC,OAAO3E,qBAAqB,MAAM0D,QAAQnB,KAAK;AACjD;AAEA,qEAAqE,GACrE,OAAO,eAAesC,0BACpBC,KAAoF,EACpFC,OAAiD,CAAC,CAAC;QAG7BA;IADtB,IAAI,CAAC3F,aAAa0F,MAAME,IAAI,EAAEF,MAAMG,GAAG,EAAE,cAAc,OAAOhE;IAC9D,MAAMiE,SAAS,MAAM,EAACH,iBAAAA,KAAKI,QAAQ,YAAbJ,iBAAiBvF,oBAAoB;QACzD4F,OAAO;QACPH,KAAKH,MAAMG,GAAG;QACdI,KAAKP,MAAMO,GAAG;QACdL,MAAMF,MAAME,IAAI,CAACM,IAAI;QACrBC,QAAQ;IACV;IACA,OAAOL,SAAShE,4BAA4B;AAC9C;AAEA,mGAAmG,GACnG,OAAO,SAASsE,uBAAuBC,IAAuB,EAAEC,OAA0B;IACxF,MAAMC,MAAMF,KAAKG,MAAM,GAAG,GAAGH,KAAKI,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG;IACjD,MAAMC,MAAMJ,QAAQE,MAAM,GAAG,CAAC,WAAW,EAAEF,QAAQG,IAAI,CAAC,MAAM,GAAG;IACjE,OAAO,GAAGF,IAAI,wHAAwH,EAAEG,KAAK,CAAC9B,KAAK,CAAC,GAAG;AACzJ;AAMA;;;;;CAKC,GACD,OAAO,eAAe+B,kBACpBrD,SAAoB,EACpBoC,KAWC;IAED,MAAMkB,UAAUtD,UAAUG,UAAU,CAAC,SAASC,GAAG,CAACgC,MAAMnC,MAAM;IAC9D,MAAMsD,SAASD,QAAQnD,UAAU,CAAC,WAAWC,GAAG,CAACgC,MAAM3B,QAAQ;IAC/D,MAAM+C,YAAYD,OAAOpD,UAAU,CAAC,YAAYC,GAAG,CAACgC,MAAMqB,eAAe;IACzE,MAAMC,SAASH,OAAOpD,UAAU,CAAC,YAAYC,GAAG,CAACgC,MAAMuB,SAAS;IAChE,OAAO3D,UAAU4D,cAAc,CAAC,OAAOC;QACrC,MAAM,CAACvB,MAAMlC,KAAK0D,QAAQC,QAAQ,GAAG,MAAMC,QAAQC,GAAG,CAAC;YAACJ,GAAGvD,GAAG,CAACgD;YAAUO,GAAGvD,GAAG,CAACiD;YAASM,GAAGvD,GAAG,CAACkD;YAAYK,GAAGvD,GAAG,CAACoD;SAAQ;QAC3H,IAAIK,QAAQG,MAAM,EAAE,OAAO;YAAEC,IAAI;YAAMR,WAAWvB,MAAMuB,SAAS;YAAEZ,MAAM,EAAE;YAAEC,SAAS,EAAE;QAAC;QACzF,IAAI,CAAC5C,IAAI8D,MAAM,IAAI9D,IAAIE,GAAG,CAAC,gBAAgB,MAAM,OAAO;YAAE6D,IAAI;YAAOC,OAAOpH;QAAkB;QAC9F,IAAI,CAAC8G,OAAOI,MAAM,EAAE,OAAO;YAAEC,IAAI;YAAOC,OAAOjH;QAA0B;QACzE,IAAI,CAACT,aAAa4F,MAAMF,MAAMG,GAAG,EAAE,cAAc,OAAO;YAAE4B,IAAI;YAAOC,OAAO7F;QAAwB;QACpG,MAAM8F,UAAUzF,KAAKwB,IAAIE,GAAG,CAAC,iBAAiB;QAC9C,MAAMgE,YAAYzG,gBAAgB;YAChC0G,YAAYnC,MAAMmC,UAAU;YAC5BC,QAAQ;YACRC,iBAAiBJ,YAAYjC,MAAMqB,eAAe;YAClDiB,iBAAiB;QACnB;QACA,IAAIJ,cAAc,WAAW,OAAO;YAAEH,IAAI;YAAOC,OAAOnH;QAA8B;QACtF,MAAM0H,QAAQ/H,kBAA2CkH,OAAOxD,GAAG,CAAC;QACpE,IAAI,CAACqE,OAAO,OAAO;YAAER,IAAI;YAAOC,OAAOlH;QAAsB;QAC7D,MAAM0H,UAAUrH,wBAAwBoH,OAAOvC,MAAMyC,KAAK,EAAEzC,MAAM0C,OAAO;QACzE,IAAI,CAACF,QAAQD,KAAK,EAAE,OAAO;YAAER,IAAI;YAAOC,OAAOQ,QAAQ5B,OAAO,CAACG,IAAI,CAAC,QAAQzE;QAA2B;QACvG,MAAMqG,SAASlI,kBAAkB+H,QAAQD,KAAK;QAC9C,IAAI,CAACI,QAAQ,OAAO;YAAEZ,IAAI;YAAOC,OAAOlH;QAAsB;QAC9D,yEAAyE;QACzE,4DAA4D;QAC5D,MAAM8H,OAAO,aAAMlB,OAAOlB,IAAI;QAC9B,OAAOoC,IAAI,CAAC,cAAc;QAC1BnB,GAAGoB,MAAM,CAACvB,QAAQ,aACbsB;YACHL,OAAOO,OAAOC,IAAI,CAACJ;YACnBK,aAAazG;YACb0G,WAAWjD,MAAMkD,GAAG;YACpBC,WAAWnD,MAAMkD,GAAG;YACpBE,WAAWpD,MAAMG,GAAG;YACpBkD,SAASrD,MAAMqD,OAAO;;QAExB,OAAO;YAAEtB,IAAI;YAAMR,WAAWvB,MAAMuB,SAAS;YAAEZ,MAAM6B,QAAQ7B,IAAI;YAAEC,SAAS4B,QAAQ5B,OAAO;QAAC;IAC9F;AACF;AAiBA,eAAe0C,iBACb1F,SAAoB,EACpB2F,GAAqC,EACrCC,SAA2C;QAG5BD;IADf,IAAI,CAACA,IAAI1F,MAAM,EAAE,OAAO3B;IACxB,MAAMY,UAASyG,cAAAA,IAAIzG,MAAM,YAAVyG,cAAc,CAAC;IAC9B,MAAM9F,QAAQ,MAAM+F,UAAU5F,WAAW2F,IAAI1F,MAAM;IACnD,MAAMwB,OAAOxC,YAAYC;IACzB,MAAMuB,WAAWuB,qBAAqBpD,KAAKM,MAAM,CAAC,SAAS,GAAG;QAAEW;QAAO4B;IAAK;IAC5E,IAAI,CAAChB,UAAU,OAAOhC;IACtB,MAAMoH,OAAOpI,gBAAgByB,QAAQ,CAAC6B,cAAgBD,mBAAmBC,aAAa;YAAElB;YAAO4B;QAAK;IACpG,IAAIjE,mBAAmBqI,KAAKf,OAAO,GAAG,OAAO;QAACpG;WAA+BmH,KAAKC,QAAQ;KAAC,CAAC3C,IAAI,CAAC;IACjG,OAAO;QAAE1C;QAAUoE,OAAOnH,UAAUwB,MAAM,CAAC,OAAO;QAAG4F,SAASe,KAAKf,OAAO;QAAEgB,UAAUD,KAAKC,QAAQ;IAAC;AACtG;AAEA,OAAO,SAASC,0BAA0B1D,OAAgC,CAAC,CAAC;QACvDA,kBACDA,iBACJA;IAFd,MAAM2D,cAAa3D,mBAAAA,KAAK2D,UAAU,YAAf3D,mBAAmBrE;IACtC,MAAM4H,aAAYvD,kBAAAA,KAAKuD,SAAS,YAAdvD,kBAAkBtC;IACpC,MAAMkG,SAAQ5D,cAAAA,KAAK4D,KAAK,YAAV5D,cAAcgB;IAC5B,OAAO,OAAO,EAAEsC,GAAG,EAAEL,GAAG,EAAEtF,SAAS,EAAE2C,GAAG,EAAEuD,QAAQ,EAAE;kBA0B1B;QAzBxB,qEAAqE;QACrE,MAAMC,gBAAQD,4BAAAA,SAAW,8BAAenI;QACxC,MAAMqI,UAAU,CAACC,UAAuC,aAAKnI,iBAAiBiI;gBAAQE;;QACtF,MAAMpG,SAAS0F,IAAI1F,MAAM;QACzB,IAAI,CAACA,QAAQ,OAAOmG,QAAQ9H;QAC5B,MAAMgI,OAAO,MAAMZ,iBAAiB1F,WAAW2F,KAAKC;QACpD,IAAI,OAAOU,SAAS,UAAU,OAAOF,QAAQE;QAC7C,MAAM3C,YAAY7F,gBAAgB6H;QAClC,MAAME,OAAO,MAAMG,WAAWhG,WAAW;YACvCuG,OAAOZ,IAAIY,KAAK;YAChBtG;YACAf,QAAQ;gBAAEsH,QAAQF,KAAK7F,QAAQ;gBAAEgG,YAAY;gBAAU9C,WAAW;YAAK;YACvE+C,OAAO/C;QACT;QACA,IAAI,WAAWkC,MAAM,OAAOO,QAAQP,KAAKzB,KAAK;QAC9C,MAAMuC,SAAS,CAAC5D,MAAyBC,UAA6C,CAAA;gBACpF4D,UAAU;gBACVhH,IAAIiG,KAAKjG,EAAE;gBACX+D;gBACA1D;gBACA4G,eAAehB,KAAKgB,aAAa;gBACjCC,OAAOjB,KAAKxG,IAAI;gBAChB0H,MAAMjE,uBAAuBC,MAAMC;YACrC,CAAA;QACA,IAAI6C,KAAKmB,OAAO,EAAE,OAAO9I,iBAAiBiI,OAAO;YAAEc,SAAS;gBAACN,OAAO,EAAE,EAAE,EAAE;aAAE;QAAC;QAC7E,MAAMO,UAAUvE,cAAAA,OAAQ,QAAA,AAAC,CAAA,MAAM3C,UAAUG,UAAU,CAAC,QAAQC,GAAG,CAACuF,IAAIY,KAAK,EAAEjG,GAAG,EAAC,EAAGsC,IAAI,cAA9D,QAAoE;QAC5F,MAAMN,OAAO,MAAMtC,UAAUG,UAAU,CAAC,SAASC,GAAG,CAACH,QAAQK,GAAG;QAChE,MAAM6G,UAAU,MAAMhF,0BAA0B;YAAEG;YAAMC,KAAKoD,IAAIH,SAAS;YAAE7C,KAAKuE;QAAQ,GAAG;YAAEzE,UAAUJ,KAAKI,QAAQ;QAAC;QACtH,IAAI0E,SAAS,OAAOjJ,iBAAiBiI,OAAO;YAAEiB,QAAQnJ,cAAckJ;QAAS;QAC7E,MAAM5C,aAAa9H,iBAAiByK,SAAkB;QACtD,MAAM5C,YAAYzG,gBAAgB;YAChC0G;YACAC,QAAQ;YACRC,iBAAiBoB,KAAKpC,eAAe,KAAKoC,KAAKwB,gBAAgB;YAC/D3C,iBAAiBmB,KAAKyB,kBAAkB,KAAKzB,KAAKpC,eAAe;QACnE;QACA,IAAIa,cAAc,WAAW,OAAOpG,iBAAiBiI,OAAO;YAAEiB,QAAQnJ,cAAchB;QAA+B;QACnH,MAAM+J,UAAU,MAAMf,MAAMjG,WAAW;YACrCC;YACAQ,UAAUoF,KAAKjG,EAAE;YACjB6D,iBAAiBoC,KAAKpC,eAAe;YACrCE;YACAkB,OAAOyB,KAAKzB,KAAK;YACjBC,SAASwB,KAAKxB,OAAO;YACrBvC,KAAKoD,IAAIH,SAAS;YAClBC,SAAS7H,cAAc+H;YACvBpB;YACAe;QACF;QACA,IAAI0B,QAAQ7C,EAAE,KAAK,OAAO,OAAOiC,QAAQY,QAAQ5C,KAAK;QACtD,OAAOlG,iBAAiBiI,OAAO;YAAEc,SAAS;gBAACN,OAAOK,QAAQjE,IAAI,EAAE;uBAAIiE,QAAQhE,OAAO;uBAAKsD,KAAKR,QAAQ;iBAAC;aAAE;QAAC;IAC3G;AACF;AAEA,OAAO,MAAMyB,yBAAyBxB,4BAA2B;AAWjE;;;;;CAKC,GACD,OAAO,SAASyB,+BAA+BnF,OAAqC,CAAC,CAAC;QACpEA,eACGA,kBACDA;IAFlB,MAAMoF,WAAUpF,gBAAAA,KAAKoF,OAAO,YAAZpF,gBAAgBtF;IAChC,MAAMiJ,cAAa3D,mBAAAA,KAAK2D,UAAU,YAAf3D,mBAAmBrE;IACtC,MAAM4H,aAAYvD,kBAAAA,KAAKuD,SAAS,YAAdvD,kBAAkBtC;IACpC,OAAO,OAAOiB;YAKiDA;QAJ7D,IAAI,CAACA,QAAQf,MAAM,EAAE,OAAO;YAAEyH,QAAQ;YAAKtD,OAAO9F;QAA2B;QAC7E,MAAMqJ,QAAQ,MAAMF,QAAQzG,QAAQf,MAAM;QAC1C,IAAI,CAAC0H,SAASA,UAAU3G,QAAQuF,KAAK,EAAE,OAAO;YAAEmB,QAAQ;YAAKtD,OAAO;QAAe;QACnF,MAAM9B,OAAO,MAAMtB,QAAQhB,SAAS,CAACG,UAAU,CAAC,SAASC,GAAG,CAACY,QAAQf,MAAM,EAAEK,GAAG;QAChF,MAAM6G,UAAU,MAAMhF,0BAA0B;YAAEG;YAAMC,GAAG,GAAEvB,eAAAA,QAAQuB,GAAG,YAAXvB,eAAe;YAAI2B,KAAK3B,QAAQ2B,GAAG;QAAC,GAAG;YAAEF,UAAUJ,KAAKI,QAAQ;QAAC;QAC9H,IAAI0E,SAAS,OAAO;YAAEO,QAAQ;YAAKtD,OAAO+C;QAAQ;QAClD,MAAMb,OAAO,MAAMZ,iBAAiB1E,QAAQhB,SAAS,EAAe;YAAEC,QAAQe,QAAQf,MAAM;YAAEf,QAAQ8B,QAAQ9B,MAAM;QAA4B,GAAG0G;QACnJ,IAAI,OAAOU,SAAS,UAAU,OAAO;YAAEoB,QAAQ;YAAKtD,OAAOkC;QAAK;QAChE,MAAMT,OAAO,MAAMG,WAAWhF,QAAQhB,SAAS,EAAE;YAC/CuG,OAAOvF,QAAQuF,KAAK;YACpBtG,QAAQe,QAAQf,MAAM;YACtBf,QAAQ;gBAAEsH,QAAQF,KAAK7F,QAAQ;gBAAEgG,YAAY;gBAAU9C,WAAW;YAAK;YACvE+C,OAAO;QACT;QACA,IAAI,WAAWb,MAAM,OAAOA;QAC5B,MAAMvB,YAAYzG,gBAAgB;YAChC0G,YAAY9H,iBAAiBuE,QAAQ2B,GAAG,EAAW;YACnD6B,QAAQ;YACRC,iBAAiBoB,KAAKpC,eAAe,KAAKoC,KAAKwB,gBAAgB;YAC/D3C,iBAAiBmB,KAAKyB,kBAAkB,KAAKzB,KAAKpC,eAAe;QACnE;QACA,OAAOa,cAAc,YAAY;YAAEoD,QAAQ;YAAKtD,OAAOnH;QAA8B,IAAI;IAC3F;AACF;AAEA,OAAO,MAAM2K,2BAA2BJ,iCAAgC;AAExE,2DAA2D,GAC3D,OAAO,SAASK;IACd1J,kBAAkBC,oBAAoBmJ,wBAAwB;QAAEO,WAAWzJ;IAAkC;IAC7GV,uBAAuBS,oBAAoBwJ;AAC7C"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-job-navigation-step.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { checkEntitlement } from '@aglyn/aglyn/app-utils/plan-entitlements'\nimport { holdsSiteKey } from '@aglyn/aglyn/app-utils/host-permissions'\nimport { orgPermissionLabel } from '@aglyn/aglyn/app-utils/org-permissions'\nimport { decodeStoredNodes, encodeStoredNodes } from '@aglyn/aglyn/app-utils/stored-nodes'\nimport { getLockdownVerdict } from '@aglyn/tenant-data-admin/server/lockdown'\nimport { resolveOrgIdForHost } from '@aglyn/tenant-data-admin/server/organizations'\nimport type { Firestore } from 'firebase-admin/firestore'\nimport { AI_EDIT_GONE_COPY, AI_EDIT_NEEDS_VERSIONING_COPY, AI_EDIT_NO_NODES_COPY, AI_EDIT_VERSION_GONE_COPY } from '../model/ai-edit-job'\nimport { isAiPlanNewRef } from '../model/ai-build-plan'\nimport { AI_BUILD_MADE_INPUT, type AiBuildMade } from '../model/ai-build-job'\nimport { aiBuildStoreLayoutOf } from '../model/ai-build-store-pages'\nimport type { AiJob, AiJobOutput } from '../model/ai-jobs.types'\nimport {\n aiLayoutWithMenuChanges,\n aiMenuChangesEmpty,\n aiMenuChangesOf,\n aiMenusOf,\n type AiMenuChanges,\n type AiMenuName,\n type AiMenuTarget,\n} from '../model/ai-layout-menus'\nimport { registerAiJobAdmission, type AiJobAdmission, type AiJobAdmissionRefusal } from './ai-job-admission'\nimport { aiOriginJobId } from './ai-job-draft-ids'\nimport { aiEditPlacement, aiEditVersionId, aiJobEditModel, readAiEditTarget } from './ai-job-edit-step'\nimport { aiLimitReview, aiUnspentOutcome } from './ai-job-generation'\nimport type { AiJobStepOutcome, AiJobStepRunner } from './ai-job-text-step'\nimport { registerAiJobStep } from './ai-jobs'\n\n/**\n * The `navigation` step (AGL-3728): a change to a site's header or footer\n * menu — add, take out, rename, relink or reorder its items — as a\n * first-class build operation, so Assist's one plan card can say \"add About\n * and Pricing to the menu, and take Blog out\" and have it done.\n *\n * NO MODEL. The planner already wrote the change as the item's arguments, in\n * words (`aiMenuChangesOf`); this applies it to the layout's own Besigner\n * elements in code (`aiLayoutWithMenuChanges`), so it costs no credits and\n * cannot invent a link: every destination is one of the site's pages, a page\n * this build made, a path on the site or an https address.\n *\n * ── Where it lands ───────────────────────────────────────────────────────\n *\n * As the `edit` step's change to a layout does: a NEW version beside the\n * layout's current one, which visitors keep seeing until a person publishes\n * the new one. A layout is always served, so without version history there is\n * nowhere for it to land and it is refused as a plan limit, charged nothing.\n * The version is named by the job's id, so a pass asked again finds what it\n * wrote.\n *\n * ── Who may ──────────────────────────────────────────────────────────────\n *\n * The editor's own rule for a layout's versions (`canWriteHostContent` and\n * `hostWritesFrozen` in the Firestore rules): a member with a write role on\n * the site (admin, editor or author), while no lockdown freezes the site, its\n * org or the platform. Asked at the door, again before the write, and the\n * role once more inside the transaction that writes.\n *\n * ── Audit ────────────────────────────────────────────────────────────────\n *\n * The layout it wrote is the job's output, which the job machine records as\n * an `ai.job.output` activity row on the site, as every other operation's is.\n */\n\nexport const AI_NAVIGATION_KIND = 'navigation' as const\n\n/**\n * ASSUMED: the least time the step needs — the site's pages, the layout and\n * its version, the org, and the one transaction that writes. No model, so it\n * fits an inline door.\n */\nexport const AI_JOB_NAVIGATION_STEP_MINIMUM_MS = 5_000\n\nexport const AI_NAVIGATION_NO_SITE_COPY = 'Open the site whose menu should change.'\n/** Names \"Edit site content\" (`site.edit`, AGL-4047), never a role. */\nexport const AI_NAVIGATION_ROLE_COPY = `Changing the site’s menus needs the \"${orgPermissionLabel('site.edit')}\" permission on this site — ask an organization admin.`\nexport const AI_NAVIGATION_LOCKED_COPY = 'This site is not accepting changes right now.'\nexport const AI_NAVIGATION_NO_LAYOUT_COPY = 'This site has no layout with a header or footer to change. Make one in Layouts first.'\nexport const AI_NAVIGATION_NOTHING_COPY = 'The request named no menu change this could make.'\n\n/** The name the new version carries in the layout's versions. */\nexport const AI_NAVIGATION_VERSION_NAME = 'Menu changes'\n\nconst text = (value: unknown): string => (typeof value === 'string' ? value.trim() : '')\n\n/** A path on the site, as a menu item may link it. */\nconst SITE_PATH = /^\\/(?:[A-Za-z0-9._~!$&'()*+,;=:@%-]+(?:\\/[A-Za-z0-9._~!$&'()*+,;=:@%-]+)*)?\\/?(?:[?#][^\\s]*)?$/\nconst SCREEN_ID = /^[A-Za-z0-9_-]{1,128}$/\n\nfunction buildMadeOf(inputs: Readonly<Record<string, unknown>> | null | undefined): AiBuildMade {\n const raw = (inputs?.[AI_BUILD_MADE_INPUT] ?? {}) as Partial<Record<'pages' | 'layouts', unknown>>\n const rows = (value: unknown, name: 'title' | 'name') =>\n (Array.isArray(value) ? value : []).flatMap((entry) => {\n const row = (entry ?? {}) as Record<string, unknown>\n return text(row[name]) && SCREEN_ID.test(text(row['id'])) ? [{ [name]: text(row[name]), id: text(row['id']) }] : []\n })\n return { pages: rows(raw.pages, 'title') as AiBuildMade['pages'], layouts: rows(raw.layouts, 'name') as AiBuildMade['layouts'] }\n}\n\n/** The site's pages a menu may link, by id, with the layout each renders inside. */\nexport interface AiNavigationSitePage {\n id: string\n title: string\n slug: string\n template: boolean\n layoutId: string | null\n}\n\n/** The site's pages: not deleted, not an email design. */\nexport async function readAiNavigationSitePages(firestore: Firestore, hostId: string): Promise<AiNavigationSitePage[]> {\n const snapshot = await firestore.collection('hosts').doc(hostId).collection('screens').select('displayName', 'slug', 'kind', 'deletedAt', 'layoutId').get()\n return snapshot.docs.flatMap((doc) => {\n const kind = doc.get('kind')\n if (doc.get('deletedAt') || (kind && kind !== 'template')) return []\n const layoutId = doc.get('layoutId')\n return [\n {\n id: doc.id,\n slug: String(doc.get('slug') ?? ''),\n title: String(doc.get('displayName') ?? ''),\n template: kind === 'template',\n layoutId: typeof layoutId === 'string' && layoutId ? layoutId : null,\n },\n ]\n })\n}\n\n/**\n * What a destination in an item's words links (AGL-3728): a page this build\n * made (`new:<title>`), one of the site's pages by id (`page:<id>` or the bare\n * id), a path on the site, or an https address; `null` for anything else.\n */\nexport function aiNavigationTarget(\n destination: string,\n context: { pages: readonly Pick<AiNavigationSitePage, 'id' | 'template'>[]; made: AiBuildMade },\n): AiMenuTarget | null {\n const value = destination.trim()\n const pageIds = new Set(context.pages.filter((page) => !page.template).map((page) => page.id))\n if (isAiPlanNewRef(value as string | null)) {\n const title = value.slice(value.indexOf(':') + 1).trim().toLowerCase()\n const made = context.made.pages.find((page) => page.title.trim().toLowerCase() === title)\n // A page this build was to make and did not is no destination.\n return made && pageIds.has(made.id) ? { screenId: made.id } : null\n }\n const id = value.replace(/^page:/i, '')\n if (pageIds.has(id)) return { screenId: id }\n if (value.startsWith('/') && !value.startsWith('//') && SITE_PATH.test(value)) return { href: value }\n if (/^https:\\/\\/[^\\s/?#]+\\.[^\\s/?#]+(?:[/?#]\\S*)?$/i.test(value)) return { href: value }\n return null\n}\n\n/** The layout an item changes: the one it names, else the one the site's pages render inside. */\nexport function aiNavigationLayoutOf(\n named: string,\n context: { pages: readonly AiNavigationSitePage[]; made: AiBuildMade },\n): string | null {\n if (isAiPlanNewRef(named as string | null)) {\n const name = named.slice(named.indexOf(':') + 1).trim().toLowerCase()\n return context.made.layouts.find((layout) => layout.name.trim().toLowerCase() === name)?.id ?? null\n }\n if (SCREEN_ID.test(named)) return named\n return aiBuildStoreLayoutOf(null, context.pages)\n}\n\n/** Why this member may not change this site's menus now, or `null`. */\nexport async function aiNavigationAccessRefusal(\n input: { host: FirebaseFirestore.DocumentSnapshot; uid: string; org: object | null },\n deps: { lockdown?: typeof getLockdownVerdict } = {},\n): Promise<string | null> {\n if (!holdsSiteKey(input.host, input.uid, 'site.edit')) return AI_NAVIGATION_ROLE_COPY\n const locked = await (deps.lockdown ?? getLockdownVerdict)({\n staff: false,\n uid: input.uid,\n org: input.org as never,\n host: input.host.data() as never,\n intent: 'write',\n })\n return locked ? AI_NAVIGATION_LOCKED_COPY : null\n}\n\n/** The new version's output note: what was done, what was not, and that it waits to be published. */\nexport function aiNavigationOutputNote(done: readonly string[], notDone: readonly string[]): string {\n const did = done.length ? `${done.join(' ')} ` : ''\n const not = notDone.length ? ` Not done: ${notDone.join(' ')}` : ''\n return `${did}Saved as a new version of the layout beside the one visitors see: open it to review it, and publish it when it is ready.${not}`.slice(0, 1_000)\n}\n\nexport type AiNavigationWrite =\n | { ok: true; versionId: string; done: string[]; notDone: string[] }\n | { ok: false; error: string }\n\n/**\n * The change written, in one transaction that reads the layout as it is\n * stored NOW: it still exists, its version is still there, the member still\n * holds a write role, and the plan still keeps version history. The change is\n * applied again to that version's nodes, so a save made since is kept.\n */\nexport async function writeAiNavigation(\n firestore: Firestore,\n input: {\n hostId: string\n layoutId: string\n sourceVersionId: string\n versionId: string\n menus: readonly AiMenuName[]\n changes: AiMenuChanges\n uid: string\n aiJobId: string\n versioning: boolean\n now: Date\n },\n): Promise<AiNavigationWrite> {\n const hostRef = firestore.collection('hosts').doc(input.hostId)\n const docRef = hostRef.collection('layouts').doc(input.layoutId)\n const sourceRef = docRef.collection('versions').doc(input.sourceVersionId)\n const newRef = docRef.collection('versions').doc(input.versionId)\n return firestore.runTransaction(async (tx): Promise<AiNavigationWrite> => {\n const [host, doc, source, already] = await Promise.all([tx.get(hostRef), tx.get(docRef), tx.get(sourceRef), tx.get(newRef)])\n if (already.exists) return { ok: true, versionId: input.versionId, done: [], notDone: [] }\n if (!doc.exists || doc.get('deletedAt') != null) return { ok: false, error: AI_EDIT_GONE_COPY }\n if (!source.exists) return { ok: false, error: AI_EDIT_VERSION_GONE_COPY }\n if (!holdsSiteKey(host, input.uid, 'site.edit')) return { ok: false, error: AI_NAVIGATION_ROLE_COPY }\n const pointer = text(doc.get('versionId')) || null\n const placement = aiEditPlacement({\n versioning: input.versioning,\n served: true,\n sourceIsPointer: pointer === input.sourceVersionId,\n sourceScheduled: false,\n })\n if (placement === 'refused') return { ok: false, error: AI_EDIT_NEEDS_VERSIONING_COPY }\n const nodes = decodeStoredNodes<Record<string, unknown>>(source.get('nodes'))\n if (!nodes) return { ok: false, error: AI_EDIT_NO_NODES_COPY }\n const applied = aiLayoutWithMenuChanges(nodes, input.menus, input.changes)\n if (!applied.nodes) return { ok: false, error: applied.notDone.join(' ') || AI_NAVIGATION_NOTHING_COPY }\n const packed = encodeStoredNodes(applied.nodes as never)\n if (!packed) return { ok: false, error: AI_EDIT_NO_NODES_COPY }\n // A copy of the version it started from — everything the editor stored —\n // with the changed menus, as the versions route copies one.\n const copy = { ...(source.data() as Record<string, unknown>) }\n delete copy['aiEditJobId']\n tx.create(newRef, {\n ...copy,\n nodes: Buffer.from(packed),\n displayName: AI_NAVIGATION_VERSION_NAME,\n createdAt: input.now,\n updatedAt: input.now,\n createdBy: input.uid,\n aiJobId: input.aiJobId,\n })\n return { ok: true, versionId: input.versionId, done: applied.done, notDone: applied.notDone }\n })\n}\n\nexport interface AiJobNavigationStepDeps {\n readTarget?: typeof readAiEditTarget\n readPages?: typeof readAiNavigationSitePages\n write?: typeof writeAiNavigation\n lockdown?: typeof getLockdownVerdict\n}\n\n/** What the step decided before writing: the layout, its version, the change and what was read away. */\ninterface AiNavigationPlan {\n layoutId: string\n menus: AiMenuName[]\n changes: AiMenuChanges\n problems: string[]\n}\n\nasync function navigationPlanOf(\n firestore: Firestore,\n job: Pick<AiJob, 'hostId' | 'inputs'>,\n readPages: typeof readAiNavigationSitePages,\n): Promise<AiNavigationPlan | string> {\n if (!job.hostId) return AI_NAVIGATION_NO_SITE_COPY\n const inputs = job.inputs ?? {}\n const pages = await readPages(firestore, job.hostId)\n const made = buildMadeOf(inputs)\n const layoutId = aiNavigationLayoutOf(text(inputs['layout']), { pages, made })\n if (!layoutId) return AI_NAVIGATION_NO_LAYOUT_COPY\n const read = aiMenuChangesOf(inputs, (destination) => aiNavigationTarget(destination, { pages, made }))\n if (aiMenuChangesEmpty(read.changes)) return [AI_NAVIGATION_NOTHING_COPY, ...read.problems].join(' ')\n return { layoutId, menus: aiMenusOf(inputs['menu']), changes: read.changes, problems: read.problems }\n}\n\nexport function createAiJobNavigationStep(deps: AiJobNavigationStepDeps = {}): AiJobStepRunner {\n const readTarget = deps.readTarget ?? readAiEditTarget\n const readPages = deps.readPages ?? readAiNavigationSitePages\n const write = deps.write ?? writeAiNavigation\n return async ({ job, now, firestore, org, modelFor }): Promise<AiJobStepOutcome> => {\n // No model is asked: the outcome records the edit step's at no cost.\n const model = modelFor?.('job.edit') ?? aiJobEditModel()\n const unspent = (failure: string): AiJobStepOutcome => ({ ...aiUnspentOutcome(model), failure })\n const hostId = job.hostId\n if (!hostId) return unspent(AI_NAVIGATION_NO_SITE_COPY)\n const plan = await navigationPlanOf(firestore, job, readPages)\n if (typeof plan === 'string') return unspent(plan)\n const versionId = aiEditVersionId(job)\n const read = await readTarget(firestore, {\n orgId: job.orgId,\n hostId,\n inputs: { target: plan.layoutId, targetKind: 'layout', versionId: null, newVersion: false },\n jobId: versionId,\n })\n if ('error' in read) return unspent(read.error)\n const output = (done: readonly string[], notDone: readonly string[]): AiJobOutput => ({\n resource: 'layout',\n id: read.id,\n versionId,\n hostId,\n hostSubdomain: read.hostSubdomain,\n label: read.name,\n note: aiNavigationOutputNote(done, notDone),\n })\n if (read.written) return aiUnspentOutcome(model, { outputs: [output([], [])] })\n const orgData = org ?? ((await firestore.collection('orgs').doc(job.orgId).get()).data() ?? null)\n const host = await firestore.collection('hosts').doc(hostId).get()\n const refused = await aiNavigationAccessRefusal({ host, uid: job.createdBy, org: orgData }, { lockdown: deps.lockdown })\n if (refused) return aiUnspentOutcome(model, { review: aiLimitReview(refused) })\n const versioning = checkEntitlement(orgData as never, 'versioning')\n const placement = aiEditPlacement({\n versioning,\n served: true,\n sourceIsPointer: read.sourceVersionId === read.pointerVersionId,\n sourceScheduled: read.scheduledVersionId === read.sourceVersionId,\n })\n if (placement === 'refused') return aiUnspentOutcome(model, { review: aiLimitReview(AI_EDIT_NEEDS_VERSIONING_COPY) })\n const written = await write(firestore, {\n hostId,\n layoutId: read.id,\n sourceVersionId: read.sourceVersionId,\n versionId,\n menus: plan.menus,\n changes: plan.changes,\n uid: job.createdBy,\n aiJobId: aiOriginJobId(job),\n versioning,\n now,\n })\n if (written.ok === false) return unspent(written.error)\n return aiUnspentOutcome(model, { outputs: [output(written.done, [...written.notDone, ...plan.problems])] })\n }\n}\n\nexport const runAiJobNavigationStep = createAiJobNavigationStep()\n\n// ── Admission ─────────────────────────────────────────────────────────────\n\nexport interface AiNavigationJobAdmissionDeps {\n ownerOf?: typeof resolveOrgIdForHost\n readTarget?: typeof readAiEditTarget\n readPages?: typeof readAiNavigationSitePages\n lockdown?: typeof getLockdownVerdict\n}\n\n/**\n * A navigation change is admitted on a site of the job's own org, for a\n * member who may write its content now, where the site has a layout and the\n * change has somewhere to land that no visitor sees on this plan. Refused in\n * those words before anything exists.\n */\nexport function createAiNavigationJobAdmission(deps: AiNavigationJobAdmissionDeps = {}): AiJobAdmission {\n const ownerOf = deps.ownerOf ?? resolveOrgIdForHost\n const readTarget = deps.readTarget ?? readAiEditTarget\n const readPages = deps.readPages ?? readAiNavigationSitePages\n return async (context): Promise<AiJobAdmissionRefusal | null> => {\n if (!context.hostId) return { status: 400, error: AI_NAVIGATION_NO_SITE_COPY }\n const owner = await ownerOf(context.hostId)\n if (!owner || owner !== context.orgId) return { status: 404, error: 'Unknown site' }\n const host = await context.firestore.collection('hosts').doc(context.hostId).get()\n const refused = await aiNavigationAccessRefusal({ host, uid: context.uid ?? '', org: context.org }, { lockdown: deps.lockdown })\n if (refused) return { status: 403, error: refused }\n const plan = await navigationPlanOf(context.firestore as Firestore, { hostId: context.hostId, inputs: context.inputs as Record<string, unknown> }, readPages)\n if (typeof plan === 'string') return { status: 400, error: plan }\n const read = await readTarget(context.firestore, {\n orgId: context.orgId,\n hostId: context.hostId,\n inputs: { target: plan.layoutId, targetKind: 'layout', versionId: null, newVersion: false },\n jobId: null,\n })\n if ('error' in read) return read\n const placement = aiEditPlacement({\n versioning: checkEntitlement(context.org as never, 'versioning'),\n served: true,\n sourceIsPointer: read.sourceVersionId === read.pointerVersionId,\n sourceScheduled: read.scheduledVersionId === read.sourceVersionId,\n })\n return placement === 'refused' ? { status: 403, error: AI_EDIT_NEEDS_VERSIONING_COPY } : null\n }\n}\n\nexport const aiNavigationJobAdmission = createAiNavigationJobAdmission()\n\n/** Registers the navigation step and its door (AGL-3728). */\nexport function registerAiNavigationJob(): void {\n registerAiJobStep(AI_NAVIGATION_KIND, runAiJobNavigationStep, { minimumMs: AI_JOB_NAVIGATION_STEP_MINIMUM_MS })\n registerAiJobAdmission(AI_NAVIGATION_KIND, aiNavigationJobAdmission)\n}\n"],"names":["checkEntitlement","holdsSiteKey","orgPermissionLabel","decodeStoredNodes","encodeStoredNodes","getLockdownVerdict","resolveOrgIdForHost","AI_EDIT_GONE_COPY","AI_EDIT_NEEDS_VERSIONING_COPY","AI_EDIT_NO_NODES_COPY","AI_EDIT_VERSION_GONE_COPY","isAiPlanNewRef","AI_BUILD_MADE_INPUT","aiBuildStoreLayoutOf","aiLayoutWithMenuChanges","aiMenuChangesEmpty","aiMenuChangesOf","aiMenusOf","registerAiJobAdmission","aiOriginJobId","aiEditPlacement","aiEditVersionId","aiJobEditModel","readAiEditTarget","aiLimitReview","aiUnspentOutcome","registerAiJobStep","AI_NAVIGATION_KIND","AI_JOB_NAVIGATION_STEP_MINIMUM_MS","AI_NAVIGATION_NO_SITE_COPY","AI_NAVIGATION_ROLE_COPY","AI_NAVIGATION_LOCKED_COPY","AI_NAVIGATION_NO_LAYOUT_COPY","AI_NAVIGATION_NOTHING_COPY","AI_NAVIGATION_VERSION_NAME","text","value","trim","SITE_PATH","SCREEN_ID","buildMadeOf","inputs","raw","rows","name","Array","isArray","flatMap","entry","row","test","id","pages","layouts","readAiNavigationSitePages","firestore","hostId","snapshot","collection","doc","select","get","docs","kind","layoutId","slug","String","title","template","aiNavigationTarget","destination","context","pageIds","Set","filter","page","map","slice","indexOf","toLowerCase","made","find","has","screenId","replace","startsWith","href","aiNavigationLayoutOf","named","layout","aiNavigationAccessRefusal","input","deps","host","uid","locked","lockdown","staff","org","data","intent","aiNavigationOutputNote","done","notDone","did","length","join","not","writeAiNavigation","hostRef","docRef","sourceRef","sourceVersionId","newRef","versionId","runTransaction","tx","source","already","Promise","all","exists","ok","error","pointer","placement","versioning","served","sourceIsPointer","sourceScheduled","nodes","applied","menus","changes","packed","copy","create","Buffer","from","displayName","createdAt","now","updatedAt","createdBy","aiJobId","navigationPlanOf","job","readPages","read","problems","createAiJobNavigationStep","readTarget","write","modelFor","model","unspent","failure","plan","orgId","target","targetKind","newVersion","jobId","output","resource","hostSubdomain","label","note","written","outputs","orgData","refused","review","pointerVersionId","scheduledVersionId","runAiJobNavigationStep","createAiNavigationJobAdmission","ownerOf","status","owner","aiNavigationJobAdmission","registerAiNavigationJob","minimumMs"],"mappings":"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"}
|
|
@@ -375,30 +375,40 @@ export interface AiLayoutPageRunInput {
|
|
|
375
375
|
*/
|
|
376
376
|
export declare function aiRunLayoutPage(input: AiLayoutPageRunInput): Promise<AiValidatedGeneration<AiLayoutPageBuilt>>;
|
|
377
377
|
/**
|
|
378
|
-
* What
|
|
379
|
-
* are the source's and fixed,
|
|
380
|
-
*
|
|
378
|
+
* What a main page's design answer is told (AGL-4107), cached: the page's
|
|
379
|
+
* words and structure are the source's and fixed, read by code, and the
|
|
380
|
+
* answer only chooses how its sections are drawn. The tool has no field for
|
|
381
|
+
* a word of copy, a line or a block, so nothing it says can reword or move
|
|
382
|
+
* one.
|
|
381
383
|
*/
|
|
382
|
-
export declare const
|
|
383
|
-
/** The
|
|
384
|
-
export declare const
|
|
385
|
-
/**
|
|
386
|
-
export declare function
|
|
384
|
+
export declare const AI_LAYOUT_DESIGN_TEXT: string;
|
|
385
|
+
/** The design answer's cached instructions, and the rule that fenced text is data. */
|
|
386
|
+
export declare const AI_JOB_PAGE_DESIGN_INSTRUCTIONS: readonly AiSystemBlock[];
|
|
387
|
+
/** A design answer's user turn: the page, the kind of site it is, and its structure, the sections' names fenced. */
|
|
388
|
+
export declare function aiLayoutDesignPrompt(input: {
|
|
387
389
|
job: Pick<AiJob, 'inputs' | '$id'>;
|
|
388
390
|
screen: Pick<AiBuildPlanScreen, 'title' | 'slug' | 'sections'>;
|
|
389
|
-
doc: Pick<AiSiteImportDocument, 'blocks' | 'title' | 'url'>;
|
|
391
|
+
doc: Pick<AiSiteImportDocument, 'blocks' | 'title' | 'url' | 'layout'>;
|
|
390
392
|
}): string;
|
|
391
393
|
/**
|
|
392
|
-
* The check a page brought in is held to (AGL-4084):
|
|
393
|
-
*
|
|
394
|
-
*
|
|
395
|
-
* words.
|
|
394
|
+
* The check a page brought in is held to (AGL-4084, AGL-4107): its layout
|
|
395
|
+
* compiled by the site compiler with every word as written — with the design
|
|
396
|
+
* answer where one is given — stored, and checked whole as a page of its
|
|
397
|
+
* owner's own words. An answer whose design cannot be drawn is set aside and
|
|
398
|
+
* the page is drawn as its source lays it out, so no answer is asked again
|
|
399
|
+
* for what code decides. Nothing in an answer can change a word.
|
|
396
400
|
*/
|
|
397
401
|
export declare function aiImportedPageCheck(input: Pick<AiLayoutPageCheckInput, 'screen' | 'sectionIds' | 'targets' | 'context' | 'motion' | 'design'> & {
|
|
398
402
|
doc: AiSiteImportDocument;
|
|
403
|
+
language?: string;
|
|
399
404
|
}): (answer: Record<string, unknown> | null) => {
|
|
400
405
|
value: AiLayoutPageBuilt | null;
|
|
401
406
|
violations: AiDoctrineViolation[];
|
|
402
407
|
};
|
|
403
|
-
/** The
|
|
404
|
-
export declare const
|
|
408
|
+
/** The design answer's kind of generation, which shares the page's ceilings. */
|
|
409
|
+
export declare const AI_LAYOUT_DESIGN_KIND = "layout-page";
|
|
410
|
+
/**
|
|
411
|
+
* The most a design answer runs to (AGL-4107): a few tokens a section and a
|
|
412
|
+
* group, with room to think, inside a page's ceiling on the balanced tier.
|
|
413
|
+
*/
|
|
414
|
+
export declare const AI_LAYOUT_DESIGN_MAX_TOKENS = 3000;
|