@aglyn/plugins-ai 1.0.0-beta.231 → 1.0.0-beta.232
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +17 -17
- package/src/lib/activity/ai-activity-actions.js +8 -4
- package/src/lib/activity/ai-activity-actions.js.map +1 -1
- package/src/lib/components/ai-job-follow.component.js +1 -0
- package/src/lib/components/ai-job-follow.component.js.map +1 -1
- package/src/lib/components/ai-job-links.js +13 -0
- package/src/lib/components/ai-job-links.js.map +1 -1
- package/src/lib/components/ai-jobs-list-page.component.js +1 -0
- package/src/lib/components/ai-jobs-list-page.component.js.map +1 -1
- package/src/lib/components/ai-media-create.component.d.ts +20 -7
- package/src/lib/components/ai-media-create.component.js +107 -55
- package/src/lib/components/ai-media-create.component.js.map +1 -1
- package/src/lib/components/ai-seo-fields-card.component.js +1 -0
- package/src/lib/components/ai-seo-fields-card.component.js.map +1 -1
- package/src/lib/components/ai-site-memory-card.component.d.ts +32 -0
- package/src/lib/components/ai-site-memory-card.component.js +187 -0
- package/src/lib/components/ai-site-memory-card.component.js.map +1 -0
- package/src/lib/components/ai-site-start-card.component.js +80 -77
- package/src/lib/components/ai-site-start-card.component.js.map +1 -1
- package/src/lib/components/ai-theme-proposal-card.component.js +4 -0
- package/src/lib/components/ai-theme-proposal-card.component.js.map +1 -1
- package/src/lib/components/ai-usage-strip.component.js +1 -0
- package/src/lib/components/ai-usage-strip.component.js.map +1 -1
- package/src/lib/components/assist-panel.component.d.ts +10 -0
- package/src/lib/components/assist-panel.component.js +119 -9
- package/src/lib/components/assist-panel.component.js.map +1 -1
- package/src/lib/components/assist-signals-page.component.js +2 -0
- package/src/lib/components/assist-signals-page.component.js.map +1 -1
- package/src/lib/components/billing-ai-allotments.component.js +3 -0
- package/src/lib/components/billing-ai-allotments.component.js.map +1 -1
- package/src/lib/components/billing-ai-top-users.component.js +1 -0
- package/src/lib/components/billing-ai-top-users.component.js.map +1 -1
- package/src/lib/components/billing-assist-overage-card.component.js +2 -0
- package/src/lib/components/billing-assist-overage-card.component.js.map +1 -1
- package/src/lib/components/member-ai-usage-card.component.js +10 -0
- package/src/lib/components/member-ai-usage-card.component.js.map +1 -1
- package/src/lib/components/staff-org-ai-card.component.js +1 -0
- package/src/lib/components/staff-org-ai-card.component.js.map +1 -1
- package/src/lib/components/staff-org-ai-conversations.component.d.ts +23 -0
- package/src/lib/components/staff-org-ai-conversations.component.js +346 -0
- package/src/lib/components/staff-org-ai-conversations.component.js.map +1 -0
- package/src/lib/jobs/ai-build-capabilities.d.ts +13 -1
- package/src/lib/jobs/ai-build-capabilities.js +101 -7
- package/src/lib/jobs/ai-build-capabilities.js.map +1 -1
- package/src/lib/jobs/ai-business-profile-prefill.d.ts +29 -0
- package/src/lib/jobs/ai-business-profile-prefill.js +85 -0
- package/src/lib/jobs/ai-business-profile-prefill.js.map +1 -0
- package/src/lib/jobs/ai-job-build-step.js +3 -1
- package/src/lib/jobs/ai-job-build-step.js.map +1 -1
- package/src/lib/jobs/ai-job-edit-step.d.ts +225 -0
- package/src/lib/jobs/ai-job-edit-step.js +631 -0
- package/src/lib/jobs/ai-job-edit-step.js.map +1 -0
- package/src/lib/jobs/ai-job-insight-step.js +21 -4
- package/src/lib/jobs/ai-job-insight-step.js.map +1 -1
- package/src/lib/jobs/ai-job-layout-language.d.ts +8 -3
- package/src/lib/jobs/ai-job-layout-language.js +8 -2
- package/src/lib/jobs/ai-job-layout-language.js.map +1 -1
- package/src/lib/jobs/ai-job-layout-step.js +7 -6
- package/src/lib/jobs/ai-job-layout-step.js.map +1 -1
- package/src/lib/jobs/ai-job-logic-step.d.ts +20 -0
- package/src/lib/jobs/ai-job-logic-step.js +87 -6
- package/src/lib/jobs/ai-job-logic-step.js.map +1 -1
- package/src/lib/jobs/ai-job-page-language.d.ts +52 -7
- package/src/lib/jobs/ai-job-page-language.js +72 -9
- package/src/lib/jobs/ai-job-page-language.js.map +1 -1
- package/src/lib/jobs/ai-job-page-step.js +12 -2
- package/src/lib/jobs/ai-job-page-step.js.map +1 -1
- package/src/lib/jobs/ai-job-plan-step.d.ts +19 -5
- package/src/lib/jobs/ai-job-plan-step.js +54 -20
- package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
- package/src/lib/jobs/ai-job-site-content.d.ts +163 -0
- package/src/lib/jobs/ai-job-site-content.js +443 -0
- package/src/lib/jobs/ai-job-site-content.js.map +1 -0
- package/src/lib/jobs/ai-job-site-look.d.ts +112 -0
- package/src/lib/jobs/ai-job-site-look.js +322 -0
- package/src/lib/jobs/ai-job-site-look.js.map +1 -0
- package/src/lib/jobs/ai-job-site-step.d.ts +26 -5
- package/src/lib/jobs/ai-job-site-step.js +163 -24
- package/src/lib/jobs/ai-job-site-step.js.map +1 -1
- package/src/lib/jobs/ai-jobs-notify.d.ts +6 -1
- package/src/lib/jobs/ai-jobs-notify.js +15 -3
- package/src/lib/jobs/ai-jobs-notify.js.map +1 -1
- package/src/lib/layout-language/ai-layout-compiler.d.ts +9 -0
- package/src/lib/layout-language/ai-layout-compiler.js +120 -33
- package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
- package/src/lib/layout-language/ai-layout-frame.js +5 -4
- package/src/lib/layout-language/ai-layout-frame.js.map +1 -1
- package/src/lib/layout-language/ai-layout-language.d.ts +12 -5
- package/src/lib/layout-language/ai-layout-language.js +92 -9
- package/src/lib/layout-language/ai-layout-language.js.map +1 -1
- package/src/lib/layout-language/ai-layout-pictures.d.ts +144 -0
- package/src/lib/layout-language/ai-layout-pictures.js +214 -0
- package/src/lib/layout-language/ai-layout-pictures.js.map +1 -0
- package/src/lib/layout-language/ai-layout-store.d.ts +2 -0
- package/src/lib/layout-language/ai-layout-store.js +7 -1
- package/src/lib/layout-language/ai-layout-store.js.map +1 -1
- package/src/lib/model/ai-build-progress.js +4 -1
- package/src/lib/model/ai-build-progress.js.map +1 -1
- package/src/lib/model/ai-edit-job.d.ts +109 -0
- package/src/lib/model/ai-edit-job.js +157 -0
- package/src/lib/model/ai-edit-job.js.map +1 -0
- package/src/lib/model/ai-job-activity.js +1 -0
- package/src/lib/model/ai-job-activity.js.map +1 -1
- package/src/lib/model/ai-jobs.types.d.ts +3 -1
- package/src/lib/model/ai-jobs.types.js.map +1 -1
- package/src/lib/model/ai-logic-job.d.ts +18 -1
- package/src/lib/model/ai-logic-job.js +24 -3
- package/src/lib/model/ai-logic-job.js.map +1 -1
- package/src/lib/model/ai-media-credits.d.ts +8 -4
- package/src/lib/model/ai-media-credits.js +11 -4
- package/src/lib/model/ai-media-credits.js.map +1 -1
- package/src/lib/model/ai-media-kinds.d.ts +68 -0
- package/src/lib/model/ai-media-kinds.js +98 -0
- package/src/lib/model/ai-media-kinds.js.map +1 -0
- package/src/lib/model/ai-site-build-progress.d.ts +4 -0
- package/src/lib/model/ai-site-build-progress.js +28 -11
- package/src/lib/model/ai-site-build-progress.js.map +1 -1
- package/src/lib/model/ai-site-context.d.ts +111 -0
- package/src/lib/model/ai-site-context.js +222 -0
- package/src/lib/model/ai-site-context.js.map +1 -0
- package/src/lib/model/ai-site-job.d.ts +10 -2
- package/src/lib/model/ai-site-job.js +12 -5
- package/src/lib/model/ai-site-job.js.map +1 -1
- package/src/lib/model/ai-site-kinds.d.ts +164 -0
- package/src/lib/model/ai-site-kinds.js +1942 -0
- package/src/lib/model/ai-site-kinds.js.map +1 -0
- package/src/lib/model/ai-site-look.d.ts +150 -0
- package/src/lib/model/ai-site-look.js +1236 -0
- package/src/lib/model/ai-site-look.js.map +1 -0
- package/src/lib/model/ai-site-memory.d.ts +80 -0
- package/src/lib/model/ai-site-memory.js +171 -0
- package/src/lib/model/ai-site-memory.js.map +1 -0
- package/src/lib/model/ai-site-start.d.ts +10 -1
- package/src/lib/model/ai-site-start.js +16 -2
- package/src/lib/model/ai-site-start.js.map +1 -1
- package/src/lib/model/assist-follow-up.d.ts +92 -0
- package/src/lib/model/assist-follow-up.js +128 -0
- package/src/lib/model/assist-follow-up.js.map +1 -0
- package/src/lib/plugin-config.js +2 -0
- package/src/lib/plugin-config.js.map +1 -1
- package/src/lib/plugin.js +20 -1
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/providers/anthropic.d.ts +9 -1
- package/src/lib/providers/anthropic.js +143 -9
- package/src/lib/providers/anthropic.js.map +1 -1
- package/src/lib/providers/catalog.d.ts +37 -7
- package/src/lib/providers/catalog.js +103 -11
- package/src/lib/providers/catalog.js.map +1 -1
- package/src/lib/providers/contract.d.ts +29 -0
- package/src/lib/providers/contract.js.map +1 -1
- package/src/lib/providers/image-contract.d.ts +22 -1
- package/src/lib/providers/image-contract.js +40 -1
- package/src/lib/providers/image-contract.js.map +1 -1
- package/src/lib/providers/image-endpoints.d.ts +24 -0
- package/src/lib/providers/image-endpoints.js +28 -0
- package/src/lib/providers/image-endpoints.js.map +1 -0
- package/src/lib/providers/model-choice.js +23 -2
- package/src/lib/providers/model-choice.js.map +1 -1
- package/src/lib/providers/routing.js +18 -0
- package/src/lib/providers/routing.js.map +1 -1
- package/src/lib/providers/vertex-image-endpoint.d.ts +48 -0
- package/src/lib/providers/vertex-image-endpoint.js +80 -0
- package/src/lib/providers/vertex-image-endpoint.js.map +1 -0
- package/src/lib/providers/vertex-image.d.ts +13 -27
- package/src/lib/providers/vertex-image.js +15 -42
- package/src/lib/providers/vertex-image.js.map +1 -1
- package/src/lib/runtime/ai-blog-post-generation.d.ts +62 -0
- package/src/lib/runtime/ai-blog-post-generation.js +89 -0
- package/src/lib/runtime/ai-blog-post-generation.js.map +1 -0
- package/src/lib/runtime/ai-dev-env.d.ts +53 -0
- package/src/lib/runtime/ai-dev-env.js +72 -0
- package/src/lib/runtime/ai-dev-env.js.map +1 -0
- package/src/lib/runtime/ai-dev-replay.d.ts +116 -0
- package/src/lib/runtime/ai-dev-replay.js +313 -0
- package/src/lib/runtime/ai-dev-replay.js.map +1 -0
- package/src/lib/runtime/ai-doctrine.js +5 -1
- package/src/lib/runtime/ai-doctrine.js.map +1 -1
- package/src/lib/runtime/ai-eval-live.js +4 -0
- package/src/lib/runtime/ai-eval-live.js.map +1 -1
- package/src/lib/runtime/ai-eval.d.ts +13 -1
- package/src/lib/runtime/ai-eval.js +84 -1
- package/src/lib/runtime/ai-eval.js.map +1 -1
- package/src/lib/runtime/ai-live-batch.d.ts +45 -0
- package/src/lib/runtime/ai-live-batch.js +89 -0
- package/src/lib/runtime/ai-live-batch.js.map +1 -0
- package/src/lib/runtime/ai-runtime.js +46 -2
- package/src/lib/runtime/ai-runtime.js.map +1 -1
- package/src/lib/runtime/site-context.d.ts +58 -0
- package/src/lib/runtime/site-context.js +127 -0
- package/src/lib/runtime/site-context.js.map +1 -0
- package/src/lib/server/ai-admin-conversations.d.ts +22 -0
- package/src/lib/server/ai-admin-conversations.js +197 -0
- package/src/lib/server/ai-admin-conversations.js.map +1 -0
- package/src/lib/server/ai-media-image.d.ts +5 -5
- package/src/lib/server/ai-media-image.js +25 -11
- package/src/lib/server/ai-media-image.js.map +1 -1
- package/src/lib/server/ai-media-raster-prompt.d.ts +34 -0
- package/src/lib/server/ai-media-raster-prompt.js +53 -0
- package/src/lib/server/ai-media-raster-prompt.js.map +1 -0
- package/src/lib/server/assist-chat.d.ts +11 -0
- package/src/lib/server/assist-chat.js +57 -18
- package/src/lib/server/assist-chat.js.map +1 -1
- package/src/lib/server/assist-edit-applied.js +16 -3
- package/src/lib/server/assist-edit-applied.js.map +1 -1
- package/src/lib/server/assist-view-context.d.ts +19 -1
- package/src/lib/server/assist-view-context.js +38 -1
- package/src/lib/server/assist-view-context.js.map +1 -1
- package/src/lib/server.js +10 -0
- package/src/lib/server.js.map +1 -1
- package/src/lib/subprocessors.js +17 -1
- package/src/lib/subprocessors.js.map +1 -1
- package/src/lib/tools/ai-blog-post-tool.d.ts +60 -0
- package/src/lib/tools/ai-blog-post-tool.js +175 -0
- package/src/lib/tools/ai-blog-post-tool.js.map +1 -0
- package/src/lib/usage/assist-usage.d.ts +3 -0
- package/src/lib/usage/assist-usage.js +4 -2
- package/src/lib/usage/assist-usage.js.map +1 -1
- package/src/lib/usage/staff-org-ai-conversations.d.ts +103 -0
- package/src/lib/usage/staff-org-ai-conversations.js +152 -0
- package/src/lib/usage/staff-org-ai-conversations.js.map +1 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-build-capabilities.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 type { AglynOrgBilling } from '@aglyn/aglyn/foundation/definitions/org-billing.types'\nimport { isHostPluginEnabled } from '@aglyn/aglyn/plugin-manager/enabled-plugins'\nimport {\n pluginAiCapabilities,\n registerPluginAiCapability,\n type PluginAiCapability,\n type ResolvedPluginAiCapability,\n} from '@aglyn/aglyn/plugin-manager/plugin-ai-capabilities'\nimport { filterEnabledPluginsByReleaseFlags } from '@aglyn/tenant-data-admin/server/release-flags'\nimport { AI_TEMPLATE_SUBJECTS } from '../model/ai-template-subjects'\nimport { AI_SITE_PASS_CREDITS } from '../model/ai-site-job'\nimport type { AiBuildOps } from '../model/ai-build-job'\nimport { aiJobStepRunnerFor } from './ai-jobs'\n\n/**\n * What THIS plugin lets a build make (AGL-3616), registered on the core's\n * capability contract exactly as any other plugin registers its own, so the\n * planner, the gates and the estimate read one list and name no plugin.\n *\n * Every one is built by a runner this plugin already has (`runnerKind`):\n * pages, layouts, forms, components and email designs are the plan's\n * creations and screens; templates, campaigns and automations are items with\n * arguments. A campaign and an automation are still WRITTEN by the marketing\n * and workflows plugins, through the writers their runners already call.\n */\n\n/** This plugin's id, as its registrations name their owner. */\nconst AI_PLUGIN_ID = 'ai'\n\nconst NO_ARGS = { type: 'object', properties: {}, additionalProperties: false } as const\n\nconst passes = (count: number) => () => count * AI_SITE_PASS_CREDITS\n\n/** The operations this plugin owns, as it registers them. */\nexport const AI_OWNED_CAPABILITIES: readonly PluginAiCapability[] = [\n {\n op: 'page',\n noun: 'page',\n where: 'Pages',\n intents: ['new pages: home, about, services, contact, pricing, a landing page'],\n argsSchema: NO_ARGS,\n maxPerPlan: 8,\n freeAllowed: true,\n runnerKind: 'page',\n estimateCredits: passes(6),\n degrade: 'omit',\n },\n {\n op: 'layout',\n noun: 'layout',\n where: 'Layouts',\n intents: ['a header and footer shared by pages'],\n argsSchema: NO_ARGS,\n maxPerPlan: 1,\n freeAllowed: true,\n runnerKind: 'layout',\n estimateCredits: passes(1),\n degrade: 'fallback',\n },\n {\n op: 'form',\n noun: 'form',\n where: 'Forms',\n intents: ['a contact form, a quote request, a sign-up form'],\n argsSchema: NO_ARGS,\n maxPerPlan: 3,\n freeAllowed: true,\n runnerKind: 'form',\n estimateCredits: passes(1),\n degrade: 'omit',\n },\n {\n op: 'component',\n noun: 'component',\n where: 'Components',\n intents: ['a reusable card or block placed on several pages'],\n argsSchema: NO_ARGS,\n maxPerPlan: 4,\n freeAllowed: false,\n runnerKind: 'component',\n estimateCredits: passes(1),\n degrade: 'omit',\n },\n {\n op: 'email',\n noun: 'email design',\n where: 'Emails → Templates',\n intents: ['an email design: a welcome, a reply, an announcement'],\n argsSchema: NO_ARGS,\n maxPerPlan: 2,\n freeAllowed: false,\n runnerKind: 'email',\n estimateCredits: passes(1),\n degrade: 'omit',\n },\n {\n op: 'template',\n noun: 'page template',\n where: 'Templates',\n intents: ['a page template for blog posts, products or authors'],\n argsSchema: {\n type: 'object',\n properties: {\n subject: {\n type: 'string',\n description: 'What each page shows: entry (a collection entry), product or author.',\n enum: AI_TEMPLATE_SUBJECTS,\n },\n collectionId: {\n type: 'string',\n description: 'For entry: the collection id from the site inventory.',\n maxLength: 100,\n },\n },\n required: ['subject'],\n additionalProperties: false,\n },\n maxPerPlan: 2,\n freeAllowed: false,\n runnerKind: 'template',\n estimateCredits: passes(6),\n degrade: 'omit',\n },\n {\n op: 'campaign',\n noun: 'email campaign',\n where: 'Marketing → Campaigns',\n intents: ['an email campaign drafted and left unsent'],\n argsSchema: {\n type: 'object',\n properties: {\n name: { type: 'string', description: 'What the campaign is called.', maxLength: 120 },\n },\n additionalProperties: false,\n },\n maxPerPlan: 2,\n freeAllowed: false,\n runnerKind: 'campaign',\n estimateCredits: passes(2),\n degrade: 'omit',\n },\n {\n op: 'workflow',\n noun: 'automation',\n where: 'Automations',\n intents: ['an automation: when a form is sent, do something'],\n argsSchema: NO_ARGS,\n maxPerPlan: 2,\n freeAllowed: false,\n runnerKind: 'workflow',\n estimateCredits: passes(1),\n degrade: 'omit',\n },\n]\n\n/** Registers this plugin's build operations; the console surface calls it. */\nexport function registerAiBuildCapabilities(): void {\n for (const capability of AI_OWNED_CAPABILITIES) {\n registerPluginAiCapability(capability, { pluginId: AI_PLUGIN_ID })\n }\n}\n\n/** What decides which operations a build may use here. */\nexport interface AiBuildOpsContext {\n orgId: string\n hostId: string | null\n org: Partial<AglynOrgBilling> | null\n /** The site document, for the plugins switched on and off on it. */\n host: Readonly<Record<string, unknown>> | null\n freeTaste: boolean\n}\n\nexport interface AiBuildOpsDeps {\n /** The registered capabilities; the core registry's otherwise. */\n capabilities?: () => ResolvedPluginAiCapability[]\n /** The release-flag read; the platform's otherwise. */\n releasedPlugins?: (pluginIds: string[], orgId: string) => Promise<string[]>\n /** Whether a runner is registered for a kind; the machine's otherwise. */\n hasRunner?: (kind: string) => boolean\n}\n\n/**\n * The operations a build may plan on this site, by op (AGL-3616): every\n * registered capability whose owner runs here — switched on for the\n * workspace and the site, past its release flag — whose entitlement the plan\n * holds, which the Free taste may use where the workspace is on it, and,\n * for an AI-run operation, whose runner this process loaded. One release-flag\n * read for every owner at once. What a member may do and what an allowance\n * has left are the owner's to say when the item runs (`refusal`).\n */\nexport async function aiBuildOps(context: AiBuildOpsContext, deps: AiBuildOpsDeps = {}): Promise<AiBuildOps> {\n const all = (deps.capabilities ?? pluginAiCapabilities)()\n const hasRunner = deps.hasRunner ?? ((kind: string) => aiJobStepRunnerFor(kind as never) !== null)\n const owners = [...new Set(all.map((one) => one.pluginId).filter((id) => id !== AI_PLUGIN_ID))]\n const released = new Set(\n owners.length\n ? await (deps.releasedPlugins ??\n ((ids, orgId) => filterEnabledPluginsByReleaseFlags(ids, { orgId, authorization: null })))(owners, context.orgId)\n : [],\n )\n const ops = new Map<string, PluginAiCapability>()\n for (const { pluginId, capability } of all) {\n if (pluginId !== AI_PLUGIN_ID) {\n if (!released.has(pluginId)) continue\n if (!isHostPluginEnabled(context.org as { enabledPlugins?: string[] } | null, context.host, pluginId)) continue\n }\n if (capability.feature && !checkEntitlement(context.org, capability.feature)) continue\n if (context.freeTaste && !capability.freeAllowed) continue\n if (capability.runnerKind && !hasRunner(capability.runnerKind)) continue\n ops.set(capability.op, capability)\n }\n return ops\n}\n\n/**\n * The lines the plan step's request lists the item operations in: each op\n * with what it makes, its arguments and their meaning. Per site, so they ride\n * the job's own turn and never a cached system block.\n */\nexport function aiBuildOpLines(ops: AiBuildOps, structural: readonly string[]): string[] {\n const items = [...ops.values()].filter((one) => !structural.includes(one.op))\n if (!items.length) return ['Operations for items: none on this site. Leave items empty.']\n const lines = ['Operations for items (anything else goes in create or screens):']\n for (const one of items) {\n const args = Object.entries(one.argsSchema.properties).map(([name, property]) => {\n const required = one.argsSchema.required?.includes(name) ? '' : ' (optional)'\n const choices = property.enum ? ` one of ${property.enum.join('|')}` : ''\n return `${name}: ${property.type}${choices}${required} — ${property.description}`\n })\n lines.push(\n `- ${one.op}: ${aiNounWithArticle(one.noun)}, at most ${one.maxPerPlan}; for ${one.intents.join('; ')}.${\n one.pageBlocks?.length ? ` A page section that uses it places the ${one.pageBlocks.join(' or ')} block: put new:<name> in that section's uses.` : ''\n } Args: ${args.length ? `{ ${args.join('; ')} }` : '{}'}.`,\n )\n }\n return lines\n}\n\nfunction aiNounWithArticle(noun: string): string {\n return `${/^[aeiou]/i.test(noun) ? 'an' : 'a'} ${noun}`\n}\n\n/** What a build can make here, in the owner's words, for the chat's instructions. */\nexport function aiBuildIntents(ops: AiBuildOps): string[] {\n return [...ops.values()].flatMap((one) => one.intents)\n}\n"],"names":["checkEntitlement","isHostPluginEnabled","pluginAiCapabilities","registerPluginAiCapability","filterEnabledPluginsByReleaseFlags","AI_TEMPLATE_SUBJECTS","AI_SITE_PASS_CREDITS","aiJobStepRunnerFor","AI_PLUGIN_ID","NO_ARGS","type","properties","additionalProperties","passes","count","AI_OWNED_CAPABILITIES","op","noun","where","intents","argsSchema","maxPerPlan","freeAllowed","runnerKind","estimateCredits","degrade","subject","description","enum","collectionId","maxLength","required","name","registerAiBuildCapabilities","capability","pluginId","aiBuildOps","context","deps","all","capabilities","hasRunner","kind","owners","Set","map","one","filter","id","released","length","releasedPlugins","ids","orgId","authorization","ops","Map","has","org","host","feature","freeTaste","set","aiBuildOpLines","structural","items","values","includes","lines","args","Object","entries","property","choices","join","push","aiNounWithArticle","pageBlocks","test","aiBuildIntents","flatMap"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-build-capabilities.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 type { AglynOrgBilling } from '@aglyn/aglyn/foundation/definitions/org-billing.types'\nimport { isHostPluginEnabled } from '@aglyn/aglyn/plugin-manager/enabled-plugins'\nimport {\n pluginAiCapabilities,\n registerPluginAiCapability,\n type PluginAiCapability,\n type ResolvedPluginAiCapability,\n} from '@aglyn/aglyn/plugin-manager/plugin-ai-capabilities'\nimport { filterEnabledPluginsByReleaseFlags } from '@aglyn/tenant-data-admin/server/release-flags'\nimport { AI_TEMPLATE_SUBJECTS } from '../model/ai-template-subjects'\nimport { AI_SITE_PASS_CREDITS } from '../model/ai-site-job'\nimport type { AiBuildOps } from '../model/ai-build-job'\nimport { AI_LOGIC_FUNCTION_RESOURCE } from '../model/ai-logic-job'\nimport { AI_AUTOMATION_RESOURCE } from '../model/ai-workflow-job'\nimport { AI_EDIT_TARGET_KINDS } from '../model/ai-edit-job'\nimport { AI_CAMPAIGN_RESOURCE } from './ai-job-campaign-step'\nimport { aiPluginDraftOwner, type AiPluginDraftOwnerLookup } from './ai-job-plugin-drafts'\nimport { aiJobStepRunnerFor } from './ai-jobs'\n\n/**\n * What THIS plugin lets a build make (AGL-3616), registered on the core's\n * capability contract exactly as any other plugin registers its own, so the\n * planner, the gates and the estimate read one list and name no plugin.\n *\n * Every one is built by a runner this plugin already has (`runnerKind`):\n * pages, layouts, forms, components and email designs are the plan's\n * creations and screens; templates, campaigns and automations are items with\n * arguments. A campaign and an automation are still WRITTEN by the marketing\n * and workflows plugins, through the writers their runners already call, and\n * a site function by the logic plugin's `function` writer, which the `logic`\n * runner calls when its job is a build's unit. A change to a page or layout\n * the site already has is the `edit` runner's.\n */\n\n/** This plugin's id, as its registrations name their owner. */\nconst AI_PLUGIN_ID = 'ai'\n\nconst NO_ARGS = { type: 'object', properties: {}, additionalProperties: false } as const\n\nconst passes = (count: number) => () => count * AI_SITE_PASS_CREDITS\n\n/** The operations this plugin owns, as it registers them. */\nexport const AI_OWNED_CAPABILITIES: readonly PluginAiCapability[] = [\n {\n op: 'page',\n noun: 'page',\n where: 'Pages',\n intents: ['new pages: home, about, services, contact, pricing, a landing page'],\n argsSchema: NO_ARGS,\n maxPerPlan: 8,\n freeAllowed: true,\n runnerKind: 'page',\n estimateCredits: passes(6),\n degrade: 'omit',\n },\n {\n op: 'layout',\n noun: 'layout',\n where: 'Layouts',\n intents: ['a header and footer shared by pages'],\n argsSchema: NO_ARGS,\n maxPerPlan: 1,\n freeAllowed: true,\n runnerKind: 'layout',\n estimateCredits: passes(1),\n degrade: 'fallback',\n },\n {\n op: 'form',\n noun: 'form',\n where: 'Forms',\n intents: ['a contact form, a quote request, a sign-up form'],\n argsSchema: NO_ARGS,\n maxPerPlan: 3,\n freeAllowed: true,\n runnerKind: 'form',\n estimateCredits: passes(1),\n degrade: 'omit',\n },\n {\n op: 'component',\n noun: 'component',\n where: 'Components',\n intents: ['a reusable card or block placed on several pages'],\n argsSchema: NO_ARGS,\n maxPerPlan: 4,\n freeAllowed: false,\n runnerKind: 'component',\n estimateCredits: passes(1),\n degrade: 'omit',\n },\n {\n op: 'email',\n noun: 'email design',\n where: 'Emails → Templates',\n intents: ['an email design: a welcome, a reply, an announcement'],\n argsSchema: NO_ARGS,\n maxPerPlan: 2,\n freeAllowed: false,\n runnerKind: 'email',\n estimateCredits: passes(1),\n degrade: 'omit',\n },\n {\n op: 'template',\n noun: 'page template',\n where: 'Templates',\n intents: ['a page template for blog posts, products or authors'],\n argsSchema: {\n type: 'object',\n properties: {\n subject: {\n type: 'string',\n description: 'What each page shows: entry (a collection entry), product or author.',\n enum: AI_TEMPLATE_SUBJECTS,\n },\n collectionId: {\n type: 'string',\n description: 'For entry: the collection id from the site inventory.',\n maxLength: 100,\n },\n },\n required: ['subject'],\n additionalProperties: false,\n },\n maxPerPlan: 2,\n freeAllowed: false,\n runnerKind: 'template',\n estimateCredits: passes(6),\n degrade: 'omit',\n },\n {\n op: 'campaign',\n noun: 'email campaign',\n where: 'Marketing → Campaigns',\n intents: ['an email campaign drafted and left unsent'],\n argsSchema: {\n type: 'object',\n properties: {\n name: { type: 'string', description: 'What the campaign is called.', maxLength: 120 },\n },\n additionalProperties: false,\n },\n maxPerPlan: 2,\n freeAllowed: false,\n runnerKind: 'campaign',\n estimateCredits: passes(2),\n degrade: 'omit',\n },\n {\n op: 'workflow',\n noun: 'automation',\n where: 'Automations',\n intents: ['an automation: when a form is sent, do something'],\n argsSchema: NO_ARGS,\n maxPerPlan: 2,\n freeAllowed: false,\n runnerKind: 'workflow',\n estimateCredits: passes(1),\n degrade: 'omit',\n },\n {\n // A function needs a model, so it is this plugin's operation; the logic\n // plugin owns the record and writes it (AGL-3616). New functions only: a\n // build never changes one the site already has.\n op: 'function',\n noun: 'site function',\n where: 'Logic → Functions',\n intents: ['a site function that works a value out from what it is given: a price, a total, a quote'],\n argsSchema: NO_ARGS,\n maxPerPlan: 2,\n // Free includes one function (`functionsPerHost: 1`), and Logic no feature.\n freeAllowed: true,\n quota: 'functionsPerHost',\n runnerKind: 'logic',\n estimateCredits: passes(1),\n degrade: 'omit',\n },\n {\n // A change to something the site already has (AGL-3616), made by the\n // `edit` runner: the Assist edit rung's protocol against the stored\n // document, saved as a version visitors do not see. Not on the Free\n // taste: without version history only an unpublished page can take a\n // change, which is rarely the page a request means, and its admission\n // would refuse the item after the plan was confirmed.\n op: 'edit',\n noun: 'page change',\n where: 'the page’s or layout’s versions',\n intents: [\n 'a change to a page or layout the site already has — shorter copy, a new section, different wording — saved as a version visitors do not see until it is published',\n ],\n argsSchema: {\n type: 'object',\n properties: {\n target: {\n type: 'string',\n description: 'The id of an existing page or layout from the site inventory.',\n maxLength: 64,\n },\n targetKind: {\n type: 'string',\n description: 'screen when target is a page, layout when it is a layout.',\n enum: AI_EDIT_TARGET_KINDS,\n },\n },\n required: ['target'],\n additionalProperties: false,\n },\n maxPerPlan: 3,\n freeAllowed: false,\n runnerKind: 'edit',\n estimateCredits: passes(1),\n degrade: 'omit',\n },\n]\n\n/**\n * The resource another plugin writes for each operation of this plugin's that\n * cannot be built without it. The operation runs where that writer's owner\n * runs — registered, switched on for the workspace and the site, and past its\n * release flag — exactly as an operation that owner registered would.\n */\nexport const AI_OWNED_OP_WRITERS: Readonly<Partial<Record<string, string>>> = {\n function: AI_LOGIC_FUNCTION_RESOURCE,\n // A campaign is written by the marketing plugin's campaign writer, an\n // automation by the workflows plugin's: neither is offered where its\n // writer's plugin is off, rather than planned and then skipped.\n campaign: AI_CAMPAIGN_RESOURCE,\n workflow: AI_AUTOMATION_RESOURCE,\n}\n\n/** Registers this plugin's build operations; the console surface calls it. */\nexport function registerAiBuildCapabilities(): void {\n for (const capability of AI_OWNED_CAPABILITIES) {\n registerPluginAiCapability(capability, { pluginId: AI_PLUGIN_ID })\n }\n}\n\n/** What decides which operations a build may use here. */\nexport interface AiBuildOpsContext {\n orgId: string\n hostId: string | null\n org: Partial<AglynOrgBilling> | null\n /** The site document, for the plugins switched on and off on it. */\n host: Readonly<Record<string, unknown>> | null\n freeTaste: boolean\n}\n\nexport interface AiBuildOpsDeps {\n /** The registered capabilities; the core registry's otherwise. */\n capabilities?: () => ResolvedPluginAiCapability[]\n /** The release-flag read; the platform's otherwise. */\n releasedPlugins?: (pluginIds: string[], orgId: string) => Promise<string[]>\n /** Whether a runner is registered for a kind; the machine's otherwise. */\n hasRunner?: (kind: string) => boolean\n /** Which plugin writes a resource; the core's registry otherwise. */\n writerOwner?: AiPluginDraftOwnerLookup\n}\n\n/**\n * The operations a build may plan on this site, by op (AGL-3616): every\n * registered capability whose owner runs here — switched on for the\n * workspace and the site, past its release flag; for one of this plugin's\n * operations another plugin writes (`AI_OWNED_OP_WRITERS`), that writer's\n * owner, and a writer registered at all — whose entitlement the plan\n * holds, which the Free taste may use where the workspace is on it, and,\n * for an AI-run operation, whose runner this process loaded. One release-flag\n * read for every owner at once. What a member may do and what an allowance\n * has left are the owner's to say when the item runs (`refusal`).\n */\nexport async function aiBuildOps(context: AiBuildOpsContext, deps: AiBuildOpsDeps = {}): Promise<AiBuildOps> {\n const all = (deps.capabilities ?? pluginAiCapabilities)()\n const hasRunner = deps.hasRunner ?? ((kind: string) => aiJobStepRunnerFor(kind as never) !== null)\n const writerOwner = deps.writerOwner ?? aiPluginDraftOwner\n // The plugin each of this plugin's operations depends on, by op; `null` where its writer is not registered.\n const writtenBy = new Map<string, string | null>()\n for (const { pluginId, capability } of all) {\n const resource = pluginId === AI_PLUGIN_ID ? AI_OWNED_OP_WRITERS[capability.op] : undefined\n if (resource) writtenBy.set(capability.op, writerOwner(resource))\n }\n const owners = [\n ...new Set(\n [...all.map((one) => one.pluginId), ...writtenBy.values()].filter(\n (id): id is string => !!id && id !== AI_PLUGIN_ID,\n ),\n ),\n ]\n const released = new Set(\n owners.length\n ? await (deps.releasedPlugins ??\n ((ids, orgId) => filterEnabledPluginsByReleaseFlags(ids, { orgId, authorization: null })))(owners, context.orgId)\n : [],\n )\n const ops = new Map<string, PluginAiCapability>()\n for (const { pluginId, capability } of all) {\n // The plugin that must run here: the owner, or for one of this plugin's\n // operations, the plugin that writes what it makes.\n const runsOn = pluginId === AI_PLUGIN_ID ? writtenBy.get(capability.op) : pluginId\n if (runsOn === null) continue\n if (runsOn !== undefined && runsOn !== AI_PLUGIN_ID) {\n if (!released.has(runsOn)) continue\n if (!isHostPluginEnabled(context.org as { enabledPlugins?: string[] } | null, context.host, runsOn)) continue\n }\n if (capability.feature && !checkEntitlement(context.org, capability.feature)) continue\n if (context.freeTaste && !capability.freeAllowed) continue\n if (capability.runnerKind && !hasRunner(capability.runnerKind)) continue\n ops.set(capability.op, capability)\n }\n return ops\n}\n\n/**\n * The lines the plan step's request lists the item operations in: each op\n * with what it makes, its arguments and their meaning. Per site, so they ride\n * the job's own turn and never a cached system block.\n */\nexport function aiBuildOpLines(ops: AiBuildOps, structural: readonly string[]): string[] {\n const items = [...ops.values()].filter((one) => !structural.includes(one.op))\n if (!items.length) return ['Operations for items: none on this site. Leave items empty.']\n const lines = ['Operations for items (anything else goes in create or screens):']\n for (const one of items) {\n const args = Object.entries(one.argsSchema.properties).map(([name, property]) => {\n const required = one.argsSchema.required?.includes(name) ? '' : ' (optional)'\n const choices = property.enum ? ` one of ${property.enum.join('|')}` : ''\n return `${name}: ${property.type}${choices}${required} — ${property.description}`\n })\n lines.push(\n `- ${one.op}: ${aiNounWithArticle(one.noun)}, at most ${one.maxPerPlan}; for ${one.intents.join('; ')}.${\n one.pageBlocks?.length ? ` A page section that uses it places the ${one.pageBlocks.join(' or ')} block: put new:<name> in that section's uses.` : ''\n } Args: ${args.length ? `{ ${args.join('; ')} }` : '{}'}.`,\n )\n }\n return lines\n}\n\nfunction aiNounWithArticle(noun: string): string {\n return `${/^[aeiou]/i.test(noun) ? 'an' : 'a'} ${noun}`\n}\n\n/** What a build can make here, in the owner's words, for the chat's instructions. */\nexport function aiBuildIntents(ops: AiBuildOps): string[] {\n return [...ops.values()].flatMap((one) => one.intents)\n}\n"],"names":["checkEntitlement","isHostPluginEnabled","pluginAiCapabilities","registerPluginAiCapability","filterEnabledPluginsByReleaseFlags","AI_TEMPLATE_SUBJECTS","AI_SITE_PASS_CREDITS","AI_LOGIC_FUNCTION_RESOURCE","AI_AUTOMATION_RESOURCE","AI_EDIT_TARGET_KINDS","AI_CAMPAIGN_RESOURCE","aiPluginDraftOwner","aiJobStepRunnerFor","AI_PLUGIN_ID","NO_ARGS","type","properties","additionalProperties","passes","count","AI_OWNED_CAPABILITIES","op","noun","where","intents","argsSchema","maxPerPlan","freeAllowed","runnerKind","estimateCredits","degrade","subject","description","enum","collectionId","maxLength","required","name","quota","target","targetKind","AI_OWNED_OP_WRITERS","function","campaign","workflow","registerAiBuildCapabilities","capability","pluginId","aiBuildOps","context","deps","all","capabilities","hasRunner","kind","writerOwner","writtenBy","Map","resource","undefined","set","owners","Set","map","one","values","filter","id","released","length","releasedPlugins","ids","orgId","authorization","ops","runsOn","get","has","org","host","feature","freeTaste","aiBuildOpLines","structural","items","includes","lines","args","Object","entries","property","choices","join","push","aiNounWithArticle","pageBlocks","test","aiBuildIntents","flatMap"],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import type { BusinessProfileValues } from '@aglyn/aglyn/app-utils/business-profile';
|
|
18
|
+
import type { AiJob } from '../model/ai-jobs.types';
|
|
19
|
+
import type { AiJobTransitionListener } from './ai-jobs';
|
|
20
|
+
/** The guided start's answers, as profile values; `null` when it gave none. */
|
|
21
|
+
export declare function aiBusinessProfileStartValues(job: Pick<AiJob, 'kind' | 'inputs'>): BusinessProfileValues | null;
|
|
22
|
+
/** The plan's home page description, as a line about the business; `null` when it has none. */
|
|
23
|
+
export declare function aiBusinessProfilePlanValues(job: Pick<AiJob, 'kind' | 'plan'>): BusinessProfileValues | null;
|
|
24
|
+
/**
|
|
25
|
+
* The transition listener's half that prefills (AGL-3661): on a site job's
|
|
26
|
+
* plan and on its finish, the start's answers and then the plan's guess, each
|
|
27
|
+
* a no-op once written. A failure is logged and never fails the job.
|
|
28
|
+
*/
|
|
29
|
+
export declare function aiBusinessProfilePrefiller(firestoreOf: () => FirebaseFirestore.Firestore): AiJobTransitionListener;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ import { prefillAiBusinessProfile } from "../runtime/site-context.js";
|
|
17
|
+
/**
|
|
18
|
+
* A site job fills in the site's business profile (AGL-3661), so the next job
|
|
19
|
+
* — and the owner, on Setup → Business profile — starts from what the guided
|
|
20
|
+
* start was told rather than from nothing.
|
|
21
|
+
*
|
|
22
|
+
* Two sources, each recorded as itself:
|
|
23
|
+
* - `start`: the answers the owner gave the guided start — what the business
|
|
24
|
+
* is, who it is for, its city. Their words, given in another place.
|
|
25
|
+
* - `ai`: what the plan wrote for the home page's search description, used
|
|
26
|
+
* only where the start said nothing about what the business does.
|
|
27
|
+
*
|
|
28
|
+
* Neither ever replaces what the owner typed into the profile; the merge in
|
|
29
|
+
* `@aglyn/aglyn/app-utils/business-profile` decides that, not this file.
|
|
30
|
+
*/ const text = (value)=>typeof value === 'string' ? value.trim() : '';
|
|
31
|
+
/** "a local dog groomer" reads as a line once its first letter is a capital. */ const sentence = (value)=>value ? value[0].toUpperCase() + value.slice(1) : value;
|
|
32
|
+
/** The guided start's answers, as profile values; `null` when it gave none. */ export function aiBusinessProfileStartValues(job) {
|
|
33
|
+
var _job_inputs;
|
|
34
|
+
if (job.kind !== 'site') return null;
|
|
35
|
+
const inputs = (_job_inputs = job.inputs) != null ? _job_inputs : {};
|
|
36
|
+
const values = {};
|
|
37
|
+
const businessType = text(inputs['businessType']);
|
|
38
|
+
const audience = text(inputs['audience']);
|
|
39
|
+
const city = text(inputs['city']);
|
|
40
|
+
if (businessType) values.whatYouDo = sentence(businessType);
|
|
41
|
+
if (audience) values.audience = audience;
|
|
42
|
+
if (city) values.serviceArea = city;
|
|
43
|
+
return Object.keys(values).length ? values : null;
|
|
44
|
+
}
|
|
45
|
+
/** The plan's home page description, as a line about the business; `null` when it has none. */ export function aiBusinessProfilePlanValues(job) {
|
|
46
|
+
var _ref;
|
|
47
|
+
var _job_plan;
|
|
48
|
+
if (job.kind !== 'site') return null;
|
|
49
|
+
const screens = (_ref = (_job_plan = job.plan) == null ? void 0 : _job_plan.screens) != null ? _ref : [];
|
|
50
|
+
const home = screens.find((screen)=>[
|
|
51
|
+
'',
|
|
52
|
+
'/',
|
|
53
|
+
'home',
|
|
54
|
+
'index'
|
|
55
|
+
].includes(text(screen.slug).replace(/^\/+|\/+$/g, '')));
|
|
56
|
+
const description = text(home == null ? void 0 : home.seoDescription);
|
|
57
|
+
return description ? {
|
|
58
|
+
whatYouDo: description
|
|
59
|
+
} : null;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The transition listener's half that prefills (AGL-3661): on a site job's
|
|
63
|
+
* plan and on its finish, the start's answers and then the plan's guess, each
|
|
64
|
+
* a no-op once written. A failure is logged and never fails the job.
|
|
65
|
+
*/ export function aiBusinessProfilePrefiller(firestoreOf) {
|
|
66
|
+
return async ({ job, to })=>{
|
|
67
|
+
if (job.kind !== 'site' || !job.hostId || to === 'failed') return;
|
|
68
|
+
const start = aiBusinessProfileStartValues(job);
|
|
69
|
+
const plan = aiBusinessProfilePlanValues(job);
|
|
70
|
+
if (!start && !plan) return;
|
|
71
|
+
try {
|
|
72
|
+
const firestore = firestoreOf();
|
|
73
|
+
if (start) await prefillAiBusinessProfile(firestore, job.hostId, start, 'start');
|
|
74
|
+
if (plan) await prefillAiBusinessProfile(firestore, job.hostId, plan, 'ai');
|
|
75
|
+
} catch (error) {
|
|
76
|
+
console.warn('ai business profile prefill failed', {
|
|
77
|
+
orgId: job.orgId,
|
|
78
|
+
jobId: job.$id,
|
|
79
|
+
error
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
//# sourceMappingURL=ai-business-profile-prefill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-business-profile-prefill.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { BusinessProfileValues } from '@aglyn/aglyn/app-utils/business-profile'\nimport type { AiJob } from '../model/ai-jobs.types'\nimport { prefillAiBusinessProfile } from '../runtime/site-context'\nimport type { AiJobTransitionListener } from './ai-jobs'\n\n/**\n * A site job fills in the site's business profile (AGL-3661), so the next job\n * — and the owner, on Setup → Business profile — starts from what the guided\n * start was told rather than from nothing.\n *\n * Two sources, each recorded as itself:\n * - `start`: the answers the owner gave the guided start — what the business\n * is, who it is for, its city. Their words, given in another place.\n * - `ai`: what the plan wrote for the home page's search description, used\n * only where the start said nothing about what the business does.\n *\n * Neither ever replaces what the owner typed into the profile; the merge in\n * `@aglyn/aglyn/app-utils/business-profile` decides that, not this file.\n */\n\nconst text = (value: unknown): string => (typeof value === 'string' ? value.trim() : '')\n\n/** \"a local dog groomer\" reads as a line once its first letter is a capital. */\nconst sentence = (value: string): string => (value ? value[0].toUpperCase() + value.slice(1) : value)\n\n/** The guided start's answers, as profile values; `null` when it gave none. */\nexport function aiBusinessProfileStartValues(job: Pick<AiJob, 'kind' | 'inputs'>): BusinessProfileValues | null {\n if (job.kind !== 'site') return null\n const inputs = job.inputs ?? {}\n const values: BusinessProfileValues = {}\n const businessType = text(inputs['businessType'])\n const audience = text(inputs['audience'])\n const city = text(inputs['city'])\n if (businessType) values.whatYouDo = sentence(businessType)\n if (audience) values.audience = audience\n if (city) values.serviceArea = city\n return Object.keys(values).length ? values : null\n}\n\n/** The plan's home page description, as a line about the business; `null` when it has none. */\nexport function aiBusinessProfilePlanValues(job: Pick<AiJob, 'kind' | 'plan'>): BusinessProfileValues | null {\n if (job.kind !== 'site') return null\n const screens = job.plan?.screens ?? []\n const home = screens.find((screen) => ['', '/', 'home', 'index'].includes(text(screen.slug).replace(/^\\/+|\\/+$/g, '')))\n const description = text(home?.seoDescription)\n return description ? { whatYouDo: description } : null\n}\n\n/**\n * The transition listener's half that prefills (AGL-3661): on a site job's\n * plan and on its finish, the start's answers and then the plan's guess, each\n * a no-op once written. A failure is logged and never fails the job.\n */\nexport function aiBusinessProfilePrefiller(\n firestoreOf: () => FirebaseFirestore.Firestore,\n): AiJobTransitionListener {\n return async ({ job, to }) => {\n if (job.kind !== 'site' || !job.hostId || to === 'failed') return\n const start = aiBusinessProfileStartValues(job)\n const plan = aiBusinessProfilePlanValues(job)\n if (!start && !plan) return\n try {\n const firestore = firestoreOf()\n if (start) await prefillAiBusinessProfile(firestore, job.hostId, start, 'start')\n if (plan) await prefillAiBusinessProfile(firestore, job.hostId, plan, 'ai')\n } catch (error) {\n console.warn('ai business profile prefill failed', { orgId: job.orgId, jobId: job.$id, error })\n }\n }\n}\n"],"names":["prefillAiBusinessProfile","text","value","trim","sentence","toUpperCase","slice","aiBusinessProfileStartValues","job","kind","inputs","values","businessType","audience","city","whatYouDo","serviceArea","Object","keys","length","aiBusinessProfilePlanValues","screens","plan","home","find","screen","includes","slug","replace","description","seoDescription","aiBusinessProfilePrefiller","firestoreOf","to","hostId","start","firestore","error","console","warn","orgId","jobId","$id"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAID,SAASA,wBAAwB,QAAQ,6BAAyB;AAGlE;;;;;;;;;;;;;CAaC,GAED,MAAMC,OAAO,CAACC,QAA4B,OAAOA,UAAU,WAAWA,MAAMC,IAAI,KAAK;AAErF,8EAA8E,GAC9E,MAAMC,WAAW,CAACF,QAA2BA,QAAQA,KAAK,CAAC,EAAE,CAACG,WAAW,KAAKH,MAAMI,KAAK,CAAC,KAAKJ;AAE/F,6EAA6E,GAC7E,OAAO,SAASK,6BAA6BC,GAAmC;QAE/DA;IADf,IAAIA,IAAIC,IAAI,KAAK,QAAQ,OAAO;IAChC,MAAMC,UAASF,cAAAA,IAAIE,MAAM,YAAVF,cAAc,CAAC;IAC9B,MAAMG,SAAgC,CAAC;IACvC,MAAMC,eAAeX,KAAKS,MAAM,CAAC,eAAe;IAChD,MAAMG,WAAWZ,KAAKS,MAAM,CAAC,WAAW;IACxC,MAAMI,OAAOb,KAAKS,MAAM,CAAC,OAAO;IAChC,IAAIE,cAAcD,OAAOI,SAAS,GAAGX,SAASQ;IAC9C,IAAIC,UAAUF,OAAOE,QAAQ,GAAGA;IAChC,IAAIC,MAAMH,OAAOK,WAAW,GAAGF;IAC/B,OAAOG,OAAOC,IAAI,CAACP,QAAQQ,MAAM,GAAGR,SAAS;AAC/C;AAEA,6FAA6F,GAC7F,OAAO,SAASS,4BAA4BZ,GAAiC;;QAE3DA;IADhB,IAAIA,IAAIC,IAAI,KAAK,QAAQ,OAAO;IAChC,MAAMY,mBAAUb,YAAAA,IAAIc,IAAI,qBAARd,UAAUa,OAAO,mBAAI,EAAE;IACvC,MAAME,OAAOF,QAAQG,IAAI,CAAC,CAACC,SAAW;YAAC;YAAI;YAAK;YAAQ;SAAQ,CAACC,QAAQ,CAACzB,KAAKwB,OAAOE,IAAI,EAAEC,OAAO,CAAC,cAAc;IAClH,MAAMC,cAAc5B,KAAKsB,wBAAAA,KAAMO,cAAc;IAC7C,OAAOD,cAAc;QAAEd,WAAWc;IAAY,IAAI;AACpD;AAEA;;;;CAIC,GACD,OAAO,SAASE,2BACdC,WAA8C;IAE9C,OAAO,OAAO,EAAExB,GAAG,EAAEyB,EAAE,EAAE;QACvB,IAAIzB,IAAIC,IAAI,KAAK,UAAU,CAACD,IAAI0B,MAAM,IAAID,OAAO,UAAU;QAC3D,MAAME,QAAQ5B,6BAA6BC;QAC3C,MAAMc,OAAOF,4BAA4BZ;QACzC,IAAI,CAAC2B,SAAS,CAACb,MAAM;QACrB,IAAI;YACF,MAAMc,YAAYJ;YAClB,IAAIG,OAAO,MAAMnC,yBAAyBoC,WAAW5B,IAAI0B,MAAM,EAAEC,OAAO;YACxE,IAAIb,MAAM,MAAMtB,yBAAyBoC,WAAW5B,IAAI0B,MAAM,EAAEZ,MAAM;QACxE,EAAE,OAAOe,OAAO;YACdC,QAAQC,IAAI,CAAC,sCAAsC;gBAAEC,OAAOhC,IAAIgC,KAAK;gBAAEC,OAAOjC,IAAIkC,GAAG;gBAAEL;YAAM;QAC/F;IACF;AACF"}
|
|
@@ -567,7 +567,9 @@ export const runAiJobBuildStep = createAiJobBuildStep();
|
|
|
567
567
|
/** The runner kinds this plugin's own item operations use, for the time a pass needs without the registry. */ const AI_BUILD_ITEM_RUNNER_KINDS = {
|
|
568
568
|
template: 'template',
|
|
569
569
|
campaign: 'campaign',
|
|
570
|
-
workflow: 'workflow'
|
|
570
|
+
workflow: 'workflow',
|
|
571
|
+
function: 'logic',
|
|
572
|
+
edit: 'edit'
|
|
571
573
|
};
|
|
572
574
|
/**
|
|
573
575
|
* Why a Free build cannot be confirmed: its estimate is more than the owner's
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-job-build-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 type { AglynOrgBilling } from '@aglyn/aglyn/foundation/definitions/org-billing.types'\nimport { resolveEffectivePlan } from '@aglyn/aglyn/app-utils/plan-entitlements'\nimport { resolveOrgIdForHost } from '@aglyn/tenant-data-admin/server/organizations'\nimport {\n AI_BUILD_LIMITS,\n AI_BUILD_PUBLISH_INPUT,\n aiArticle,\n aiBuildCreditEstimate,\n aiBuildDegradation,\n aiBuildInitialLedger,\n aiBuildItemDelivered,\n aiBuildItemOpen,\n aiBuildNextUnit,\n aiBuildOrder,\n aiBuildPlacedItemLines,\n aiBuildPlanShapeRefusal,\n aiBuildUnits,\n type AiBuildOps,\n type AiBuildUnit,\n} from '../model/ai-build-job'\nimport { isAiPlanNewRef, type AiBuildPlanCreateKind } from '../model/ai-build-plan'\nimport type {\n AiJob,\n AiJobItemFailure,\n AiJobItemLedger,\n AiJobKind,\n AiJobOutput,\n AiJobPlan,\n} from '../model/ai-jobs.types'\nimport { AI_SITE_MAX_SECTIONS } from '../model/ai-site-job'\nimport { FREE_AI_TASTE_CREDITS_PER_MONTH } from '../plan-entitlements'\nimport { aiModelForStep } from '../providers/routing'\nimport {\n AI_BUILD_UNIT_EMPTY_COPY,\n aiBuildBuiltRefs,\n aiUnitErrorRetryable,\n aiUnitFailure,\n aiUnitSpend,\n} from './ai-build-unit-outcome'\nimport { assistCreditsFromUsd } from '../usage/assist-credits'\nimport { ASSIST_RETURNED_USD_FIELD, assistSpendAfterReturnsUsd } from '../usage/assist-credit-returns'\nimport { freeAccountUsageRef, freeAssistAccount, type AssistMeteredOrg } from '../usage/assist-free-taste'\nimport { aiBuildOps, type AiBuildOpsContext } from './ai-build-capabilities'\nimport {\n aiJobAdmissionRefusal,\n registerAiJobAdmission,\n type AiJobAdmission,\n type AiJobAdmissionContext,\n} from './ai-job-admission'\nimport { aiOriginJobId } from './ai-job-draft-ids'\nimport { readAiDraftNodes } from './ai-job-drafts'\nimport { aiConfirmedPlan, aiUnspentOutcome } from './ai-job-generation'\nimport { AI_JOB_PAGE_STEP_MINIMUM_MS } from './ai-job-page-budget'\nimport {\n aiPluginDraftAdmissionRefusal,\n aiPluginDraftWriter,\n type AiPluginDraftWriterLookup,\n} from './ai-job-plugin-drafts'\nimport { aiSitePageWritten, aiSiteResolvedRef } from './ai-job-site-step'\nimport { AI_LAYOUT_SITE_PAGES_INPUT, aiLayoutSitePagesOfPlan } from './ai-job-layout-site-pages'\nimport { AI_LAYOUT_FORM_PAGE_INPUT, AI_LAYOUT_LANGUAGE_INPUT, aiLayoutFormPageOfPlan } from './ai-job-page-language'\nimport {\n AI_JOB_BRIEF_MAX_CHARS,\n type AiJobItemOutcome,\n type AiJobStepOutcome,\n type AiJobStepRunner,\n} from './ai-job-text-step'\nimport { aiJobPublishesBuild, aiPublishGuidedSite } from './ai-site-publish'\nimport {\n AI_PLANNED_JOB_KINDS,\n aiJobStepRunMinimumMs,\n aiJobStepRunnerFor,\n registerAiJobStep,\n registerAiJobStepPasses,\n} from './ai-jobs'\n\n/**\n * The build step (AGL-3616): the generation step of a `build` job, run once\n * the member confirmed the plan their request produced.\n *\n * Like the site scaffold it generalizes, it builds nothing itself and asks no\n * model of its own. Each pass takes the next unit in dependency order and\n * hands it to what builds that kind of thing — a page, layout, form,\n * component, email design or template to this plugin's own step, under a job\n * derived for the unit; another plugin's resource to that plugin's writer on\n * the resource-draft seam, with the content the owner's capability derives\n * from the item's arguments. One unit, one pass, one recorded spend.\n *\n * ── Settled item by item ────────────────────────────────────────────────\n *\n * Where a unit stands is read from the job's ITEM LEDGER, never from counting\n * outputs: the machine writes each pass's row in the transaction that\n * records its spend (`recordStep`). A unit that fails is a FAILED ROW, not a\n * failed job: the pass reports it, the machine gives back that item's spend\n * where the failure was ours, and the next pass builds the next unit. What\n * depended on it is built without it, or skipped where it cannot stand\n * without it (`aiBuildDegradation`). The machine ends the job when nothing is\n * left: `done` when anything was delivered, `failed` — its planning given\n * back too — when nothing was.\n *\n * ── Drafts, unless asked and confirmed ───────────────────────────────────\n *\n * Every unit writes the draft its own kind writes, which nothing publishes.\n * Only a build whose request asked to publish AND whose member ticked the\n * plan card's box puts its built pages live, once, on its last pass, through\n * the guided start's publish.\n */\n\n/** What a build answers with no confirmed plan to build. */\nexport const AI_BUILD_NO_PLAN_COPY = 'This build has no confirmed plan to build.'\n\n/** What a unit says when nothing on this site builds its operation any more. */\nexport const aiBuildUnavailableCopy = (noun: string): string =>\n `Not built: ${aiArticle(noun)} cannot be made on this site right now.`\n\n\n/** What a page that was reported built but holds none of its plan says. */\nexport const AI_BUILD_PAGE_NOT_WRITTEN_COPY = 'The page was not written from its plan.'\n\n\n/**\n * The most passes a build's step may take: every unit at a page's worst — its\n * sections and its listing — so a runner that never finishes is still\n * bounded while the largest plan is not. Try again starts the count over.\n */\nexport const AI_BUILD_MAX_PASSES = AI_BUILD_LIMITS.units * (AI_SITE_MAX_SECTIONS + 1)\n\n/** The job kind a creation of the build is built by. */\nconst CREATION_JOB_KINDS: Partial<Record<AiBuildPlanCreateKind, AiJobKind>> = {\n layout: 'layout',\n form: 'form',\n component: 'component',\n email: 'email',\n}\n\n/** The job kind a unit is built by, where an AI runner builds it. */\nexport function aiBuildUnitJobKind(unit: AiBuildUnit, ops: AiBuildOps): AiJobKind | null {\n if (unit.screen) return 'page'\n if (unit.creation) return CREATION_JOB_KINDS[unit.creation.kind] ?? null\n const runnerKind = ops.get(unit.op)?.runnerKind\n return runnerKind ? (runnerKind as AiJobKind) : null\n}\n\n/** The id a unit's job, and so its draft, is named by. */\nexport function aiBuildUnitJobId(job: Pick<AiJob, '$id'>, unit: AiBuildUnit): string {\n return unit.creation?.id ?? unit.screen?.id ?? unit.item?.id ?? `${job.$id}-${unit.slot}`\n}\n\n/**\n * The job a unit is built under (generalizing `aiSiteUnitJob`): this job's\n * org, site, creator and model; the kind that builds the unit; a plan\n * narrowed to the unit, its `new:` references resolved to what was built and\n * the failed ones left out; and a brief that says what the unit is, what it\n * is built without, and which blocks its sections place.\n */\nexport function aiBuildUnitJob(\n job: AiJob,\n unit: AiBuildUnit,\n context: {\n kind: AiJobKind\n units: readonly AiBuildUnit[]\n ledger: readonly AiJobItemLedger[]\n ops: AiBuildOps\n briefLines?: readonly string[]\n },\n): AiJob {\n const plan = job.plan as AiJobPlan\n const built = aiBuildBuiltRefs(context.units, context.ledger, job.outputs ?? [])\n const labels = { ...(plan.labels ?? {}) }\n for (const entry of built.values()) labels[entry.id] = entry.label\n const brief = [job.brief.trim()]\n const unitPlan: AiJobPlan = { ...plan, labels, reuse: [...plan.reuse], create: [], screens: [] }\n delete unitPlan.items\n const placedByScreens = new Set(plan.screens.flatMap((screen) => screen.sections.flatMap((section) => section.uses)))\n if (unit.creation) {\n unitPlan.reuse = plan.reuse.filter((entry) => !placedByScreens.has(entry.id))\n unitPlan.create = [{ ...unit.creation, duplicateOf: aiSiteResolvedRef(unit.creation.duplicateOf, built) }]\n brief.push(`Build the ${unit.creation.kind} “${unit.creation.name}”: ${unit.creation.why}`)\n }\n if (unit.screen) {\n const screen = unit.screen\n for (const entry of built.values()) {\n unitPlan.reuse.push({ kind: entry.kind, id: entry.id, purpose: `the ${entry.kind} this request built` })\n }\n let builtLayout: string | null = null\n for (const entry of built.values()) if (entry.kind === 'layout') builtLayout = builtLayout ?? entry.id\n unitPlan.screens = [\n {\n ...screen,\n // A page whose layout failed renders inside the site's own: the page\n // step falls back to it when the plan names none.\n layout: aiSiteResolvedRef(screen.layout, built) ?? (isAiPlanNewRef(screen.layout) ? builtLayout : null),\n template: aiSiteResolvedRef(screen.template, built),\n duplicateOf: aiSiteResolvedRef(screen.duplicateOf, built),\n record: screen.record\n ? { ...screen.record, dataset: aiSiteResolvedRef(screen.record.dataset, built) ?? screen.record.dataset }\n : null,\n sections: screen.sections.map((section) => ({\n ...section,\n uses: section.uses\n .map((ref) => aiSiteResolvedRef(ref, built))\n .filter((ref): ref is string => !!ref),\n })),\n },\n ]\n brief.push(`Build the page “${screen.title}”, at ${screen.slug}.`)\n brief.push(...aiBuildPlacedItemLines(unit, { units: context.units, ledger: context.ledger, ops: context.ops }))\n }\n const item = unit.item\n if (item) {\n const noun = context.ops.get(item.op)?.noun ?? item.op\n brief.push(`Build the ${noun} “${item.name}”${item.why ? `: ${item.why}` : '.'}`)\n // A planned kind's step builds the plan's first creation of its kind.\n unitPlan.create = AI_PLANNED_JOB_KINDS.includes(context.kind)\n ? [{ kind: context.kind as AiBuildPlanCreateKind, name: item.name, why: item.why, duplicateOf: null, fields: [], ...(item.id ? { id: item.id } : {}) }]\n : []\n }\n brief.push(...(context.briefLines ?? []))\n const inputs: Record<string, unknown> = {\n ...job.inputs,\n ...(item?.args ?? {}),\n originJobId: aiOriginJobId(job),\n }\n delete inputs[AI_BUILD_PUBLISH_INPUT]\n // A build's pages and layouts are designed in the layout language and\n // compiled (AGL-3660), told the pages the build plans and where its form is.\n if (context.kind === 'page' || context.kind === 'layout') {\n inputs[AI_LAYOUT_LANGUAGE_INPUT] = true\n const pages = aiLayoutSitePagesOfPlan(plan.screens)\n if (pages.length) inputs[AI_LAYOUT_SITE_PAGES_INPUT] = pages\n const formPage = aiLayoutFormPageOfPlan(plan)\n if (formPage) inputs[AI_LAYOUT_FORM_PAGE_INPUT] = formPage\n }\n return {\n ...job,\n $id: aiBuildUnitJobId(job, unit),\n kind: context.kind,\n steps: [],\n outputs: [],\n items: null,\n plan: item && !AI_PLANNED_JOB_KINDS.includes(context.kind) ? null : unitPlan,\n inputs,\n brief: brief.join('\\n').slice(0, AI_JOB_BRIEF_MAX_CHARS),\n }\n}\n\n/** The unit's failure, for its row: ours or not, why, in customer-safe words. */\nfunction failed(\n slot: string,\n failure: AiJobItemFailure,\n extra: Partial<AiJobItemOutcome> = {},\n): AiJobItemOutcome {\n return { slot, status: 'failed', failure, ...extra }\n}\n\nexport interface AiJobBuildStepDeps {\n /** The runner registry; specs hand in fakes. */\n runnerFor?: typeof aiJobStepRunnerFor\n /** The draft writer registry; specs hand in fakes. */\n writerFor?: AiPluginDraftWriterLookup\n /** The operations this site may use; the registry and its gates otherwise. */\n opsFor?: (context: AiBuildOpsContext) => Promise<AiBuildOps>\n /** A runner kind's own admission, asked before its item runs; the registry's otherwise. */\n admissionFor?: typeof aiJobAdmissionRefusal\n /** Another plugin's admission for its writer; the seam's otherwise. */\n pluginAdmission?: typeof aiPluginDraftAdmissionRefusal\n /** The draft reader a built page is checked through. */\n readNodes?: typeof readAiDraftNodes\n /** The publish a build asked for and confirmed. */\n publish?: typeof aiPublishGuidedSite\n}\n\n/** Whether a build's workspace spends the Free taste. */\nexport function aiBuildFreeTaste(org: object | null | undefined): boolean {\n return Boolean(org) && resolveEffectivePlan(org as never) === 'free'\n}\n\n/** The site document a gate reads, or `null`. */\nasync function readHost(firestore: FirebaseFirestore.Firestore, hostId: string | null) {\n if (!hostId) return null\n return ((await firestore.collection('hosts').doc(hostId).get()).data() ?? null) as Record<string, unknown> | null\n}\n\nexport function createAiJobBuildStep(deps: AiJobBuildStepDeps = {}): AiJobStepRunner {\n const runnerFor = deps.runnerFor ?? aiJobStepRunnerFor\n const writerFor = deps.writerFor ?? aiPluginDraftWriter\n const opsFor = deps.opsFor ?? ((context) => aiBuildOps(context))\n const admissionFor = deps.admissionFor ?? aiJobAdmissionRefusal\n const pluginAdmission = deps.pluginAdmission ?? aiPluginDraftAdmissionRefusal\n const readNodes = deps.readNodes ?? readAiDraftNodes\n const publish = deps.publish ?? aiPublishGuidedSite\n\n return async (context): Promise<AiJobStepOutcome> => {\n const { job, firestore } = context\n const model = context.modelFor?.('job.plan') ?? aiModelForStep('job.plan')\n const plan = aiConfirmedPlan(job)\n if (!plan) return { ...aiUnspentOutcome(model), failure: AI_BUILD_NO_PLAN_COPY }\n const org = (context.org ?? null) as Partial<AglynOrgBilling> | null\n const units = aiBuildUnits(plan)\n const ordered = aiBuildOrder(units) ?? units\n const starting = !job.items?.length\n const ledger = starting ? aiBuildInitialLedger(units) : (job.items as AiJobItemLedger[])\n const init = starting ? { items: ledger } : {}\n const unit = aiBuildNextUnit(ordered, ledger)\n const rows = new Map(ledger.map((row) => [row.slot, row]))\n const host = await readHost(firestore, job.hostId ?? null)\n const ops = await opsFor({\n orgId: job.orgId,\n hostId: job.hostId ?? null,\n org,\n host,\n freeTaste: aiBuildFreeTaste(org),\n })\n\n /** Whether units other than this one are still to build. */\n const othersOpen = (slot: string) =>\n ordered.some((one) => one.slot !== slot && aiBuildItemOpen(rows.get(one.slot) ?? { status: 'pending' }))\n\n /** The build's last pass puts its pages live, where it was asked and confirmed. */\n const finish = async (outcome: AiJobStepOutcome, extraPages: readonly AiJobOutput[] = []): Promise<AiJobStepOutcome> => {\n if (!aiJobPublishesBuild(job) || job.sitePublish || !job.hostId) return outcome\n const pageIds = new Set(\n units\n .filter((one) => one.screen && aiBuildItemDelivered(rows.get(one.slot) ?? { status: 'pending' }))\n .flatMap((one) => rows.get(one.slot)?.outputs ?? []),\n )\n const pages = [\n ...(job.outputs ?? []).filter((output) => output.resource === 'screen' && pageIds.has(output.id)),\n ...extraPages,\n ]\n if (!pages.length) return outcome\n const sitePublish = await publish(firestore, { job, outputs: pages, now: context.now }).catch((error: unknown) => {\n console.error('ai build publish threw', { orgId: job.orgId, jobId: job.$id, error })\n return null\n })\n return sitePublish ? { ...outcome, sitePublish } : outcome\n }\n\n if (!unit) return finish({ ...aiUnspentOutcome(model), ...init })\n\n const settle = (item: AiJobItemOutcome, spent: AiJobStepOutcome = aiUnspentOutcome(model)): AiJobStepOutcome => ({\n ...spent,\n ...init,\n item,\n ...(item.status === 'running' || othersOpen(unit.slot) ? { continue: true } : {}),\n })\n\n // What its dependencies came to.\n const degradation = aiBuildDegradation(unit, { units, ledger, ops })\n if (degradation.skip) {\n return settle({ slot: unit.slot, status: 'skipped', note: degradation.skip, degradedBy: degradation.degradedBy })\n }\n const capability = ops.get(unit.op)\n const noun = capability?.noun ?? unit.op\n if (!capability) return settle({ slot: unit.slot, status: 'skipped', note: aiBuildUnavailableCopy(noun) })\n const degraded = degradation.degradedBy.length > 0\n const note = degradation.notes.length ? degradation.notes.join(' ') : null\n\n // Another plugin's resource: its writer, with the content its capability derives.\n if (capability.draftResource) {\n const item = unit.item\n const writer = writerFor(capability.draftResource)\n if (!item || !writer || !job.hostId) {\n return settle({ slot: unit.slot, status: 'skipped', note: aiBuildUnavailableCopy(noun) })\n }\n const admission: AiJobAdmissionContext = {\n firestore,\n orgId: job.orgId,\n hostId: job.hostId,\n inputs: {},\n org,\n uid: job.createdBy,\n }\n const refusal = await pluginAdmission(admission, {\n kind: 'build',\n drafts: [{ resource: capability.draftResource, label: capability.noun }],\n writerFor,\n })\n if (refusal) return settle({ slot: unit.slot, status: 'skipped', note: `Not built: ${refusal.error}` })\n const dependencies: Record<string, { op: string; id: string }> = {}\n for (const slot of unit.deps) {\n const dep = units.find((one) => one.slot === slot)\n const row = rows.get(slot)\n if (!dep || !row || !aiBuildItemDelivered(row) || !row.outputs.length) continue\n dependencies[`new:${dep.label}`] = { op: dep.op, id: row.outputs[0] }\n }\n const content = capability.draftContent?.({ name: item.name, args: item.args }, { hostId: job.hostId, dependencies }) ?? item.args\n const checked = writer.check(content, { hostId: job.hostId })\n if (checked.ok === false) {\n return settle(\n failed(unit.slot, { ours: true, reason: 'step-failure', message: checked.problems[0] ?? AI_BUILD_UNIT_EMPTY_COPY }),\n )\n }\n const id = aiBuildUnitJobId(job, unit)\n const written = await writer.write({\n orgId: job.orgId,\n hostId: job.hostId,\n uid: job.createdBy,\n org,\n now: context.now,\n id,\n name: item.name,\n content,\n })\n if (written.ok === false) {\n return settle(failed(unit.slot, { ours: false, reason: 'review', message: written.error }))\n }\n const output: AiJobOutput = {\n resource: 'draft',\n id: written.id,\n versionId: written.versionId,\n hostId: job.hostId,\n label: written.name,\n draftResource: capability.draftResource,\n note: `A draft, in ${capability.where}.`,\n }\n return settle(\n {\n slot: unit.slot,\n status: degraded ? 'degraded' : 'succeeded',\n outputs: [written.id],\n note,\n ...(degraded ? { degradedBy: degradation.degradedBy } : {}),\n },\n { ...aiUnspentOutcome(model), outputs: [output] },\n )\n }\n\n // This plugin's own runner, under a job derived for the unit.\n const kind = aiBuildUnitJobKind(unit, ops)\n const runner = kind ? runnerFor(kind) : null\n if (!kind || !runner) return settle({ slot: unit.slot, status: 'skipped', note: aiBuildUnavailableCopy(noun) })\n const derived = aiBuildUnitJob(job, unit, { kind, units, ledger, ops, briefLines: degradation.briefLines })\n // An item's kind is asked its own admission first (a campaign's plan,\n // a template's subject), once, before its first pass.\n if (unit.item && rows.get(unit.slot)?.status !== 'running') {\n const refusal = await admissionFor(kind, {\n firestore,\n orgId: job.orgId,\n hostId: job.hostId ?? null,\n inputs: derived.inputs,\n org,\n uid: job.createdBy,\n }).catch((error: unknown) => {\n console.error('ai build item admission failed', { orgId: job.orgId, jobId: job.$id, slot: unit.slot, error })\n return { status: 403 as const, error: AI_BUILD_UNIT_EMPTY_COPY }\n })\n if (refusal) return settle({ slot: unit.slot, status: 'skipped', note: `Not built: ${refusal.error}` })\n }\n\n let outcome: AiJobStepOutcome\n try {\n outcome = await runner({ ...context, job: derived })\n } catch (error) {\n // A provider that will answer later is the machine's to retry; anything\n // else is this item's failure, and the build goes on.\n if (aiUnitErrorRetryable(error)) throw error\n console.error('ai build unit threw', { orgId: job.orgId, jobId: job.$id, slot: unit.slot, error })\n return settle(failed(unit.slot, { ours: true, reason: 'provider', message: AI_BUILD_UNIT_EMPTY_COPY }))\n }\n const spent = aiUnitSpend(outcome)\n const ids = outcome.outputs.map((output) => output.id)\n const stopped = aiUnitFailure(unit.slot, outcome)\n if (stopped) return settle(stopped, spent)\n // A page counts as built only when its plan's sections are in it (AGL-3596).\n if (unit.screen && job.hostId) {\n const page = outcome.outputs.find((output) => output.resource === 'screen')\n const written =\n page !== undefined &&\n (await aiSitePageWritten(\n firestore,\n { hostId: job.hostId, unitJobId: derived.$id, screen: unit.screen, draftId: page.id },\n readNodes,\n ))\n if (!written) {\n return settle(\n failed(unit.slot, { ours: true, reason: 'step-failure', message: AI_BUILD_PAGE_NOT_WRITTEN_COPY }),\n { ...spent, outputs: outcome.outputs.filter((output) => output.resource !== 'screen') },\n )\n }\n }\n const done = settle(\n {\n slot: unit.slot,\n status: degraded ? 'degraded' : 'succeeded',\n outputs: ids,\n note,\n ...(degraded ? { degradedBy: degradation.degradedBy } : {}),\n },\n spent,\n )\n if (done.continue) return done\n // The last unit: what was built goes live where it was asked and confirmed.\n rows.set(unit.slot, { ...(rows.get(unit.slot) as AiJobItemLedger), status: degraded ? 'degraded' : 'succeeded', outputs: ids })\n return finish(done, unit.screen ? outcome.outputs.filter((output) => output.resource === 'screen') : [])\n }\n}\n\nexport const runAiJobBuildStep = createAiJobBuildStep()\n\n/**\n * The least time a build's next pass needs: what the step that builds its\n * next unit registers for the job derived for it; a page pass's when the\n * next unit is another plugin's draft, which asks no model.\n */\nexport function aiBuildJobRunMinimumMs(job: AiJob): number {\n const plan = aiConfirmedPlan(job)\n if (!plan) return AI_JOB_PAGE_STEP_MINIMUM_MS\n const units = aiBuildUnits(plan)\n const ordered = aiBuildOrder(units) ?? units\n const ledger = job.items?.length ? job.items : aiBuildInitialLedger(units)\n const unit = aiBuildNextUnit(ordered, ledger)\n if (!unit) return AI_JOB_PAGE_STEP_MINIMUM_MS\n const kind: AiJobKind | null = unit.screen\n ? 'page'\n : unit.creation\n ? (CREATION_JOB_KINDS[unit.creation.kind] ?? null)\n : (AI_BUILD_ITEM_RUNNER_KINDS[unit.op] ?? null)\n if (!kind) return AI_JOB_PAGE_STEP_MINIMUM_MS\n return aiJobStepRunMinimumMs(aiBuildUnitJob(job, unit, { kind, units, ledger, ops: new Map() }))\n}\n\n/** The runner kinds this plugin's own item operations use, for the time a pass needs without the registry. */\nconst AI_BUILD_ITEM_RUNNER_KINDS: Readonly<Record<string, AiJobKind>> = {\n template: 'template',\n campaign: 'campaign',\n workflow: 'workflow',\n}\n\n/**\n * Why a Free build cannot be confirmed: its estimate is more than the owner's\n * Free allowance has left this month. Read off the account month the meter\n * writes, net of give-backs; a read that fails admits, since the reservation\n * still refuses at the wall.\n */\nexport async function aiBuildFreeBalanceRefusal(input: {\n firestore: FirebaseFirestore.Firestore\n org: object | null\n estimate: number\n now: Date\n}): Promise<string | null> {\n const account = freeAssistAccount(input.org as AssistMeteredOrg | null)\n if (!account?.accountUid) return null\n try {\n const month = input.now.toISOString().slice(0, 7)\n const snapshot = await freeAccountUsageRef(input.firestore, account.accountUid, month).get()\n const spent = assistCreditsFromUsd(\n assistSpendAfterReturnsUsd(snapshot.get('estCostUsd'), snapshot.get(ASSIST_RETURNED_USD_FIELD)),\n )\n const left = Math.max(0, FREE_AI_TASTE_CREDITS_PER_MONTH - spent)\n return input.estimate > left\n ? `This plan is estimated at ${input.estimate} credits, and your Free AI credits have ${left} left this month. Ask for less, or upgrade for more.`\n : null\n } catch (error) {\n console.error('ai build free balance read failed', { error })\n return null\n }\n}\n\nexport interface AiBuildAdmissionDeps {\n opsFor?: (context: AiBuildOpsContext) => Promise<AiBuildOps>\n freeBalanceRefusal?: typeof aiBuildFreeBalanceRefusal\n ownerOf?: typeof resolveOrgIdForHost\n now?: () => Date\n}\n\n/**\n * A build is admitted for a site of the job's own org where a page can be\n * built; and confirmed only for a plan it can build here — its shape, its\n * operations as this site has them, and on the Free taste an estimate the\n * month's Free credits still cover.\n */\nexport function createAiBuildJobAdmission(deps: AiBuildAdmissionDeps = {}): AiJobAdmission {\n const opsFor = deps.opsFor ?? ((context) => aiBuildOps(context))\n const freeBalanceRefusal = deps.freeBalanceRefusal ?? aiBuildFreeBalanceRefusal\n const ownerOf = deps.ownerOf ?? resolveOrgIdForHost\n return async (context) => {\n if (!context.hostId) return { status: 400, error: 'Open the site to build on before asking Assist to build' }\n const owner = await ownerOf(context.hostId)\n if (!owner || owner !== context.orgId) return { status: 404, error: 'Unknown site' }\n if (!aiJobStepRunnerFor('page')) return { status: 400, error: 'Building from a request is not available yet.' }\n const plan = context.plan\n if (!plan) return null\n const org = context.org as Partial<AglynOrgBilling> | null\n const freeTaste = aiBuildFreeTaste(org)\n const host = await readHost(context.firestore, context.hostId)\n const ops = await opsFor({ orgId: context.orgId, hostId: context.hostId, org, host, freeTaste })\n const shape = aiBuildPlanShapeRefusal(plan, { freeTaste, ops })\n if (shape) return { status: 400, error: shape }\n if (freeTaste) {\n const refusal = await freeBalanceRefusal({\n firestore: context.firestore,\n org,\n estimate: aiBuildCreditEstimate(plan, { ops }),\n now: deps.now?.() ?? new Date(),\n })\n if (refusal) return { status: 403, error: refusal }\n }\n return null\n }\n}\n\nexport const aiBuildJobAdmission = createAiBuildJobAdmission()\n\n/**\n * Registers the build with the least time a pass needs, the time its next\n * pass needs, the passes its largest plan may take, and its admission.\n */\nexport function registerAiBuildJob(): void {\n registerAiJobStep('build', runAiJobBuildStep, {\n minimumMs: AI_JOB_PAGE_STEP_MINIMUM_MS,\n minimumMsFor: aiBuildJobRunMinimumMs,\n })\n registerAiJobStepPasses('build', AI_BUILD_MAX_PASSES)\n registerAiJobAdmission('build', aiBuildJobAdmission)\n}\n"],"names":["resolveEffectivePlan","resolveOrgIdForHost","AI_BUILD_LIMITS","AI_BUILD_PUBLISH_INPUT","aiArticle","aiBuildCreditEstimate","aiBuildDegradation","aiBuildInitialLedger","aiBuildItemDelivered","aiBuildItemOpen","aiBuildNextUnit","aiBuildOrder","aiBuildPlacedItemLines","aiBuildPlanShapeRefusal","aiBuildUnits","isAiPlanNewRef","AI_SITE_MAX_SECTIONS","FREE_AI_TASTE_CREDITS_PER_MONTH","aiModelForStep","AI_BUILD_UNIT_EMPTY_COPY","aiBuildBuiltRefs","aiUnitErrorRetryable","aiUnitFailure","aiUnitSpend","assistCreditsFromUsd","ASSIST_RETURNED_USD_FIELD","assistSpendAfterReturnsUsd","freeAccountUsageRef","freeAssistAccount","aiBuildOps","aiJobAdmissionRefusal","registerAiJobAdmission","aiOriginJobId","readAiDraftNodes","aiConfirmedPlan","aiUnspentOutcome","AI_JOB_PAGE_STEP_MINIMUM_MS","aiPluginDraftAdmissionRefusal","aiPluginDraftWriter","aiSitePageWritten","aiSiteResolvedRef","AI_LAYOUT_SITE_PAGES_INPUT","aiLayoutSitePagesOfPlan","AI_LAYOUT_FORM_PAGE_INPUT","AI_LAYOUT_LANGUAGE_INPUT","aiLayoutFormPageOfPlan","AI_JOB_BRIEF_MAX_CHARS","aiJobPublishesBuild","aiPublishGuidedSite","AI_PLANNED_JOB_KINDS","aiJobStepRunMinimumMs","aiJobStepRunnerFor","registerAiJobStep","registerAiJobStepPasses","AI_BUILD_NO_PLAN_COPY","aiBuildUnavailableCopy","noun","AI_BUILD_PAGE_NOT_WRITTEN_COPY","AI_BUILD_MAX_PASSES","units","CREATION_JOB_KINDS","layout","form","component","email","aiBuildUnitJobKind","unit","ops","screen","creation","kind","runnerKind","get","op","aiBuildUnitJobId","job","id","item","$id","slot","aiBuildUnitJob","context","plan","built","ledger","outputs","labels","entry","values","label","brief","trim","unitPlan","reuse","create","screens","items","placedByScreens","Set","flatMap","sections","section","uses","filter","has","duplicateOf","push","name","why","purpose","builtLayout","template","record","dataset","map","ref","title","slug","includes","fields","briefLines","inputs","args","originJobId","pages","length","formPage","steps","join","slice","failed","failure","extra","status","aiBuildFreeTaste","org","Boolean","readHost","firestore","hostId","collection","doc","data","createAiJobBuildStep","deps","runnerFor","writerFor","opsFor","admissionFor","pluginAdmission","readNodes","publish","rows","model","modelFor","ordered","starting","init","Map","row","host","orgId","freeTaste","othersOpen","some","one","finish","outcome","extraPages","sitePublish","pageIds","output","resource","now","catch","error","console","jobId","settle","spent","continue","degradation","skip","note","degradedBy","capability","degraded","notes","draftResource","writer","admission","uid","createdBy","refusal","drafts","dependencies","dep","find","content","draftContent","checked","check","ok","ours","reason","message","problems","written","write","versionId","where","runner","derived","ids","stopped","page","undefined","unitJobId","draftId","done","set","runAiJobBuildStep","aiBuildJobRunMinimumMs","AI_BUILD_ITEM_RUNNER_KINDS","campaign","workflow","aiBuildFreeBalanceRefusal","input","account","accountUid","month","toISOString","snapshot","left","Math","max","estimate","createAiBuildJobAdmission","freeBalanceRefusal","ownerOf","owner","shape","Date","aiBuildJobAdmission","registerAiBuildJob","minimumMs","minimumMsFor"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC;AAGD,SAASA,oBAAoB,QAAQ,2CAA0C;AAC/E,SAASC,mBAAmB,QAAQ,gDAA+C;AACnF,SACEC,eAAe,EACfC,sBAAsB,EACtBC,SAAS,EACTC,qBAAqB,EACrBC,kBAAkB,EAClBC,oBAAoB,EACpBC,oBAAoB,EACpBC,eAAe,EACfC,eAAe,EACfC,YAAY,EACZC,sBAAsB,EACtBC,uBAAuB,EACvBC,YAAY,QAGP,2BAAuB;AAC9B,SAASC,cAAc,QAAoC,4BAAwB;AASnF,SAASC,oBAAoB,QAAQ,0BAAsB;AAC3D,SAASC,+BAA+B,QAAQ,0BAAsB;AACtE,SAASC,cAAc,QAAQ,0BAAsB;AACrD,SACEC,wBAAwB,EACxBC,gBAAgB,EAChBC,oBAAoB,EACpBC,aAAa,EACbC,WAAW,QACN,6BAAyB;AAChC,SAASC,oBAAoB,QAAQ,6BAAyB;AAC9D,SAASC,yBAAyB,EAAEC,0BAA0B,QAAQ,oCAAgC;AACtG,SAASC,mBAAmB,EAAEC,iBAAiB,QAA+B,gCAA4B;AAC1G,SAASC,UAAU,QAAgC,6BAAyB;AAC5E,SACEC,qBAAqB,EACrBC,sBAAsB,QAGjB,wBAAoB;AAC3B,SAASC,aAAa,QAAQ,wBAAoB;AAClD,SAASC,gBAAgB,QAAQ,qBAAiB;AAClD,SAASC,eAAe,EAAEC,gBAAgB,QAAQ,yBAAqB;AACvE,SAASC,2BAA2B,QAAQ,0BAAsB;AAClE,SACEC,6BAA6B,EAC7BC,mBAAmB,QAEd,4BAAwB;AAC/B,SAASC,iBAAiB,EAAEC,iBAAiB,QAAQ,wBAAoB;AACzE,SAASC,0BAA0B,EAAEC,uBAAuB,QAAQ,gCAA4B;AAChG,SAASC,yBAAyB,EAAEC,wBAAwB,EAAEC,sBAAsB,QAAQ,4BAAwB;AACpH,SACEC,sBAAsB,QAIjB,wBAAoB;AAC3B,SAASC,mBAAmB,EAAEC,mBAAmB,QAAQ,uBAAmB;AAC5E,SACEC,oBAAoB,EACpBC,qBAAqB,EACrBC,kBAAkB,EAClBC,iBAAiB,EACjBC,uBAAuB,QAClB,eAAW;AAElB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BC,GAED,0DAA0D,GAC1D,OAAO,MAAMC,wBAAwB,6CAA4C;AAEjF,8EAA8E,GAC9E,OAAO,MAAMC,yBAAyB,CAACC,OACrC,CAAC,WAAW,EAAEpD,UAAUoD,MAAM,uCAAuC,CAAC,CAAA;AAGxE,yEAAyE,GACzE,OAAO,MAAMC,iCAAiC,0CAAyC;AAGvF;;;;CAIC,GACD,OAAO,MAAMC,sBAAsBxD,gBAAgByD,KAAK,GAAI3C,CAAAA,uBAAuB,CAAA,EAAE;AAErF,sDAAsD,GACtD,MAAM4C,qBAAwE;IAC5EC,QAAQ;IACRC,MAAM;IACNC,WAAW;IACXC,OAAO;AACT;AAEA,mEAAmE,GACnE,OAAO,SAASC,mBAAmBC,IAAiB,EAAEC,GAAe;QAEzCP;QACPO;IAFnB,IAAID,KAAKE,MAAM,EAAE,OAAO;IACxB,IAAIF,KAAKG,QAAQ,EAAE,QAAOT,yCAAAA,kBAAkB,CAACM,KAAKG,QAAQ,CAACC,IAAI,CAAC,YAAtCV,yCAA0C;IACpE,MAAMW,cAAaJ,WAAAA,IAAIK,GAAG,CAACN,KAAKO,EAAE,sBAAfN,SAAkBI,UAAU;IAC/C,OAAOA,aAAcA,aAA2B;AAClD;AAEA,wDAAwD,GACxD,OAAO,SAASG,iBAAiBC,GAAuB,EAAET,IAAiB;QAClEA,MAAAA;QAAAA,gBAAqBA,cAAmBA;IAA/C,QAAOA,QAAAA,kBAAAA,iBAAAA,KAAKG,QAAQ,qBAAbH,eAAeU,EAAE,qBAAIV,eAAAA,KAAKE,MAAM,qBAAXF,aAAaU,EAAE,YAApCV,SAAwCA,aAAAA,KAAKW,IAAI,qBAATX,WAAWU,EAAE,YAArDV,OAAyD,GAAGS,IAAIG,GAAG,CAAC,CAAC,EAAEZ,KAAKa,IAAI,EAAE;AAC3F;AAEA;;;;;;CAMC,GACD,OAAO,SAASC,eACdL,GAAU,EACVT,IAAiB,EACjBe,OAMC;QAG6DN,cACzCO,cAiDND;IAnDf,MAAMC,OAAOP,IAAIO,IAAI;IACrB,MAAMC,QAAQ/D,iBAAiB6D,QAAQtB,KAAK,EAAEsB,QAAQG,MAAM,GAAET,eAAAA,IAAIU,OAAO,YAAXV,eAAe,EAAE;IAC/E,MAAMW,SAAS,cAAMJ,eAAAA,KAAKI,MAAM,YAAXJ,eAAe,CAAC;IACrC,KAAK,MAAMK,SAASJ,MAAMK,MAAM,GAAIF,MAAM,CAACC,MAAMX,EAAE,CAAC,GAAGW,MAAME,KAAK;IAClE,MAAMC,QAAQ;QAACf,IAAIe,KAAK,CAACC,IAAI;KAAG;IAChC,MAAMC,WAAsB,aAAKV;QAAMI;QAAQO,OAAO;eAAIX,KAAKW,KAAK;SAAC;QAAEC,QAAQ,EAAE;QAAEC,SAAS,EAAE;;IAC9F,OAAOH,SAASI,KAAK;IACrB,MAAMC,kBAAkB,IAAIC,IAAIhB,KAAKa,OAAO,CAACI,OAAO,CAAC,CAAC/B,SAAWA,OAAOgC,QAAQ,CAACD,OAAO,CAAC,CAACE,UAAYA,QAAQC,IAAI;IAClH,IAAIpC,KAAKG,QAAQ,EAAE;QACjBuB,SAASC,KAAK,GAAGX,KAAKW,KAAK,CAACU,MAAM,CAAC,CAAChB,QAAU,CAACU,gBAAgBO,GAAG,CAACjB,MAAMX,EAAE;QAC3EgB,SAASE,MAAM,GAAG;YAAC,aAAK5B,KAAKG,QAAQ;gBAAEoC,aAAajE,kBAAkB0B,KAAKG,QAAQ,CAACoC,WAAW,EAAEtB;;SAAS;QAC1GO,MAAMgB,IAAI,CAAC,CAAC,UAAU,EAAExC,KAAKG,QAAQ,CAACC,IAAI,CAAC,EAAE,EAAEJ,KAAKG,QAAQ,CAACsC,IAAI,CAAC,GAAG,EAAEzC,KAAKG,QAAQ,CAACuC,GAAG,EAAE;IAC5F;IACA,IAAI1C,KAAKE,MAAM,EAAE;YAYH5B,oBAIyBA;QAfrC,MAAM4B,SAASF,KAAKE,MAAM;QAC1B,KAAK,MAAMmB,SAASJ,MAAMK,MAAM,GAAI;YAClCI,SAASC,KAAK,CAACa,IAAI,CAAC;gBAAEpC,MAAMiB,MAAMjB,IAAI;gBAAEM,IAAIW,MAAMX,EAAE;gBAAEiC,SAAS,CAAC,IAAI,EAAEtB,MAAMjB,IAAI,CAAC,mBAAmB,CAAC;YAAC;QACxG;QACA,IAAIwC,cAA6B;QACjC,KAAK,MAAMvB,SAASJ,MAAMK,MAAM,GAAI,IAAID,MAAMjB,IAAI,KAAK,UAAUwC,cAAcA,sBAAAA,cAAevB,MAAMX,EAAE;QACtGgB,SAASG,OAAO,GAAG;YACjB,aACK3B;gBACH,qEAAqE;gBACrE,kDAAkD;gBAClDP,MAAM,GAAErB,qBAAAA,kBAAkB4B,OAAOP,MAAM,EAAEsB,kBAAjC3C,qBAA4CzB,eAAeqD,OAAOP,MAAM,IAAIiD,cAAc;gBAClGC,UAAUvE,kBAAkB4B,OAAO2C,QAAQ,EAAE5B;gBAC7CsB,aAAajE,kBAAkB4B,OAAOqC,WAAW,EAAEtB;gBACnD6B,QAAQ5C,OAAO4C,MAAM,GACjB,aAAK5C,OAAO4C,MAAM;oBAAEC,OAAO,GAAEzE,sBAAAA,kBAAkB4B,OAAO4C,MAAM,CAACC,OAAO,EAAE9B,kBAAzC3C,sBAAmD4B,OAAO4C,MAAM,CAACC,OAAO;qBACrG;gBACJb,UAAUhC,OAAOgC,QAAQ,CAACc,GAAG,CAAC,CAACb,UAAa,aACvCA;wBACHC,MAAMD,QAAQC,IAAI,CACfY,GAAG,CAAC,CAACC,MAAQ3E,kBAAkB2E,KAAKhC,QACpCoB,MAAM,CAAC,CAACY,MAAuB,CAAC,CAACA;;;SAGzC;QACDzB,MAAMgB,IAAI,CAAC,CAAC,gBAAgB,EAAEtC,OAAOgD,KAAK,CAAC,MAAM,EAAEhD,OAAOiD,IAAI,CAAC,CAAC,CAAC;QACjE3B,MAAMgB,IAAI,IAAI9F,uBAAuBsD,MAAM;YAAEP,OAAOsB,QAAQtB,KAAK;YAAEyB,QAAQH,QAAQG,MAAM;YAAEjB,KAAKc,QAAQd,GAAG;QAAC;IAC9G;IACA,MAAMU,OAAOX,KAAKW,IAAI;IACtB,IAAIA,MAAM;;YACKI;QAAb,MAAMzB,iBAAOyB,mBAAAA,QAAQd,GAAG,CAACK,GAAG,CAACK,KAAKJ,EAAE,sBAAvBQ,iBAA0BzB,IAAI,oBAAIqB,KAAKJ,EAAE;QACtDiB,MAAMgB,IAAI,CAAC,CAAC,UAAU,EAAElD,KAAK,EAAE,EAAEqB,KAAK8B,IAAI,CAAC,CAAC,EAAE9B,KAAK+B,GAAG,GAAG,CAAC,EAAE,EAAE/B,KAAK+B,GAAG,EAAE,GAAG,KAAK;QAChF,sEAAsE;QACtEhB,SAASE,MAAM,GAAG7C,qBAAqBqE,QAAQ,CAACrC,QAAQX,IAAI,IACxD;YAAC;gBAAEA,MAAMW,QAAQX,IAAI;gBAA2BqC,MAAM9B,KAAK8B,IAAI;gBAAEC,KAAK/B,KAAK+B,GAAG;gBAAEH,aAAa;gBAAMc,QAAQ,EAAE;eAAM1C,KAAKD,EAAE,GAAG;gBAAEA,IAAIC,KAAKD,EAAE;YAAC,IAAI,CAAC;SAAK,GACrJ,EAAE;IACR;IACAc,MAAMgB,IAAI,KAAKzB,sBAAAA,QAAQuC,UAAU,YAAlBvC,sBAAsB,EAAE;IACvC,MAAMwC,SAAkC,aACnC9C,IAAI8C,MAAM,UACT5C,wBAAAA,KAAM6C,IAAI,mBAAI,CAAC;QACnBC,aAAa3F,cAAc2C;;IAE7B,OAAO8C,MAAM,CAACtH,uBAAuB;IACrC,sEAAsE;IACtE,6EAA6E;IAC7E,IAAI8E,QAAQX,IAAI,KAAK,UAAUW,QAAQX,IAAI,KAAK,UAAU;QACxDmD,MAAM,CAAC7E,yBAAyB,GAAG;QACnC,MAAMgF,QAAQlF,wBAAwBwC,KAAKa,OAAO;QAClD,IAAI6B,MAAMC,MAAM,EAAEJ,MAAM,CAAChF,2BAA2B,GAAGmF;QACvD,MAAME,WAAWjF,uBAAuBqC;QACxC,IAAI4C,UAAUL,MAAM,CAAC9E,0BAA0B,GAAGmF;IACpD;IACA,OAAO,aACFnD;QACHG,KAAKJ,iBAAiBC,KAAKT;QAC3BI,MAAMW,QAAQX,IAAI;QAClByD,OAAO,EAAE;QACT1C,SAAS,EAAE;QACXW,OAAO;QACPd,MAAML,QAAQ,CAAC5B,qBAAqBqE,QAAQ,CAACrC,QAAQX,IAAI,IAAI,OAAOsB;QACpE6B;QACA/B,OAAOA,MAAMsC,IAAI,CAAC,MAAMC,KAAK,CAAC,GAAGnF;;AAErC;AAEA,+EAA+E,GAC/E,SAASoF,OACPnD,IAAY,EACZoD,OAAyB,EACzBC,QAAmC,CAAC,CAAC;IAErC,OAAO;QAAErD;QAAMsD,QAAQ;QAAUF;OAAYC;AAC/C;AAmBA,uDAAuD,GACvD,OAAO,SAASE,iBAAiBC,GAA8B;IAC7D,OAAOC,QAAQD,QAAQvI,qBAAqBuI,SAAkB;AAChE;AAEA,+CAA+C,GAC/C,eAAeE,SAASC,SAAsC,EAAEC,MAAqB;QAE3E;IADR,IAAI,CAACA,QAAQ,OAAO;IACpB,QAAQ,QAAA,AAAC,CAAA,MAAMD,UAAUE,UAAU,CAAC,SAASC,GAAG,CAACF,QAAQnE,GAAG,EAAC,EAAGsE,IAAI,cAA5D,QAAkE;AAC5E;AAEA,OAAO,SAASC,qBAAqBC,OAA2B,CAAC,CAAC;QAC9CA,iBACAA,iBACHA,cACMA,oBACGA,uBACNA,iBACFA;IANhB,MAAMC,aAAYD,kBAAAA,KAAKC,SAAS,YAAdD,kBAAkB7F;IACpC,MAAM+F,aAAYF,kBAAAA,KAAKE,SAAS,YAAdF,kBAAkB1G;IACpC,MAAM6G,UAASH,eAAAA,KAAKG,MAAM,YAAXH,eAAgB,CAAC/D,UAAYpD,WAAWoD;IACvD,MAAMmE,gBAAeJ,qBAAAA,KAAKI,YAAY,YAAjBJ,qBAAqBlH;IAC1C,MAAMuH,mBAAkBL,wBAAAA,KAAKK,eAAe,YAApBL,wBAAwB3G;IAChD,MAAMiH,aAAYN,kBAAAA,KAAKM,SAAS,YAAdN,kBAAkB/G;IACpC,MAAMsH,WAAUP,gBAAAA,KAAKO,OAAO,YAAZP,gBAAgBhG;IAEhC,OAAO,OAAOiC;kBAKCA,cAEGtE,eAMuBgE,aAG7BA;YARQA,YAuID6E;QA9IjB,MAAM,EAAE7E,GAAG,EAAE+D,SAAS,EAAE,GAAGzD;QAC3B,MAAMwE,gBAAQxE,QAAQyE,QAAQ,oBAAhBzE,QAAQyE,QAAQ,MAAhBzE,SAAmB,8BAAe/D,eAAe;QAC/D,MAAMgE,OAAOhD,gBAAgByC;QAC7B,IAAI,CAACO,MAAM,OAAO,aAAK/C,iBAAiBsH;YAAQtB,SAAS7E;;QACzD,MAAMiF,OAAOtD,eAAAA,QAAQsD,GAAG,YAAXtD,eAAe;QAC5B,MAAMtB,QAAQ7C,aAAaoE;QAC3B,MAAMyE,WAAUhJ,gBAAAA,aAAagD,kBAAbhD,gBAAuBgD;QACvC,MAAMiG,WAAW,GAACjF,aAAAA,IAAIqB,KAAK,qBAATrB,WAAWkD,MAAM;QACnC,MAAMzC,SAASwE,WAAWrJ,qBAAqBoD,SAAUgB,IAAIqB,KAAK;QAClE,MAAM6D,OAAOD,WAAW;YAAE5D,OAAOZ;QAAO,IAAI,CAAC;QAC7C,MAAMlB,OAAOxD,gBAAgBiJ,SAASvE;QACtC,MAAMoE,OAAO,IAAIM,IAAI1E,OAAO8B,GAAG,CAAC,CAAC6C,MAAQ;gBAACA,IAAIhF,IAAI;gBAAEgF;aAAI;QACxD,MAAMC,OAAO,MAAMvB,SAASC,YAAW/D,cAAAA,IAAIgE,MAAM,YAAVhE,cAAc;QACrD,MAAMR,MAAM,MAAMgF,OAAO;YACvBc,OAAOtF,IAAIsF,KAAK;YAChBtB,MAAM,GAAEhE,eAAAA,IAAIgE,MAAM,YAAVhE,eAAc;YACtB4D;YACAyB;YACAE,WAAW5B,iBAAiBC;QAC9B;QAEA,0DAA0D,GAC1D,MAAM4B,aAAa,CAACpF,OAClB4E,QAAQS,IAAI,CAAC,CAACC;oBAA6Cb;uBAArCa,IAAItF,IAAI,KAAKA,QAAQtE,iBAAgB+I,YAAAA,KAAKhF,GAAG,CAAC6F,IAAItF,IAAI,aAAjByE,YAAsB;oBAAEnB,QAAQ;gBAAU;;QAEvG,iFAAiF,GACjF,MAAMiC,SAAS,OAAOC,SAA2BC,aAAqC,EAAE;gBAQhF7F;YAPN,IAAI,CAAC5B,oBAAoB4B,QAAQA,IAAI8F,WAAW,IAAI,CAAC9F,IAAIgE,MAAM,EAAE,OAAO4B;YACxE,MAAMG,UAAU,IAAIxE,IAClBvC,MACG4C,MAAM,CAAC,CAAC8D;oBAA2Cb;uBAAnCa,IAAIjG,MAAM,IAAI5D,sBAAqBgJ,YAAAA,KAAKhF,GAAG,CAAC6F,IAAItF,IAAI,aAAjByE,YAAsB;oBAAEnB,QAAQ;gBAAU;eAC7FlC,OAAO,CAAC,CAACkE;;oBAAQb;gCAAAA,YAAAA,KAAKhF,GAAG,CAAC6F,IAAItF,IAAI,sBAAjByE,UAAoBnE,OAAO,mBAAI,EAAE;;YAEvD,MAAMuC,QAAQ;mBACT,EAACjD,eAAAA,IAAIU,OAAO,YAAXV,eAAe,EAAE,EAAE4B,MAAM,CAAC,CAACoE,SAAWA,OAAOC,QAAQ,KAAK,YAAYF,QAAQlE,GAAG,CAACmE,OAAO/F,EAAE;mBAC5F4F;aACJ;YACD,IAAI,CAAC5C,MAAMC,MAAM,EAAE,OAAO0C;YAC1B,MAAME,cAAc,MAAMlB,QAAQb,WAAW;gBAAE/D;gBAAKU,SAASuC;gBAAOiD,KAAK5F,QAAQ4F,GAAG;YAAC,GAAGC,KAAK,CAAC,CAACC;gBAC7FC,QAAQD,KAAK,CAAC,0BAA0B;oBAAEd,OAAOtF,IAAIsF,KAAK;oBAAEgB,OAAOtG,IAAIG,GAAG;oBAAEiG;gBAAM;gBAClF,OAAO;YACT;YACA,OAAON,cAAc,aAAKF;gBAASE;iBAAgBF;QACrD;QAEA,IAAI,CAACrG,MAAM,OAAOoG,OAAO,aAAKnI,iBAAiBsH,QAAWI;QAE1D,MAAMqB,SAAS,CAACrG,MAAwBsG,QAA0BhJ,iBAAiBsH,MAAM,GAAwB,aAC5G0B,OACAtB;gBACHhF;eACIA,KAAKwD,MAAM,KAAK,aAAa8B,WAAWjG,KAAKa,IAAI,IAAI;gBAAEqG,UAAU;YAAK,IAAI,CAAC;QAGjF,iCAAiC;QACjC,MAAMC,cAAc/K,mBAAmB4D,MAAM;YAAEP;YAAOyB;YAAQjB;QAAI;QAClE,IAAIkH,YAAYC,IAAI,EAAE;YACpB,OAAOJ,OAAO;gBAAEnG,MAAMb,KAAKa,IAAI;gBAAEsD,QAAQ;gBAAWkD,MAAMF,YAAYC,IAAI;gBAAEE,YAAYH,YAAYG,UAAU;YAAC;QACjH;QACA,MAAMC,aAAatH,IAAIK,GAAG,CAACN,KAAKO,EAAE;QAClC,MAAMjB,gBAAOiI,8BAAAA,WAAYjI,IAAI,oBAAIU,KAAKO,EAAE;QACxC,IAAI,CAACgH,YAAY,OAAOP,OAAO;YAAEnG,MAAMb,KAAKa,IAAI;YAAEsD,QAAQ;YAAWkD,MAAMhI,uBAAuBC;QAAM;QACxG,MAAMkI,WAAWL,YAAYG,UAAU,CAAC3D,MAAM,GAAG;QACjD,MAAM0D,OAAOF,YAAYM,KAAK,CAAC9D,MAAM,GAAGwD,YAAYM,KAAK,CAAC3D,IAAI,CAAC,OAAO;QAEtE,kFAAkF;QAClF,IAAIyD,WAAWG,aAAa,EAAE;;YAC5B,MAAM/G,OAAOX,KAAKW,IAAI;YACtB,MAAMgH,SAAS3C,UAAUuC,WAAWG,aAAa;YACjD,IAAI,CAAC/G,QAAQ,CAACgH,UAAU,CAAClH,IAAIgE,MAAM,EAAE;gBACnC,OAAOuC,OAAO;oBAAEnG,MAAMb,KAAKa,IAAI;oBAAEsD,QAAQ;oBAAWkD,MAAMhI,uBAAuBC;gBAAM;YACzF;YACA,MAAMsI,YAAmC;gBACvCpD;gBACAuB,OAAOtF,IAAIsF,KAAK;gBAChBtB,QAAQhE,IAAIgE,MAAM;gBAClBlB,QAAQ,CAAC;gBACTc;gBACAwD,KAAKpH,IAAIqH,SAAS;YACpB;YACA,MAAMC,UAAU,MAAM5C,gBAAgByC,WAAW;gBAC/CxH,MAAM;gBACN4H,QAAQ;oBAAC;wBAAEtB,UAAUa,WAAWG,aAAa;wBAAEnG,OAAOgG,WAAWjI,IAAI;oBAAC;iBAAE;gBACxE0F;YACF;YACA,IAAI+C,SAAS,OAAOf,OAAO;gBAAEnG,MAAMb,KAAKa,IAAI;gBAAEsD,QAAQ;gBAAWkD,MAAM,CAAC,WAAW,EAAEU,QAAQlB,KAAK,EAAE;YAAC;YACrG,MAAMoB,eAA2D,CAAC;YAClE,KAAK,MAAMpH,QAAQb,KAAK8E,IAAI,CAAE;gBAC5B,MAAMoD,MAAMzI,MAAM0I,IAAI,CAAC,CAAChC,MAAQA,IAAItF,IAAI,KAAKA;gBAC7C,MAAMgF,MAAMP,KAAKhF,GAAG,CAACO;gBACrB,IAAI,CAACqH,OAAO,CAACrC,OAAO,CAACvJ,qBAAqBuJ,QAAQ,CAACA,IAAI1E,OAAO,CAACwC,MAAM,EAAE;gBACvEsE,YAAY,CAAC,CAAC,IAAI,EAAEC,IAAI3G,KAAK,EAAE,CAAC,GAAG;oBAAEhB,IAAI2H,IAAI3H,EAAE;oBAAEG,IAAImF,IAAI1E,OAAO,CAAC,EAAE;gBAAC;YACtE;YACA,MAAMiH,mBAAUb,WAAWc,YAAY,oBAAvBd,WAAWc,YAAY,MAAvBd,YAA0B;gBAAE9E,MAAM9B,KAAK8B,IAAI;gBAAEe,MAAM7C,KAAK6C,IAAI;YAAC,GAAG;gBAAEiB,QAAQhE,IAAIgE,MAAM;gBAAEwD;YAAa,sBAAMtH,KAAK6C,IAAI;YAClI,MAAM8E,UAAUX,OAAOY,KAAK,CAACH,SAAS;gBAAE3D,QAAQhE,IAAIgE,MAAM;YAAC;YAC3D,IAAI6D,QAAQE,EAAE,KAAK,OAAO;oBAE2CF;gBADnE,OAAOtB,OACLhD,OAAOhE,KAAKa,IAAI,EAAE;oBAAE4H,MAAM;oBAAMC,QAAQ;oBAAgBC,OAAO,GAAEL,qBAAAA,QAAQM,QAAQ,CAAC,EAAE,YAAnBN,qBAAuBrL;gBAAyB;YAErH;YACA,MAAMyD,KAAKF,iBAAiBC,KAAKT;YACjC,MAAM6I,UAAU,MAAMlB,OAAOmB,KAAK,CAAC;gBACjC/C,OAAOtF,IAAIsF,KAAK;gBAChBtB,QAAQhE,IAAIgE,MAAM;gBAClBoD,KAAKpH,IAAIqH,SAAS;gBAClBzD;gBACAsC,KAAK5F,QAAQ4F,GAAG;gBAChBjG;gBACA+B,MAAM9B,KAAK8B,IAAI;gBACf2F;YACF;YACA,IAAIS,QAAQL,EAAE,KAAK,OAAO;gBACxB,OAAOxB,OAAOhD,OAAOhE,KAAKa,IAAI,EAAE;oBAAE4H,MAAM;oBAAOC,QAAQ;oBAAUC,SAASE,QAAQhC,KAAK;gBAAC;YAC1F;YACA,MAAMJ,SAAsB;gBAC1BC,UAAU;gBACVhG,IAAImI,QAAQnI,EAAE;gBACdqI,WAAWF,QAAQE,SAAS;gBAC5BtE,QAAQhE,IAAIgE,MAAM;gBAClBlD,OAAOsH,QAAQpG,IAAI;gBACnBiF,eAAeH,WAAWG,aAAa;gBACvCL,MAAM,CAAC,YAAY,EAAEE,WAAWyB,KAAK,CAAC,CAAC,CAAC;YAC1C;YACA,OAAOhC,OACL;gBACEnG,MAAMb,KAAKa,IAAI;gBACfsD,QAAQqD,WAAW,aAAa;gBAChCrG,SAAS;oBAAC0H,QAAQnI,EAAE;iBAAC;gBACrB2G;eACIG,WAAW;gBAAEF,YAAYH,YAAYG,UAAU;YAAC,IAAI,CAAC,IAE3D,aAAKrJ,iBAAiBsH;gBAAQpE,SAAS;oBAACsF;iBAAO;;QAEnD;QAEA,8DAA8D;QAC9D,MAAMrG,OAAOL,mBAAmBC,MAAMC;QACtC,MAAMgJ,SAAS7I,OAAO2E,UAAU3E,QAAQ;QACxC,IAAI,CAACA,QAAQ,CAAC6I,QAAQ,OAAOjC,OAAO;YAAEnG,MAAMb,KAAKa,IAAI;YAAEsD,QAAQ;YAAWkD,MAAMhI,uBAAuBC;QAAM;QAC7G,MAAM4J,UAAUpI,eAAeL,KAAKT,MAAM;YAAEI;YAAMX;YAAOyB;YAAQjB;YAAKqD,YAAY6D,YAAY7D,UAAU;QAAC;QACzG,sEAAsE;QACtE,sDAAsD;QACtD,IAAItD,KAAKW,IAAI,IAAI2E,EAAAA,YAAAA,KAAKhF,GAAG,CAACN,KAAKa,IAAI,sBAAlByE,UAAqBnB,MAAM,MAAK,WAAW;gBAIhD1D;YAHV,MAAMsH,UAAU,MAAM7C,aAAa9E,MAAM;gBACvCoE;gBACAuB,OAAOtF,IAAIsF,KAAK;gBAChBtB,MAAM,GAAEhE,eAAAA,IAAIgE,MAAM,YAAVhE,eAAc;gBACtB8C,QAAQ2F,QAAQ3F,MAAM;gBACtBc;gBACAwD,KAAKpH,IAAIqH,SAAS;YACpB,GAAGlB,KAAK,CAAC,CAACC;gBACRC,QAAQD,KAAK,CAAC,kCAAkC;oBAAEd,OAAOtF,IAAIsF,KAAK;oBAAEgB,OAAOtG,IAAIG,GAAG;oBAAEC,MAAMb,KAAKa,IAAI;oBAAEgG;gBAAM;gBAC3G,OAAO;oBAAE1C,QAAQ;oBAAc0C,OAAO5J;gBAAyB;YACjE;YACA,IAAI8K,SAAS,OAAOf,OAAO;gBAAEnG,MAAMb,KAAKa,IAAI;gBAAEsD,QAAQ;gBAAWkD,MAAM,CAAC,WAAW,EAAEU,QAAQlB,KAAK,EAAE;YAAC;QACvG;QAEA,IAAIR;QACJ,IAAI;YACFA,UAAU,MAAM4C,OAAO,aAAKlI;gBAASN,KAAKyI;;QAC5C,EAAE,OAAOrC,OAAO;YACd,wEAAwE;YACxE,sDAAsD;YACtD,IAAI1J,qBAAqB0J,QAAQ,MAAMA;YACvCC,QAAQD,KAAK,CAAC,uBAAuB;gBAAEd,OAAOtF,IAAIsF,KAAK;gBAAEgB,OAAOtG,IAAIG,GAAG;gBAAEC,MAAMb,KAAKa,IAAI;gBAAEgG;YAAM;YAChG,OAAOG,OAAOhD,OAAOhE,KAAKa,IAAI,EAAE;gBAAE4H,MAAM;gBAAMC,QAAQ;gBAAYC,SAAS1L;YAAyB;QACtG;QACA,MAAMgK,QAAQ5J,YAAYgJ;QAC1B,MAAM8C,MAAM9C,QAAQlF,OAAO,CAAC6B,GAAG,CAAC,CAACyD,SAAWA,OAAO/F,EAAE;QACrD,MAAM0I,UAAUhM,cAAc4C,KAAKa,IAAI,EAAEwF;QACzC,IAAI+C,SAAS,OAAOpC,OAAOoC,SAASnC;QACpC,6EAA6E;QAC7E,IAAIjH,KAAKE,MAAM,IAAIO,IAAIgE,MAAM,EAAE;YAC7B,MAAM4E,OAAOhD,QAAQlF,OAAO,CAACgH,IAAI,CAAC,CAAC1B,SAAWA,OAAOC,QAAQ,KAAK;YAClE,MAAMmC,UACJQ,SAASC,aACR,MAAMjL,kBACLmG,WACA;gBAAEC,QAAQhE,IAAIgE,MAAM;gBAAE8E,WAAWL,QAAQtI,GAAG;gBAAEV,QAAQF,KAAKE,MAAM;gBAAEsJ,SAASH,KAAK3I,EAAE;YAAC,GACpF0E;YAEJ,IAAI,CAACyD,SAAS;gBACZ,OAAO7B,OACLhD,OAAOhE,KAAKa,IAAI,EAAE;oBAAE4H,MAAM;oBAAMC,QAAQ;oBAAgBC,SAASpJ;gBAA+B,IAChG,aAAK0H;oBAAO9F,SAASkF,QAAQlF,OAAO,CAACkB,MAAM,CAAC,CAACoE,SAAWA,OAAOC,QAAQ,KAAK;;YAEhF;QACF;QACA,MAAM+C,OAAOzC,OACX;YACEnG,MAAMb,KAAKa,IAAI;YACfsD,QAAQqD,WAAW,aAAa;YAChCrG,SAASgI;YACT9B;WACIG,WAAW;YAAEF,YAAYH,YAAYG,UAAU;QAAC,IAAI,CAAC,IAE3DL;QAEF,IAAIwC,KAAKvC,QAAQ,EAAE,OAAOuC;QAC1B,4EAA4E;QAC5EnE,KAAKoE,GAAG,CAAC1J,KAAKa,IAAI,EAAE,aAAMyE,KAAKhF,GAAG,CAACN,KAAKa,IAAI;YAAuBsD,QAAQqD,WAAW,aAAa;YAAarG,SAASgI;;QACzH,OAAO/C,OAAOqD,MAAMzJ,KAAKE,MAAM,GAAGmG,QAAQlF,OAAO,CAACkB,MAAM,CAAC,CAACoE,SAAWA,OAAOC,QAAQ,KAAK,YAAY,EAAE;IACzG;AACF;AAEA,OAAO,MAAMiD,oBAAoB9E,uBAAsB;AAEvD;;;;CAIC,GACD,OAAO,SAAS+E,uBAAuBnJ,GAAU;QAI/BhE,eAOTiD,wCACAmK;QAPQpJ;IAJf,MAAMO,OAAOhD,gBAAgByC;IAC7B,IAAI,CAACO,MAAM,OAAO9C;IAClB,MAAMuB,QAAQ7C,aAAaoE;IAC3B,MAAMyE,WAAUhJ,gBAAAA,aAAagD,kBAAbhD,gBAAuBgD;IACvC,MAAMyB,SAAST,EAAAA,aAAAA,IAAIqB,KAAK,qBAATrB,WAAWkD,MAAM,IAAGlD,IAAIqB,KAAK,GAAGzF,qBAAqBoD;IACpE,MAAMO,OAAOxD,gBAAgBiJ,SAASvE;IACtC,IAAI,CAAClB,MAAM,OAAO9B;IAClB,MAAMkC,OAAyBJ,KAAKE,MAAM,GACtC,SACAF,KAAKG,QAAQ,IACVT,yCAAAA,kBAAkB,CAACM,KAAKG,QAAQ,CAACC,IAAI,CAAC,YAAtCV,yCAA0C,QAC1CmK,sCAAAA,0BAA0B,CAAC7J,KAAKO,EAAE,CAAC,YAAnCsJ,sCAAuC;IAC9C,IAAI,CAACzJ,MAAM,OAAOlC;IAClB,OAAOc,sBAAsB8B,eAAeL,KAAKT,MAAM;QAAEI;QAAMX;QAAOyB;QAAQjB,KAAK,IAAI2F;IAAM;AAC/F;AAEA,4GAA4G,GAC5G,MAAMiE,6BAAkE;IACtEhH,UAAU;IACViH,UAAU;IACVC,UAAU;AACZ;AAEA;;;;;CAKC,GACD,OAAO,eAAeC,0BAA0BC,KAK/C;IACC,MAAMC,UAAUxM,kBAAkBuM,MAAM5F,GAAG;IAC3C,IAAI,EAAC6F,2BAAAA,QAASC,UAAU,GAAE,OAAO;IACjC,IAAI;QACF,MAAMC,QAAQH,MAAMtD,GAAG,CAAC0D,WAAW,GAAGtG,KAAK,CAAC,GAAG;QAC/C,MAAMuG,WAAW,MAAM7M,oBAAoBwM,MAAMzF,SAAS,EAAE0F,QAAQC,UAAU,EAAEC,OAAO9J,GAAG;QAC1F,MAAM2G,QAAQ3J,qBACZE,2BAA2B8M,SAAShK,GAAG,CAAC,eAAegK,SAAShK,GAAG,CAAC/C;QAEtE,MAAMgN,OAAOC,KAAKC,GAAG,CAAC,GAAG1N,kCAAkCkK;QAC3D,OAAOgD,MAAMS,QAAQ,GAAGH,OACpB,CAAC,0BAA0B,EAAEN,MAAMS,QAAQ,CAAC,wCAAwC,EAAEH,KAAK,oDAAoD,CAAC,GAChJ;IACN,EAAE,OAAO1D,OAAO;QACdC,QAAQD,KAAK,CAAC,qCAAqC;YAAEA;QAAM;QAC3D,OAAO;IACT;AACF;AASA;;;;;CAKC,GACD,OAAO,SAAS8D,0BAA0B7F,OAA6B,CAAC,CAAC;QACxDA,cACYA,0BACXA;IAFhB,MAAMG,UAASH,eAAAA,KAAKG,MAAM,YAAXH,eAAgB,CAAC/D,UAAYpD,WAAWoD;IACvD,MAAM6J,sBAAqB9F,2BAAAA,KAAK8F,kBAAkB,YAAvB9F,2BAA2BkF;IACtD,MAAMa,WAAU/F,gBAAAA,KAAK+F,OAAO,YAAZ/F,gBAAgB/I;IAChC,OAAO,OAAOgF;QACZ,IAAI,CAACA,QAAQ0D,MAAM,EAAE,OAAO;YAAEN,QAAQ;YAAK0C,OAAO;QAA0D;QAC5G,MAAMiE,QAAQ,MAAMD,QAAQ9J,QAAQ0D,MAAM;QAC1C,IAAI,CAACqG,SAASA,UAAU/J,QAAQgF,KAAK,EAAE,OAAO;YAAE5B,QAAQ;YAAK0C,OAAO;QAAe;QACnF,IAAI,CAAC5H,mBAAmB,SAAS,OAAO;YAAEkF,QAAQ;YAAK0C,OAAO;QAAgD;QAC9G,MAAM7F,OAAOD,QAAQC,IAAI;QACzB,IAAI,CAACA,MAAM,OAAO;QAClB,MAAMqD,MAAMtD,QAAQsD,GAAG;QACvB,MAAM2B,YAAY5B,iBAAiBC;QACnC,MAAMyB,OAAO,MAAMvB,SAASxD,QAAQyD,SAAS,EAAEzD,QAAQ0D,MAAM;QAC7D,MAAMxE,MAAM,MAAMgF,OAAO;YAAEc,OAAOhF,QAAQgF,KAAK;YAAEtB,QAAQ1D,QAAQ0D,MAAM;YAAEJ;YAAKyB;YAAME;QAAU;QAC9F,MAAM+E,QAAQpO,wBAAwBqE,MAAM;YAAEgF;YAAW/F;QAAI;QAC7D,IAAI8K,OAAO,OAAO;YAAE5G,QAAQ;YAAK0C,OAAOkE;QAAM;QAC9C,IAAI/E,WAAW;;YACb,MAAM+B,UAAU,MAAM6C,mBAAmB;gBACvCpG,WAAWzD,QAAQyD,SAAS;gBAC5BH;gBACAqG,UAAUvO,sBAAsB6E,MAAM;oBAAEf;gBAAI;gBAC5C0G,GAAG,UAAE7B,KAAK6B,GAAG,oBAAR7B,KAAK6B,GAAG,MAAR7B,wBAAgB,IAAIkG;YAC3B;YACA,IAAIjD,SAAS,OAAO;gBAAE5D,QAAQ;gBAAK0C,OAAOkB;YAAQ;QACpD;QACA,OAAO;IACT;AACF;AAEA,OAAO,MAAMkD,sBAAsBN,4BAA2B;AAE9D;;;CAGC,GACD,OAAO,SAASO;IACdhM,kBAAkB,SAASyK,mBAAmB;QAC5CwB,WAAWjN;QACXkN,cAAcxB;IAChB;IACAzK,wBAAwB,SAASK;IACjC3B,uBAAuB,SAASoN;AAClC"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-job-build-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 type { AglynOrgBilling } from '@aglyn/aglyn/foundation/definitions/org-billing.types'\nimport { resolveEffectivePlan } from '@aglyn/aglyn/app-utils/plan-entitlements'\nimport { resolveOrgIdForHost } from '@aglyn/tenant-data-admin/server/organizations'\nimport {\n AI_BUILD_LIMITS,\n AI_BUILD_PUBLISH_INPUT,\n aiArticle,\n aiBuildCreditEstimate,\n aiBuildDegradation,\n aiBuildInitialLedger,\n aiBuildItemDelivered,\n aiBuildItemOpen,\n aiBuildNextUnit,\n aiBuildOrder,\n aiBuildPlacedItemLines,\n aiBuildPlanShapeRefusal,\n aiBuildUnits,\n type AiBuildOps,\n type AiBuildUnit,\n} from '../model/ai-build-job'\nimport { isAiPlanNewRef, type AiBuildPlanCreateKind } from '../model/ai-build-plan'\nimport type {\n AiJob,\n AiJobItemFailure,\n AiJobItemLedger,\n AiJobKind,\n AiJobOutput,\n AiJobPlan,\n} from '../model/ai-jobs.types'\nimport { AI_SITE_MAX_SECTIONS } from '../model/ai-site-job'\nimport { FREE_AI_TASTE_CREDITS_PER_MONTH } from '../plan-entitlements'\nimport { aiModelForStep } from '../providers/routing'\nimport {\n AI_BUILD_UNIT_EMPTY_COPY,\n aiBuildBuiltRefs,\n aiUnitErrorRetryable,\n aiUnitFailure,\n aiUnitSpend,\n} from './ai-build-unit-outcome'\nimport { assistCreditsFromUsd } from '../usage/assist-credits'\nimport { ASSIST_RETURNED_USD_FIELD, assistSpendAfterReturnsUsd } from '../usage/assist-credit-returns'\nimport { freeAccountUsageRef, freeAssistAccount, type AssistMeteredOrg } from '../usage/assist-free-taste'\nimport { aiBuildOps, type AiBuildOpsContext } from './ai-build-capabilities'\nimport {\n aiJobAdmissionRefusal,\n registerAiJobAdmission,\n type AiJobAdmission,\n type AiJobAdmissionContext,\n} from './ai-job-admission'\nimport { aiOriginJobId } from './ai-job-draft-ids'\nimport { readAiDraftNodes } from './ai-job-drafts'\nimport { aiConfirmedPlan, aiUnspentOutcome } from './ai-job-generation'\nimport { AI_JOB_PAGE_STEP_MINIMUM_MS } from './ai-job-page-budget'\nimport {\n aiPluginDraftAdmissionRefusal,\n aiPluginDraftWriter,\n type AiPluginDraftWriterLookup,\n} from './ai-job-plugin-drafts'\nimport { aiSitePageWritten, aiSiteResolvedRef } from './ai-job-site-step'\nimport { AI_LAYOUT_SITE_PAGES_INPUT, aiLayoutSitePagesOfPlan } from './ai-job-layout-site-pages'\nimport { AI_LAYOUT_FORM_PAGE_INPUT, AI_LAYOUT_LANGUAGE_INPUT, aiLayoutFormPageOfPlan } from './ai-job-page-language'\nimport {\n AI_JOB_BRIEF_MAX_CHARS,\n type AiJobItemOutcome,\n type AiJobStepOutcome,\n type AiJobStepRunner,\n} from './ai-job-text-step'\nimport { aiJobPublishesBuild, aiPublishGuidedSite } from './ai-site-publish'\nimport {\n AI_PLANNED_JOB_KINDS,\n aiJobStepRunMinimumMs,\n aiJobStepRunnerFor,\n registerAiJobStep,\n registerAiJobStepPasses,\n} from './ai-jobs'\n\n/**\n * The build step (AGL-3616): the generation step of a `build` job, run once\n * the member confirmed the plan their request produced.\n *\n * Like the site scaffold it generalizes, it builds nothing itself and asks no\n * model of its own. Each pass takes the next unit in dependency order and\n * hands it to what builds that kind of thing — a page, layout, form,\n * component, email design or template to this plugin's own step, under a job\n * derived for the unit; another plugin's resource to that plugin's writer on\n * the resource-draft seam, with the content the owner's capability derives\n * from the item's arguments. One unit, one pass, one recorded spend.\n *\n * ── Settled item by item ────────────────────────────────────────────────\n *\n * Where a unit stands is read from the job's ITEM LEDGER, never from counting\n * outputs: the machine writes each pass's row in the transaction that\n * records its spend (`recordStep`). A unit that fails is a FAILED ROW, not a\n * failed job: the pass reports it, the machine gives back that item's spend\n * where the failure was ours, and the next pass builds the next unit. What\n * depended on it is built without it, or skipped where it cannot stand\n * without it (`aiBuildDegradation`). The machine ends the job when nothing is\n * left: `done` when anything was delivered, `failed` — its planning given\n * back too — when nothing was.\n *\n * ── Drafts, unless asked and confirmed ───────────────────────────────────\n *\n * Every unit writes the draft its own kind writes, which nothing publishes.\n * Only a build whose request asked to publish AND whose member ticked the\n * plan card's box puts its built pages live, once, on its last pass, through\n * the guided start's publish.\n */\n\n/** What a build answers with no confirmed plan to build. */\nexport const AI_BUILD_NO_PLAN_COPY = 'This build has no confirmed plan to build.'\n\n/** What a unit says when nothing on this site builds its operation any more. */\nexport const aiBuildUnavailableCopy = (noun: string): string =>\n `Not built: ${aiArticle(noun)} cannot be made on this site right now.`\n\n\n/** What a page that was reported built but holds none of its plan says. */\nexport const AI_BUILD_PAGE_NOT_WRITTEN_COPY = 'The page was not written from its plan.'\n\n\n/**\n * The most passes a build's step may take: every unit at a page's worst — its\n * sections and its listing — so a runner that never finishes is still\n * bounded while the largest plan is not. Try again starts the count over.\n */\nexport const AI_BUILD_MAX_PASSES = AI_BUILD_LIMITS.units * (AI_SITE_MAX_SECTIONS + 1)\n\n/** The job kind a creation of the build is built by. */\nconst CREATION_JOB_KINDS: Partial<Record<AiBuildPlanCreateKind, AiJobKind>> = {\n layout: 'layout',\n form: 'form',\n component: 'component',\n email: 'email',\n}\n\n/** The job kind a unit is built by, where an AI runner builds it. */\nexport function aiBuildUnitJobKind(unit: AiBuildUnit, ops: AiBuildOps): AiJobKind | null {\n if (unit.screen) return 'page'\n if (unit.creation) return CREATION_JOB_KINDS[unit.creation.kind] ?? null\n const runnerKind = ops.get(unit.op)?.runnerKind\n return runnerKind ? (runnerKind as AiJobKind) : null\n}\n\n/** The id a unit's job, and so its draft, is named by. */\nexport function aiBuildUnitJobId(job: Pick<AiJob, '$id'>, unit: AiBuildUnit): string {\n return unit.creation?.id ?? unit.screen?.id ?? unit.item?.id ?? `${job.$id}-${unit.slot}`\n}\n\n/**\n * The job a unit is built under (generalizing `aiSiteUnitJob`): this job's\n * org, site, creator and model; the kind that builds the unit; a plan\n * narrowed to the unit, its `new:` references resolved to what was built and\n * the failed ones left out; and a brief that says what the unit is, what it\n * is built without, and which blocks its sections place.\n */\nexport function aiBuildUnitJob(\n job: AiJob,\n unit: AiBuildUnit,\n context: {\n kind: AiJobKind\n units: readonly AiBuildUnit[]\n ledger: readonly AiJobItemLedger[]\n ops: AiBuildOps\n briefLines?: readonly string[]\n },\n): AiJob {\n const plan = job.plan as AiJobPlan\n const built = aiBuildBuiltRefs(context.units, context.ledger, job.outputs ?? [])\n const labels = { ...(plan.labels ?? {}) }\n for (const entry of built.values()) labels[entry.id] = entry.label\n const brief = [job.brief.trim()]\n const unitPlan: AiJobPlan = { ...plan, labels, reuse: [...plan.reuse], create: [], screens: [] }\n delete unitPlan.items\n const placedByScreens = new Set(plan.screens.flatMap((screen) => screen.sections.flatMap((section) => section.uses)))\n if (unit.creation) {\n unitPlan.reuse = plan.reuse.filter((entry) => !placedByScreens.has(entry.id))\n unitPlan.create = [{ ...unit.creation, duplicateOf: aiSiteResolvedRef(unit.creation.duplicateOf, built) }]\n brief.push(`Build the ${unit.creation.kind} “${unit.creation.name}”: ${unit.creation.why}`)\n }\n if (unit.screen) {\n const screen = unit.screen\n for (const entry of built.values()) {\n unitPlan.reuse.push({ kind: entry.kind, id: entry.id, purpose: `the ${entry.kind} this request built` })\n }\n let builtLayout: string | null = null\n for (const entry of built.values()) if (entry.kind === 'layout') builtLayout = builtLayout ?? entry.id\n unitPlan.screens = [\n {\n ...screen,\n // A page whose layout failed renders inside the site's own: the page\n // step falls back to it when the plan names none.\n layout: aiSiteResolvedRef(screen.layout, built) ?? (isAiPlanNewRef(screen.layout) ? builtLayout : null),\n template: aiSiteResolvedRef(screen.template, built),\n duplicateOf: aiSiteResolvedRef(screen.duplicateOf, built),\n record: screen.record\n ? { ...screen.record, dataset: aiSiteResolvedRef(screen.record.dataset, built) ?? screen.record.dataset }\n : null,\n sections: screen.sections.map((section) => ({\n ...section,\n uses: section.uses\n .map((ref) => aiSiteResolvedRef(ref, built))\n .filter((ref): ref is string => !!ref),\n })),\n },\n ]\n brief.push(`Build the page “${screen.title}”, at ${screen.slug}.`)\n brief.push(...aiBuildPlacedItemLines(unit, { units: context.units, ledger: context.ledger, ops: context.ops }))\n }\n const item = unit.item\n if (item) {\n const noun = context.ops.get(item.op)?.noun ?? item.op\n brief.push(`Build the ${noun} “${item.name}”${item.why ? `: ${item.why}` : '.'}`)\n // A planned kind's step builds the plan's first creation of its kind.\n unitPlan.create = AI_PLANNED_JOB_KINDS.includes(context.kind)\n ? [{ kind: context.kind as AiBuildPlanCreateKind, name: item.name, why: item.why, duplicateOf: null, fields: [], ...(item.id ? { id: item.id } : {}) }]\n : []\n }\n brief.push(...(context.briefLines ?? []))\n const inputs: Record<string, unknown> = {\n ...job.inputs,\n ...(item?.args ?? {}),\n originJobId: aiOriginJobId(job),\n }\n delete inputs[AI_BUILD_PUBLISH_INPUT]\n // A build's pages and layouts are designed in the layout language and\n // compiled (AGL-3660), told the pages the build plans and where its form is.\n if (context.kind === 'page' || context.kind === 'layout') {\n inputs[AI_LAYOUT_LANGUAGE_INPUT] = true\n const pages = aiLayoutSitePagesOfPlan(plan.screens)\n if (pages.length) inputs[AI_LAYOUT_SITE_PAGES_INPUT] = pages\n const formPage = aiLayoutFormPageOfPlan(plan)\n if (formPage) inputs[AI_LAYOUT_FORM_PAGE_INPUT] = formPage\n }\n return {\n ...job,\n $id: aiBuildUnitJobId(job, unit),\n kind: context.kind,\n steps: [],\n outputs: [],\n items: null,\n plan: item && !AI_PLANNED_JOB_KINDS.includes(context.kind) ? null : unitPlan,\n inputs,\n brief: brief.join('\\n').slice(0, AI_JOB_BRIEF_MAX_CHARS),\n }\n}\n\n/** The unit's failure, for its row: ours or not, why, in customer-safe words. */\nfunction failed(\n slot: string,\n failure: AiJobItemFailure,\n extra: Partial<AiJobItemOutcome> = {},\n): AiJobItemOutcome {\n return { slot, status: 'failed', failure, ...extra }\n}\n\nexport interface AiJobBuildStepDeps {\n /** The runner registry; specs hand in fakes. */\n runnerFor?: typeof aiJobStepRunnerFor\n /** The draft writer registry; specs hand in fakes. */\n writerFor?: AiPluginDraftWriterLookup\n /** The operations this site may use; the registry and its gates otherwise. */\n opsFor?: (context: AiBuildOpsContext) => Promise<AiBuildOps>\n /** A runner kind's own admission, asked before its item runs; the registry's otherwise. */\n admissionFor?: typeof aiJobAdmissionRefusal\n /** Another plugin's admission for its writer; the seam's otherwise. */\n pluginAdmission?: typeof aiPluginDraftAdmissionRefusal\n /** The draft reader a built page is checked through. */\n readNodes?: typeof readAiDraftNodes\n /** The publish a build asked for and confirmed. */\n publish?: typeof aiPublishGuidedSite\n}\n\n/** Whether a build's workspace spends the Free taste. */\nexport function aiBuildFreeTaste(org: object | null | undefined): boolean {\n return Boolean(org) && resolveEffectivePlan(org as never) === 'free'\n}\n\n/** The site document a gate reads, or `null`. */\nasync function readHost(firestore: FirebaseFirestore.Firestore, hostId: string | null) {\n if (!hostId) return null\n return ((await firestore.collection('hosts').doc(hostId).get()).data() ?? null) as Record<string, unknown> | null\n}\n\nexport function createAiJobBuildStep(deps: AiJobBuildStepDeps = {}): AiJobStepRunner {\n const runnerFor = deps.runnerFor ?? aiJobStepRunnerFor\n const writerFor = deps.writerFor ?? aiPluginDraftWriter\n const opsFor = deps.opsFor ?? ((context) => aiBuildOps(context))\n const admissionFor = deps.admissionFor ?? aiJobAdmissionRefusal\n const pluginAdmission = deps.pluginAdmission ?? aiPluginDraftAdmissionRefusal\n const readNodes = deps.readNodes ?? readAiDraftNodes\n const publish = deps.publish ?? aiPublishGuidedSite\n\n return async (context): Promise<AiJobStepOutcome> => {\n const { job, firestore } = context\n const model = context.modelFor?.('job.plan') ?? aiModelForStep('job.plan')\n const plan = aiConfirmedPlan(job)\n if (!plan) return { ...aiUnspentOutcome(model), failure: AI_BUILD_NO_PLAN_COPY }\n const org = (context.org ?? null) as Partial<AglynOrgBilling> | null\n const units = aiBuildUnits(plan)\n const ordered = aiBuildOrder(units) ?? units\n const starting = !job.items?.length\n const ledger = starting ? aiBuildInitialLedger(units) : (job.items as AiJobItemLedger[])\n const init = starting ? { items: ledger } : {}\n const unit = aiBuildNextUnit(ordered, ledger)\n const rows = new Map(ledger.map((row) => [row.slot, row]))\n const host = await readHost(firestore, job.hostId ?? null)\n const ops = await opsFor({\n orgId: job.orgId,\n hostId: job.hostId ?? null,\n org,\n host,\n freeTaste: aiBuildFreeTaste(org),\n })\n\n /** Whether units other than this one are still to build. */\n const othersOpen = (slot: string) =>\n ordered.some((one) => one.slot !== slot && aiBuildItemOpen(rows.get(one.slot) ?? { status: 'pending' }))\n\n /** The build's last pass puts its pages live, where it was asked and confirmed. */\n const finish = async (outcome: AiJobStepOutcome, extraPages: readonly AiJobOutput[] = []): Promise<AiJobStepOutcome> => {\n if (!aiJobPublishesBuild(job) || job.sitePublish || !job.hostId) return outcome\n const pageIds = new Set(\n units\n .filter((one) => one.screen && aiBuildItemDelivered(rows.get(one.slot) ?? { status: 'pending' }))\n .flatMap((one) => rows.get(one.slot)?.outputs ?? []),\n )\n const pages = [\n ...(job.outputs ?? []).filter((output) => output.resource === 'screen' && pageIds.has(output.id)),\n ...extraPages,\n ]\n if (!pages.length) return outcome\n const sitePublish = await publish(firestore, { job, outputs: pages, now: context.now }).catch((error: unknown) => {\n console.error('ai build publish threw', { orgId: job.orgId, jobId: job.$id, error })\n return null\n })\n return sitePublish ? { ...outcome, sitePublish } : outcome\n }\n\n if (!unit) return finish({ ...aiUnspentOutcome(model), ...init })\n\n const settle = (item: AiJobItemOutcome, spent: AiJobStepOutcome = aiUnspentOutcome(model)): AiJobStepOutcome => ({\n ...spent,\n ...init,\n item,\n ...(item.status === 'running' || othersOpen(unit.slot) ? { continue: true } : {}),\n })\n\n // What its dependencies came to.\n const degradation = aiBuildDegradation(unit, { units, ledger, ops })\n if (degradation.skip) {\n return settle({ slot: unit.slot, status: 'skipped', note: degradation.skip, degradedBy: degradation.degradedBy })\n }\n const capability = ops.get(unit.op)\n const noun = capability?.noun ?? unit.op\n if (!capability) return settle({ slot: unit.slot, status: 'skipped', note: aiBuildUnavailableCopy(noun) })\n const degraded = degradation.degradedBy.length > 0\n const note = degradation.notes.length ? degradation.notes.join(' ') : null\n\n // Another plugin's resource: its writer, with the content its capability derives.\n if (capability.draftResource) {\n const item = unit.item\n const writer = writerFor(capability.draftResource)\n if (!item || !writer || !job.hostId) {\n return settle({ slot: unit.slot, status: 'skipped', note: aiBuildUnavailableCopy(noun) })\n }\n const admission: AiJobAdmissionContext = {\n firestore,\n orgId: job.orgId,\n hostId: job.hostId,\n inputs: {},\n org,\n uid: job.createdBy,\n }\n const refusal = await pluginAdmission(admission, {\n kind: 'build',\n drafts: [{ resource: capability.draftResource, label: capability.noun }],\n writerFor,\n })\n if (refusal) return settle({ slot: unit.slot, status: 'skipped', note: `Not built: ${refusal.error}` })\n const dependencies: Record<string, { op: string; id: string }> = {}\n for (const slot of unit.deps) {\n const dep = units.find((one) => one.slot === slot)\n const row = rows.get(slot)\n if (!dep || !row || !aiBuildItemDelivered(row) || !row.outputs.length) continue\n dependencies[`new:${dep.label}`] = { op: dep.op, id: row.outputs[0] }\n }\n const content = capability.draftContent?.({ name: item.name, args: item.args }, { hostId: job.hostId, dependencies }) ?? item.args\n const checked = writer.check(content, { hostId: job.hostId })\n if (checked.ok === false) {\n return settle(\n failed(unit.slot, { ours: true, reason: 'step-failure', message: checked.problems[0] ?? AI_BUILD_UNIT_EMPTY_COPY }),\n )\n }\n const id = aiBuildUnitJobId(job, unit)\n const written = await writer.write({\n orgId: job.orgId,\n hostId: job.hostId,\n uid: job.createdBy,\n org,\n now: context.now,\n id,\n name: item.name,\n content,\n })\n if (written.ok === false) {\n return settle(failed(unit.slot, { ours: false, reason: 'review', message: written.error }))\n }\n const output: AiJobOutput = {\n resource: 'draft',\n id: written.id,\n versionId: written.versionId,\n hostId: job.hostId,\n label: written.name,\n draftResource: capability.draftResource,\n note: `A draft, in ${capability.where}.`,\n }\n return settle(\n {\n slot: unit.slot,\n status: degraded ? 'degraded' : 'succeeded',\n outputs: [written.id],\n note,\n ...(degraded ? { degradedBy: degradation.degradedBy } : {}),\n },\n { ...aiUnspentOutcome(model), outputs: [output] },\n )\n }\n\n // This plugin's own runner, under a job derived for the unit.\n const kind = aiBuildUnitJobKind(unit, ops)\n const runner = kind ? runnerFor(kind) : null\n if (!kind || !runner) return settle({ slot: unit.slot, status: 'skipped', note: aiBuildUnavailableCopy(noun) })\n const derived = aiBuildUnitJob(job, unit, { kind, units, ledger, ops, briefLines: degradation.briefLines })\n // An item's kind is asked its own admission first (a campaign's plan,\n // a template's subject), once, before its first pass.\n if (unit.item && rows.get(unit.slot)?.status !== 'running') {\n const refusal = await admissionFor(kind, {\n firestore,\n orgId: job.orgId,\n hostId: job.hostId ?? null,\n inputs: derived.inputs,\n org,\n uid: job.createdBy,\n }).catch((error: unknown) => {\n console.error('ai build item admission failed', { orgId: job.orgId, jobId: job.$id, slot: unit.slot, error })\n return { status: 403 as const, error: AI_BUILD_UNIT_EMPTY_COPY }\n })\n if (refusal) return settle({ slot: unit.slot, status: 'skipped', note: `Not built: ${refusal.error}` })\n }\n\n let outcome: AiJobStepOutcome\n try {\n outcome = await runner({ ...context, job: derived })\n } catch (error) {\n // A provider that will answer later is the machine's to retry; anything\n // else is this item's failure, and the build goes on.\n if (aiUnitErrorRetryable(error)) throw error\n console.error('ai build unit threw', { orgId: job.orgId, jobId: job.$id, slot: unit.slot, error })\n return settle(failed(unit.slot, { ours: true, reason: 'provider', message: AI_BUILD_UNIT_EMPTY_COPY }))\n }\n const spent = aiUnitSpend(outcome)\n const ids = outcome.outputs.map((output) => output.id)\n const stopped = aiUnitFailure(unit.slot, outcome)\n if (stopped) return settle(stopped, spent)\n // A page counts as built only when its plan's sections are in it (AGL-3596).\n if (unit.screen && job.hostId) {\n const page = outcome.outputs.find((output) => output.resource === 'screen')\n const written =\n page !== undefined &&\n (await aiSitePageWritten(\n firestore,\n { hostId: job.hostId, unitJobId: derived.$id, screen: unit.screen, draftId: page.id },\n readNodes,\n ))\n if (!written) {\n return settle(\n failed(unit.slot, { ours: true, reason: 'step-failure', message: AI_BUILD_PAGE_NOT_WRITTEN_COPY }),\n { ...spent, outputs: outcome.outputs.filter((output) => output.resource !== 'screen') },\n )\n }\n }\n const done = settle(\n {\n slot: unit.slot,\n status: degraded ? 'degraded' : 'succeeded',\n outputs: ids,\n note,\n ...(degraded ? { degradedBy: degradation.degradedBy } : {}),\n },\n spent,\n )\n if (done.continue) return done\n // The last unit: what was built goes live where it was asked and confirmed.\n rows.set(unit.slot, { ...(rows.get(unit.slot) as AiJobItemLedger), status: degraded ? 'degraded' : 'succeeded', outputs: ids })\n return finish(done, unit.screen ? outcome.outputs.filter((output) => output.resource === 'screen') : [])\n }\n}\n\nexport const runAiJobBuildStep = createAiJobBuildStep()\n\n/**\n * The least time a build's next pass needs: what the step that builds its\n * next unit registers for the job derived for it; a page pass's when the\n * next unit is another plugin's draft, which asks no model.\n */\nexport function aiBuildJobRunMinimumMs(job: AiJob): number {\n const plan = aiConfirmedPlan(job)\n if (!plan) return AI_JOB_PAGE_STEP_MINIMUM_MS\n const units = aiBuildUnits(plan)\n const ordered = aiBuildOrder(units) ?? units\n const ledger = job.items?.length ? job.items : aiBuildInitialLedger(units)\n const unit = aiBuildNextUnit(ordered, ledger)\n if (!unit) return AI_JOB_PAGE_STEP_MINIMUM_MS\n const kind: AiJobKind | null = unit.screen\n ? 'page'\n : unit.creation\n ? (CREATION_JOB_KINDS[unit.creation.kind] ?? null)\n : (AI_BUILD_ITEM_RUNNER_KINDS[unit.op] ?? null)\n if (!kind) return AI_JOB_PAGE_STEP_MINIMUM_MS\n return aiJobStepRunMinimumMs(aiBuildUnitJob(job, unit, { kind, units, ledger, ops: new Map() }))\n}\n\n/** The runner kinds this plugin's own item operations use, for the time a pass needs without the registry. */\nconst AI_BUILD_ITEM_RUNNER_KINDS: Readonly<Record<string, AiJobKind>> = {\n template: 'template',\n campaign: 'campaign',\n workflow: 'workflow',\n function: 'logic',\n edit: 'edit',\n}\n\n/**\n * Why a Free build cannot be confirmed: its estimate is more than the owner's\n * Free allowance has left this month. Read off the account month the meter\n * writes, net of give-backs; a read that fails admits, since the reservation\n * still refuses at the wall.\n */\nexport async function aiBuildFreeBalanceRefusal(input: {\n firestore: FirebaseFirestore.Firestore\n org: object | null\n estimate: number\n now: Date\n}): Promise<string | null> {\n const account = freeAssistAccount(input.org as AssistMeteredOrg | null)\n if (!account?.accountUid) return null\n try {\n const month = input.now.toISOString().slice(0, 7)\n const snapshot = await freeAccountUsageRef(input.firestore, account.accountUid, month).get()\n const spent = assistCreditsFromUsd(\n assistSpendAfterReturnsUsd(snapshot.get('estCostUsd'), snapshot.get(ASSIST_RETURNED_USD_FIELD)),\n )\n const left = Math.max(0, FREE_AI_TASTE_CREDITS_PER_MONTH - spent)\n return input.estimate > left\n ? `This plan is estimated at ${input.estimate} credits, and your Free AI credits have ${left} left this month. Ask for less, or upgrade for more.`\n : null\n } catch (error) {\n console.error('ai build free balance read failed', { error })\n return null\n }\n}\n\nexport interface AiBuildAdmissionDeps {\n opsFor?: (context: AiBuildOpsContext) => Promise<AiBuildOps>\n freeBalanceRefusal?: typeof aiBuildFreeBalanceRefusal\n ownerOf?: typeof resolveOrgIdForHost\n now?: () => Date\n}\n\n/**\n * A build is admitted for a site of the job's own org where a page can be\n * built; and confirmed only for a plan it can build here — its shape, its\n * operations as this site has them, and on the Free taste an estimate the\n * month's Free credits still cover.\n */\nexport function createAiBuildJobAdmission(deps: AiBuildAdmissionDeps = {}): AiJobAdmission {\n const opsFor = deps.opsFor ?? ((context) => aiBuildOps(context))\n const freeBalanceRefusal = deps.freeBalanceRefusal ?? aiBuildFreeBalanceRefusal\n const ownerOf = deps.ownerOf ?? resolveOrgIdForHost\n return async (context) => {\n if (!context.hostId) return { status: 400, error: 'Open the site to build on before asking Assist to build' }\n const owner = await ownerOf(context.hostId)\n if (!owner || owner !== context.orgId) return { status: 404, error: 'Unknown site' }\n if (!aiJobStepRunnerFor('page')) return { status: 400, error: 'Building from a request is not available yet.' }\n const plan = context.plan\n if (!plan) return null\n const org = context.org as Partial<AglynOrgBilling> | null\n const freeTaste = aiBuildFreeTaste(org)\n const host = await readHost(context.firestore, context.hostId)\n const ops = await opsFor({ orgId: context.orgId, hostId: context.hostId, org, host, freeTaste })\n const shape = aiBuildPlanShapeRefusal(plan, { freeTaste, ops })\n if (shape) return { status: 400, error: shape }\n if (freeTaste) {\n const refusal = await freeBalanceRefusal({\n firestore: context.firestore,\n org,\n estimate: aiBuildCreditEstimate(plan, { ops }),\n now: deps.now?.() ?? new Date(),\n })\n if (refusal) return { status: 403, error: refusal }\n }\n return null\n }\n}\n\nexport const aiBuildJobAdmission = createAiBuildJobAdmission()\n\n/**\n * Registers the build with the least time a pass needs, the time its next\n * pass needs, the passes its largest plan may take, and its admission.\n */\nexport function registerAiBuildJob(): void {\n registerAiJobStep('build', runAiJobBuildStep, {\n minimumMs: AI_JOB_PAGE_STEP_MINIMUM_MS,\n minimumMsFor: aiBuildJobRunMinimumMs,\n })\n registerAiJobStepPasses('build', AI_BUILD_MAX_PASSES)\n registerAiJobAdmission('build', aiBuildJobAdmission)\n}\n"],"names":["resolveEffectivePlan","resolveOrgIdForHost","AI_BUILD_LIMITS","AI_BUILD_PUBLISH_INPUT","aiArticle","aiBuildCreditEstimate","aiBuildDegradation","aiBuildInitialLedger","aiBuildItemDelivered","aiBuildItemOpen","aiBuildNextUnit","aiBuildOrder","aiBuildPlacedItemLines","aiBuildPlanShapeRefusal","aiBuildUnits","isAiPlanNewRef","AI_SITE_MAX_SECTIONS","FREE_AI_TASTE_CREDITS_PER_MONTH","aiModelForStep","AI_BUILD_UNIT_EMPTY_COPY","aiBuildBuiltRefs","aiUnitErrorRetryable","aiUnitFailure","aiUnitSpend","assistCreditsFromUsd","ASSIST_RETURNED_USD_FIELD","assistSpendAfterReturnsUsd","freeAccountUsageRef","freeAssistAccount","aiBuildOps","aiJobAdmissionRefusal","registerAiJobAdmission","aiOriginJobId","readAiDraftNodes","aiConfirmedPlan","aiUnspentOutcome","AI_JOB_PAGE_STEP_MINIMUM_MS","aiPluginDraftAdmissionRefusal","aiPluginDraftWriter","aiSitePageWritten","aiSiteResolvedRef","AI_LAYOUT_SITE_PAGES_INPUT","aiLayoutSitePagesOfPlan","AI_LAYOUT_FORM_PAGE_INPUT","AI_LAYOUT_LANGUAGE_INPUT","aiLayoutFormPageOfPlan","AI_JOB_BRIEF_MAX_CHARS","aiJobPublishesBuild","aiPublishGuidedSite","AI_PLANNED_JOB_KINDS","aiJobStepRunMinimumMs","aiJobStepRunnerFor","registerAiJobStep","registerAiJobStepPasses","AI_BUILD_NO_PLAN_COPY","aiBuildUnavailableCopy","noun","AI_BUILD_PAGE_NOT_WRITTEN_COPY","AI_BUILD_MAX_PASSES","units","CREATION_JOB_KINDS","layout","form","component","email","aiBuildUnitJobKind","unit","ops","screen","creation","kind","runnerKind","get","op","aiBuildUnitJobId","job","id","item","$id","slot","aiBuildUnitJob","context","plan","built","ledger","outputs","labels","entry","values","label","brief","trim","unitPlan","reuse","create","screens","items","placedByScreens","Set","flatMap","sections","section","uses","filter","has","duplicateOf","push","name","why","purpose","builtLayout","template","record","dataset","map","ref","title","slug","includes","fields","briefLines","inputs","args","originJobId","pages","length","formPage","steps","join","slice","failed","failure","extra","status","aiBuildFreeTaste","org","Boolean","readHost","firestore","hostId","collection","doc","data","createAiJobBuildStep","deps","runnerFor","writerFor","opsFor","admissionFor","pluginAdmission","readNodes","publish","rows","model","modelFor","ordered","starting","init","Map","row","host","orgId","freeTaste","othersOpen","some","one","finish","outcome","extraPages","sitePublish","pageIds","output","resource","now","catch","error","console","jobId","settle","spent","continue","degradation","skip","note","degradedBy","capability","degraded","notes","draftResource","writer","admission","uid","createdBy","refusal","drafts","dependencies","dep","find","content","draftContent","checked","check","ok","ours","reason","message","problems","written","write","versionId","where","runner","derived","ids","stopped","page","undefined","unitJobId","draftId","done","set","runAiJobBuildStep","aiBuildJobRunMinimumMs","AI_BUILD_ITEM_RUNNER_KINDS","campaign","workflow","function","edit","aiBuildFreeBalanceRefusal","input","account","accountUid","month","toISOString","snapshot","left","Math","max","estimate","createAiBuildJobAdmission","freeBalanceRefusal","ownerOf","owner","shape","Date","aiBuildJobAdmission","registerAiBuildJob","minimumMs","minimumMsFor"],"mappings":"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"}
|