@aglyn/plugins-ai 1.0.0-beta.291 → 1.0.0-beta.293
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +17 -17
- package/src/lib/components/ai-site-import-job.component.js +5 -4
- package/src/lib/components/ai-site-import-job.component.js.map +1 -1
- package/src/lib/components/ai-site-import-start.component.js +3 -3
- package/src/lib/components/ai-site-import-start.component.js.map +1 -1
- package/src/lib/components/ai-site-start-card.component.d.ts +1 -1
- package/src/lib/components/ai-site-start-card.component.js +129 -29
- package/src/lib/components/ai-site-start-card.component.js.map +1 -1
- package/src/lib/components/ai-site-start-steps.component.d.ts +15 -3
- package/src/lib/components/ai-site-start-steps.component.js +42 -25
- package/src/lib/components/ai-site-start-steps.component.js.map +1 -1
- package/src/lib/components/ai-site-style-previews.d.ts +17 -0
- package/src/lib/components/ai-site-style-previews.js +26 -95
- package/src/lib/components/ai-site-style-previews.js.map +1 -1
- package/src/lib/declarations.server.js +22 -0
- package/src/lib/declarations.server.js.map +1 -1
- package/src/lib/jobs/ai-job-import-step.d.ts +21 -2
- package/src/lib/jobs/ai-job-import-step.js +179 -49
- package/src/lib/jobs/ai-job-import-step.js.map +1 -1
- package/src/lib/jobs/ai-job-layout-language.d.ts +27 -3
- package/src/lib/jobs/ai-job-layout-language.js +156 -113
- package/src/lib/jobs/ai-job-layout-language.js.map +1 -1
- package/src/lib/jobs/ai-job-layout-step.js +56 -17
- package/src/lib/jobs/ai-job-layout-step.js.map +1 -1
- package/src/lib/jobs/ai-job-page-language.d.ts +25 -15
- package/src/lib/jobs/ai-job-page-language.js +120 -66
- package/src/lib/jobs/ai-job-page-language.js.map +1 -1
- package/src/lib/jobs/ai-job-page-step.js +27 -7
- package/src/lib/jobs/ai-job-page-step.js.map +1 -1
- package/src/lib/jobs/ai-job-site-datasets.d.ts +12 -4
- package/src/lib/jobs/ai-job-site-datasets.js +36 -16
- package/src/lib/jobs/ai-job-site-datasets.js.map +1 -1
- package/src/lib/jobs/ai-jobs.js +6 -2
- package/src/lib/jobs/ai-jobs.js.map +1 -1
- package/src/lib/jobs/ai-layout-stock-photos.d.ts +50 -1
- package/src/lib/jobs/ai-layout-stock-photos.js +586 -35
- package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -1
- package/src/lib/jobs/ai-site-import-compile.d.ts +147 -0
- package/src/lib/jobs/ai-site-import-compile.js +1143 -0
- package/src/lib/jobs/ai-site-import-compile.js.map +1 -0
- package/src/lib/jobs/ai-site-import-document.d.ts +9 -36
- package/src/lib/jobs/ai-site-import-document.js +23 -489
- package/src/lib/jobs/ai-site-import-document.js.map +1 -1
- package/src/lib/jobs/ai-site-import-look.d.ts +54 -7
- package/src/lib/jobs/ai-site-import-look.js +163 -52
- package/src/lib/jobs/ai-site-import-look.js.map +1 -1
- package/src/lib/jobs/ai-site-import-publish.d.ts +7 -1
- package/src/lib/jobs/ai-site-import-publish.js +19 -5
- package/src/lib/jobs/ai-site-import-publish.js.map +1 -1
- package/src/lib/jobs/ai-site-late-photos.js +4 -2
- package/src/lib/jobs/ai-site-late-photos.js.map +1 -1
- package/src/lib/jobs/ai-site-publish.d.ts +10 -1
- package/src/lib/jobs/ai-site-publish.js +8 -3
- package/src/lib/jobs/ai-site-publish.js.map +1 -1
- package/src/lib/jobs/fixtures/ai-stock-photo-agl4092-1029-recordings.d.ts +23 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl4092-1029-recordings.js +677 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl4092-1029-recordings.js.map +1 -0
- package/src/lib/layout-language/ai-layout-compiler.d.ts +26 -0
- package/src/lib/layout-language/ai-layout-compiler.js +677 -33
- package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
- package/src/lib/layout-language/ai-layout-frame-hollows.js +5 -1
- package/src/lib/layout-language/ai-layout-frame-hollows.js.map +1 -1
- package/src/lib/layout-language/ai-layout-frame-source.d.ts +196 -0
- package/src/lib/layout-language/ai-layout-frame-source.js +726 -0
- package/src/lib/layout-language/ai-layout-frame-source.js.map +1 -0
- package/src/lib/layout-language/ai-layout-frame.d.ts +22 -0
- package/src/lib/layout-language/ai-layout-frame.js +121 -29
- package/src/lib/layout-language/ai-layout-frame.js.map +1 -1
- package/src/lib/layout-language/ai-layout-language.d.ts +103 -37
- package/src/lib/layout-language/ai-layout-language.js +85 -120
- package/src/lib/layout-language/ai-layout-language.js.map +1 -1
- package/src/lib/model/ai-credit-estimate.d.ts +11 -7
- package/src/lib/model/ai-credit-estimate.js +11 -7
- package/src/lib/model/ai-credit-estimate.js.map +1 -1
- package/src/lib/model/ai-site-import.d.ts +307 -13
- package/src/lib/model/ai-site-import.js +227 -19
- package/src/lib/model/ai-site-import.js.map +1 -1
- package/src/lib/model/ai-site-look.d.ts +65 -1
- package/src/lib/model/ai-site-look.js +141 -23
- package/src/lib/model/ai-site-look.js.map +1 -1
- package/src/lib/model/ai-site-photos.d.ts +2 -0
- package/src/lib/model/ai-site-photos.js.map +1 -1
- package/src/lib/model/ai-site-start-steps.d.ts +4 -3
- package/src/lib/model/ai-site-start-steps.js +11 -3
- package/src/lib/model/ai-site-start-steps.js.map +1 -1
- package/src/lib/model/ai-site-start.d.ts +23 -2
- package/src/lib/model/ai-site-start.js +25 -3
- package/src/lib/model/ai-site-start.js.map +1 -1
- package/src/lib/providers/routing.d.ts +11 -0
- package/src/lib/providers/routing.js +23 -0
- package/src/lib/providers/routing.js.map +1 -1
- package/src/lib/runtime/ai-doctrine-validators.d.ts +4 -2
- package/src/lib/runtime/ai-doctrine-validators.js +7 -2
- package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
- package/src/lib/runtime/ai-icon-library.d.ts +4 -0
- package/src/lib/runtime/ai-icon-library.js +4 -0
- package/src/lib/runtime/ai-icon-library.js.map +1 -1
- package/src/lib/runtime/ai-node-tree.js +5 -1
- package/src/lib/runtime/ai-node-tree.js.map +1 -1
- package/src/lib/runtime/ai-palette.d.ts +2 -0
- package/src/lib/runtime/ai-palette.generated.js +19 -3
- package/src/lib/runtime/ai-palette.generated.js.map +1 -1
- package/src/lib/runtime/ai-palette.js +2 -1
- package/src/lib/runtime/ai-palette.js.map +1 -1
- package/src/lib/site-import/fixtures/site-layout-recordings.d.ts +50 -0
- package/src/lib/site-import/fixtures/site-layout-recordings.js +86 -0
- package/src/lib/site-import/fixtures/site-layout-recordings.js.map +1 -0
- package/src/lib/site-import/site-import-crawl.d.ts +18 -1
- package/src/lib/site-import/site-import-crawl.js +70 -10
- package/src/lib/site-import/site-import-crawl.js.map +1 -1
- package/src/lib/site-import/site-import-css.d.ts +110 -0
- package/src/lib/site-import/site-import-css.js +826 -0
- package/src/lib/site-import/site-import-css.js.map +1 -0
- package/src/lib/site-import/site-import-html.d.ts +116 -1
- package/src/lib/site-import/site-import-html.js +538 -46
- package/src/lib/site-import/site-import-html.js.map +1 -1
- package/src/lib/site-import/site-import-layout.d.ts +79 -0
- package/src/lib/site-import/site-import-layout.js +1608 -0
- package/src/lib/site-import/site-import-layout.js.map +1 -0
- package/src/lib/site-import/site-import-nav.d.ts +40 -0
- package/src/lib/site-import/site-import-nav.js +437 -0
- package/src/lib/site-import/site-import-nav.js.map +1 -0
- package/src/lib/site-import/site-import-page.d.ts +8 -1
- package/src/lib/site-import/site-import-page.js +24 -2
- package/src/lib/site-import/site-import-page.js.map +1 -1
- package/src/lib/assets/site-styles/beauty.webp +0 -0
- package/src/lib/assets/site-styles/blog.webp +0 -0
- package/src/lib/assets/site-styles/business.webp +0 -0
- package/src/lib/assets/site-styles/coming-soon.webp +0 -0
- package/src/lib/assets/site-styles/education.webp +0 -0
- package/src/lib/assets/site-styles/events.webp +0 -0
- package/src/lib/assets/site-styles/fitness.webp +0 -0
- package/src/lib/assets/site-styles/landing.webp +0 -0
- package/src/lib/assets/site-styles/music.webp +0 -0
- package/src/lib/assets/site-styles/nonprofit.webp +0 -0
- package/src/lib/assets/site-styles/personal.webp +0 -0
- package/src/lib/assets/site-styles/photography.webp +0 -0
- package/src/lib/assets/site-styles/portfolio.webp +0 -0
- package/src/lib/assets/site-styles/professional.webp +0 -0
- package/src/lib/assets/site-styles/realestate.webp +0 -0
- package/src/lib/assets/site-styles/restaurant.webp +0 -0
- package/src/lib/assets/site-styles/store.webp +0 -0
- package/src/lib/assets/site-styles/studio.webp +0 -0
- package/src/lib/assets/site-styles/trades.webp +0 -0
- package/src/lib/assets/site-styles/wellness.webp +0 -0
- package/src/lib/assets/site-styles/yoga.webp +0 -0
- package/src/lib/site-import/site-import-review.d.ts +0 -40
- package/src/lib/site-import/site-import-review.js +0 -149
- package/src/lib/site-import/site-import-review.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/providers/routing.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 { AI_SETTING_PLATFORM, AI_STEP_MODEL_SETTING } from '../plugin-config'\nimport {\n AI_MODEL_CATALOG,\n AI_STEP_TIERS,\n aiCatalogEntry,\n aiDefaultModelFor,\n type AiStepKind,\n} from './catalog'\nimport type { AiEvalKind } from '../runtime/ai-eval'\nimport type { AiEffort, AiProvider, AiThinking } from './contract'\nimport { aiProviderById, defaultAiProvider } from './registry'\n\n/**\n * The routing table (AGL-2937, AGL-2939): step kind → provider and model,\n * through the catalog and never a vendor literal.\n *\n * Precedence, dearest override first:\n *\n * 1. the org's `pluginSettings/ai` — a provider, and a model per step kind\n * that must be one the provider serves;\n * 2. the deployment's environment — `AI_PROVIDER` for the provider,\n * `AI_DEFAULT_MODEL` for every step, and `ASSIST_MODEL` for the\n * assistant alone (the incident-response override the chat door has\n * always honored);\n * 3. the catalog's tier for the step kind on the resolved provider.\n */\n\n/** The environment override for every step kind. */\nexport const AI_DEFAULT_MODEL_ENV = 'AI_DEFAULT_MODEL'\n/** The assistant's own override, honored before the general one. */\nexport const ASSIST_MODEL_ENV = 'ASSIST_MODEL'\n\n/** The org's resolved `pluginSettings/ai` values, as `getPluginConfig` merges them. */\nexport type AiPluginSettings = Record<string, unknown>\n\n/**\n * The model that serves a catalog id (AGL-3781): the id itself, or for a\n * retired row the successor it names, followed to a current row. An id the\n * catalog does not know is returned as it is, for the caller to refuse.\n */\nexport function aiServingModelId(modelId: string): string {\n let current = modelId\n for (let hops = 0; hops < AI_MODEL_CATALOG.length; hops += 1) {\n const successor = aiCatalogEntry(current)?.successor\n if (!successor) return current\n current = successor\n }\n return current\n}\n\nexport interface AiRoute {\n provider: AiProvider\n model: string\n}\n\n/** A settings value that names a real choice, or `undefined` for the platform default. */\nfunction chosen(settings: AiPluginSettings | undefined, key: string): string | undefined {\n const value = settings?.[key]\n return typeof value === 'string' && value && value !== AI_SETTING_PLATFORM\n ? value\n : undefined\n}\n\n/** The provider a workspace runs on: its own choice when registered, else the platform's. */\nexport function resolveAiProvider(settings?: AiPluginSettings): AiProvider | undefined {\n const wanted = chosen(settings, 'provider')\n if (wanted) {\n const named = aiProviderById(wanted)\n if (named) return named\n }\n return defaultAiProvider()\n}\n\n/**\n * The model a step kind runs on for a workspace, on the resolved provider.\n * A chosen model on another provider is not served — the provider decides\n * what it can run — and falls back to the provider's default for the tier.\n */\nexport function resolveAiRoute(\n kind: AiStepKind,\n settings?: AiPluginSettings,\n): AiRoute | undefined {\n const provider = resolveAiProvider(settings)\n if (!provider) return undefined\n // A setting or an override that names a retired model is served by its\n // successor, never by the retired model itself.\n const servedBy = (modelId: string | undefined): string | undefined => {\n const serving = modelId ? aiServingModelId(modelId) : undefined\n return serving && aiCatalogEntry(serving)?.provider === provider.id ? serving : undefined\n }\n const model =\n servedBy(chosen(settings, AI_STEP_MODEL_SETTING[kind])) ??\n (kind === 'assist.chat' ? servedBy(process.env[ASSIST_MODEL_ENV]?.trim()) : undefined) ??\n servedBy(process.env[AI_DEFAULT_MODEL_ENV]?.trim()) ??\n aiDefaultModelFor(provider.id, AI_STEP_TIERS[kind])\n return model ? { provider, model } : undefined\n}\n\n/**\n * What one step kind asks of its model, beside the tier it is served from\n * (`AI_STEP_TIERS` in the catalog): whether it thinks and how hard, its\n * answer ceiling, and the eval score that tier holds on the step's golden\n * briefs (AGL-2937).\n */\nexport interface AiRoutingRow {\n /**\n * `null` sends no setting: the model's own default, which on every current\n * model is adaptive thinking. A row whose ceiling holds the answer alone\n * says `off` (AGL-3781).\n */\n thinking: AiThinking | null\n effort: AiEffort | null\n /** The answer ceiling, thinking included. */\n maxTokens: number\n /** What the ceiling is sized from. */\n maxTokensBasis: string\n eval: AiRoutingEval\n /**\n * How long the step's prompt cache lives (AGL-3830): `1h` on every step a\n * site job runs, in production as in a live run, and the provider's five\n * minutes on a row that leaves it out. A guided start's routes each write\n * their prefix once and read it only inside the job, a beat or more apart,\n * so a five-minute entry is gone before the next job could read it; at an\n * hour the next site job reads what the last one wrote. The write costs 2x\n * the input price instead of 1.25x, so a step no job runs leaves it out.\n * The hour is the SHARED markers' alone (AGL-4050): a site's block and the\n * plan's own conversation are read by one job only, so they keep five\n * minutes on every row (`aiCacheMarkerTtls` in `providers/contract.ts`).\n * Read by `runValidatedGeneration` into the request's `cacheTtl`; a door\n * that sends its own request on the same step (the copy assistant's blog\n * draft) keeps five minutes.\n */\n cacheTtl?: '1h'\n}\n\n/**\n * The cache lifetime every step a site job runs asks for its shared prompt\n * (AGL-3830, AGL-4050): the plan, the look, the header and footer, every page\n * and its listing, the creations, the first posts and products, and the\n * welcome email.\n */\nconst AI_SITE_JOB_CACHE_TTL = '1h' as const\n\nexport interface AiRoutingEval {\n /** The golden-brief kinds the step answers. */\n kinds: readonly AiEvalKind[]\n /** `answers` scores the step's answers; `plans` scores the plans those kinds' answers carry. */\n scores: 'answers' | 'plans'\n /** `authored` while the score is the hand-written references'; `recorded` once a live run records answers. */\n source: 'authored' | 'recorded'\n passRate: number\n /** The mean answer score; `null` for a plan score, which passes or fails. */\n meanScore: number | null\n}\n\n/**\n * THE ROUTING TABLE (AGL-2937): what each step kind asks of the model, in one\n * place, with the evidence beside it.\n *\n * A step runs on the smallest tier that holds its eval floor. A row moves to a\n * cheaper tier, or a lower effort, only when a recorded eval\n * (`npm run eval:ai-live`) holds the floor there; while a row's score is the\n * authored references', it says so, and the row stays where production has\n * run it. `runtime/ai-eval.spec.ts` recomputes every row's score from the\n * harness, so a row cannot claim a score its briefs do not hold.\n *\n * A ceiling is sized from the p95 output the staff signals page reports for\n * the kind once production has served it; until then `maxTokensBasis` names\n * what it is sized from. The same spec holds every reference answer under its\n * row's ceiling at three characters a token, a reading that errs high for a\n * tokenizer that splits finer than four.\n */\nexport const AI_ROUTING_TABLE: Readonly<Record<AiStepKind, AiRoutingRow>> = {\n 'assist.chat': {\n // A scoped, latency-sensitive chat turn: no thinking, the low effort rung.\n thinking: 'off',\n effort: 'low',\n // 2,048 since AGL-4075: a non-Latin script spends two to four times the\n // tokens per character, and 5 of 17 non-English answers stopped at 1,024\n // against 1 of 33 English ones. Output is billed only as it is written.\n maxTokens: 2048,\n maxTokensBasis:\n 'a docs-grounded answer of a few short paragraphs in any language; the edit rung raises it for its tool call',\n eval: { kinds: ['chat'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 0.9688 },\n },\n 'copy.element': {\n // One element's copy on the fast tier, whose model thinks unless told not\n // to (AGL-3781): the ceiling holds the copy alone, as it always has, and\n // the effort is the model's own.\n thinking: 'off',\n effort: null,\n maxTokens: 1024,\n maxTokensBasis: 'one element of copy, about the length of the text it replaces',\n eval: { kinds: ['element'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 0.9688 },\n },\n 'copy.section': {\n thinking: null,\n effort: null,\n maxTokens: 3000,\n maxTokensBasis: 'a section of four to twelve nodes written as JSON',\n eval: { kinds: ['section'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 0.9688 },\n },\n 'copy.blog': {\n thinking: null,\n effort: null,\n maxTokens: 2048,\n maxTokensBasis: 'one blog post body in markdown-lite',\n eval: { kinds: ['blog'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 0.9688 },\n cacheTtl: AI_SITE_JOB_CACHE_TTL,\n },\n 'generate.section': {\n thinking: null,\n effort: null,\n maxTokens: 3000,\n maxTokensBasis: 'a section of four to twelve nodes written as JSON',\n eval: { kinds: ['section'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 0.9688 },\n },\n 'job.layout': {\n // The plan was reasoned out and confirmed before the step, so it writes without thinking.\n // A site's header and footer in the layout language think adaptively, at\n // low since AGL-3781 (`AI_LAYOUT_LANGUAGE_THINKING`): the live round of\n // 2026-10-14 built 13 of 13 frames at low, none cut off.\n thinking: 'off',\n effort: null,\n maxTokens: 8000,\n maxTokensBasis:\n \"tighter than the doctrine's default for a layout, so one step and its re-ask fit the job beat's budget; the tree is held to its rule 17 budget either way\",\n eval: { kinds: ['layout'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 0.9833 },\n cacheTtl: AI_SITE_JOB_CACHE_TTL,\n },\n 'job.template': {\n // Medium since the golden A/B of 2026-10-14 (AGL-3781): both template\n // briefs passed at medium as at the default, with about a third fewer\n // output tokens.\n thinking: 'off',\n effort: 'medium',\n maxTokens: 8000,\n maxTokensBasis:\n \"tighter than the doctrine's default for a template, so one step and its re-ask fit the job beat's budget; the tree is held to its rule 17 budget either way\",\n eval: { kinds: ['template'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 0.9833 },\n cacheTtl: AI_SITE_JOB_CACHE_TTL,\n },\n 'job.component': {\n // A component's tree and the properties it declares, in one answer, from a\n // plan reasoned out and confirmed before the step (AGL-2908).\n thinking: 'off',\n effort: null,\n maxTokens: 8000,\n maxTokensBasis:\n \"the ceiling the layout and template steps keep, so one step and its re-ask fit the job beat's budget; the tree is held to its rule 17 budget either way\",\n eval: { kinds: ['component'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 0.9833 },\n cacheTtl: AI_SITE_JOB_CACHE_TTL,\n },\n 'job.crm': {\n // CRM by AI (AGL-2917): short answers through a strict tool, written from\n // the facts the CRM reports about the record the member opened, with no\n // thinking. The ceiling fits an inline door, so a member is answered in\n // the request that asked, and has no room for thinking: the fast tier's\n // model thinks unless told not to, so the row says off, and its effort\n // is the low one a short answer read off given facts needs (AGL-3781).\n thinking: 'off',\n effort: 'low',\n maxTokens: 700,\n maxTokensBasis:\n \"the largest answer a CRM tool accepts: sixty columns matched to fields by number, or an email draft at its length limits, at three characters a token with room, as ai-job-crm-step.spec.ts measures it\",\n eval: { kinds: ['crm'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 0.9938 },\n },\n 'job.experiment': {\n // Variants of one piece of copy, or a result explained against a verdict\n // code reached before the request was made (AGL-2914). The judgment is\n // already made either way, so it writes without thinking.\n thinking: 'off',\n effort: null,\n maxTokens: 1500,\n maxTokensBasis:\n \"four variants at the tool's own lengths — a name, a headline, a body and a rationale each — written as JSON, about 3,000 characters at three characters a token with room; an explanation is a headline, four sentences and a next step, well under it, as ai-job-experiment-step.spec.ts measures both\",\n eval: { kinds: ['experiment'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 1 },\n },\n 'job.form': {\n // A form's two halves in one answer: the field declaration and the design\n // that renders it, as JSON, with no extended thinking (AGL-2913). The step\n // asks this ceiling, which is the doctrine's own for a form, and registers\n // the time it takes (AGL-3035).\n thinking: 'off',\n effort: null,\n maxTokens: 6000,\n maxTokensBasis:\n \"the largest form the doctrine's output budget admits, a form's fields, its consent and routing declaration and the design that renders them written as JSON at the wordiest golden's characters a stored byte, under it with room; ai-job-form-step.spec.ts measures it\",\n eval: { kinds: ['form'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 0.9833 },\n cacheTtl: AI_SITE_JOB_CACHE_TTL,\n },\n 'job.insight': {\n // Readers chosen, then their tables phrased (AGL-2915): short sentences\n // over figures code computed, each held to the rows it cites, so no\n // extended thinking. The read call before the answer asks for at most\n // `AI_INSIGHT_READ_MAX_TOKENS` of the same allowance.\n thinking: 'off',\n effort: null,\n maxTokens: 1500,\n maxTokensBasis:\n 'five insights at their 280-character bound, each citing three tables of ten rows, and the gap sentence, written as JSON: about 2,700 characters, under 1,000 tokens at three characters a token, with room',\n eval: { kinds: ['insight'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 0.9688 },\n },\n 'job.page': {\n // One section of a page, written against a plan a member already\n // confirmed, so it writes without thinking (AGL-2907). The ceiling here\n // is the MOST a pass may ask for; each pass sizes its own down from it to\n // what fits the time the job beat can give the step, which on the\n // balanced tier is about half of this. A page in the layout language\n // thinks adaptively, at low since AGL-3781 (`AI_LAYOUT_LANGUAGE_THINKING`):\n // the live round of 2026-10-14 built 39 of 39 pages at low, 64 of 65\n // answers held their rules on the first ask, none cut off.\n thinking: 'off',\n effort: null,\n maxTokens: 2000,\n maxTokensBasis:\n \"a section of a page written as JSON, about forty elements at the step's measured 45 tokens an element; a pass lowers it to the worst case that fits AI_JOB_PAGE_STEP_MINIMUM_MS on the model it runs\",\n eval: { kinds: ['page'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 0.9833 },\n cacheTtl: AI_SITE_JOB_CACHE_TTL,\n },\n 'job.products': {\n // A product's copy from its name, text and photo, or a store's first\n // products, categories and discounts from a brief (AGL-2916): answers held\n // to the storefront claim rules, written with no extended thinking.\n thinking: 'off',\n effort: null,\n maxTokens: 8000,\n maxTokensBasis:\n \"the largest catalog the tool accepts, twelve proposed products at every bound written as JSON, which the balanced tier asks as much of as fits a beat; one product's copy asks 1,500 and categories with discounts 2,000, as ai-job-products-step.spec.ts measures them\",\n eval: {\n kinds: ['product', 'catalog', 'categories'],\n scores: 'answers',\n source: 'authored',\n passRate: 1,\n meanScore: 0.9922,\n },\n cacheTtl: AI_SITE_JOB_CACHE_TTL,\n },\n 'job.email': {\n // One email design from the email palette, written against the brief with\n // no extended thinking (AGL-2912). A campaign job runs the same\n // generation, so it carries the same ceiling.\n thinking: 'off',\n effort: null,\n maxTokens: 6000,\n maxTokensBasis:\n \"an email's node map written as JSON, with three subject lines and three preheaders beside it\",\n eval: { kinds: ['email'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 0.9688 },\n cacheTtl: AI_SITE_JOB_CACHE_TTL,\n },\n 'job.campaign': {\n // The campaign job generates its email through the email step, so it is\n // routed identically; the draft campaign it also writes asks nothing of\n // the model (AGL-2912).\n thinking: 'off',\n effort: null,\n maxTokens: 6000,\n maxTokensBasis:\n \"an email's node map written as JSON, with three subject lines and three preheaders beside it\",\n eval: { kinds: ['email'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 0.9688 },\n },\n 'job.workflow': {\n // An automation drafted from a description, or one explained (AGL-2919):\n // which trigger and which steps a description means is the judgment the\n // step sells, so it thinks before it answers.\n thinking: 'adaptive',\n effort: null,\n maxTokens: 4000,\n maxTokensBasis:\n 'the largest automation the tool accepts, 6,000 characters written out as JSON, at three characters a token with as much again to think in, as ai-job-workflow-step.spec.ts measures it',\n eval: { kinds: ['workflow'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 0.9688 },\n },\n 'job.logic': {\n // A site function or variable proposed, or a function explained\n // (AGL-3603): which conditions and arithmetic a description means is the\n // judgment the step sells, so it thinks before it answers.\n thinking: 'adaptive',\n effort: null,\n maxTokens: 3000,\n maxTokensBasis:\n 'the largest function the tool accepts — twelve parameters, twenty-four operations — is far past any description; a function of eight operations is about 2,400 characters of JSON, at three characters a token with as much again to think in, as ai-job-logic-step.spec.ts measures it',\n eval: { kinds: ['logic'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 1 },\n },\n 'job.edit': {\n // A change to a page or a layout the site has (AGL-3616): which elements\n // a request means, on an outline with no selection, is the judgment the\n // step sells, so it thinks before it answers.\n thinking: 'adaptive',\n effort: null,\n maxTokens: 6144,\n maxTokensBasis:\n \"the Assist edit rung's own ceiling for the proposal's tool call (ASSIST_EDIT_MAX_OUTPUT_TOKENS, 4,096: forty new elements written as name/value pairs), with half as much again to think in, as ai-job-edit-step.spec.ts holds it; the whole of it twice, as a re-ask may, still fits one beat on the balanced tier\",\n eval: { kinds: ['edit'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 1 },\n },\n 'job.seo': {\n // A listing written from the page's own text to fixed lengths, sized for\n // the answer alone: no thinking, which the fast tier's model does unless\n // told not to, at the low effort a short bounded answer needs (AGL-3781).\n // The audit's site proposal and fix batches run on the same row.\n thinking: 'off',\n effort: 'low',\n maxTokens: 1024,\n maxTokensBasis:\n \"the largest listing the tool accepts, at three characters a token with a quarter again, as ai-job-seo-step.spec.ts measures it; an audit's site proposal and fix batches keep ceilings of their own, measured the same way\",\n eval: { kinds: ['seo'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 1 },\n cacheTtl: AI_SITE_JOB_CACHE_TTL,\n },\n 'job.text': {\n // Low since the golden A/B of 2026-10-14 (AGL-3781): the tagline brief\n // passed at low, its copy scored higher than at the default.\n thinking: 'adaptive',\n effort: 'low',\n maxTokens: 1024,\n maxTokensBasis: 'a few paragraphs of copy; a brief asking for more gets a draft to extend',\n eval: { kinds: ['text'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 1 },\n },\n 'job.theme': {\n // Medium since the golden A/B of 2026-10-14 (AGL-3781): the theme brief\n // passed at medium with the default's scores and half its output tokens.\n // A site start's look runs its own setting (`ai-job-site-look.ts`).\n thinking: 'adaptive',\n effort: 'medium',\n maxTokens: 8000,\n maxTokensBasis:\n 'the largest answer the theme tool accepts, about 2,500 tokens of JSON as ai-job-theme-step.spec.ts measures it, with as much again to think in',\n eval: { kinds: ['theme'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 0.9688 },\n cacheTtl: AI_SITE_JOB_CACHE_TTL,\n },\n 'job.plan': {\n // A site's plan is an outline written without thinking (AGL-3594), and a\n // paid site's asks medium (`AI_PAID_SITE_PLAN_EFFORT`, AGL-3781): the live\n // round of 2026-10-14 planned 11 of 11 paid site briefs at medium in 16\n // attempts to the default's 22, $0.129 to $0.164, with no refusal and no\n // rule broken. Every other plan, and a Free site's on the fast tier, asks\n // this row's effort — the model's default — until a round holds it lower.\n thinking: 'adaptive',\n effort: null,\n maxTokens: 8000,\n maxTokensBasis: 'a plan of up to twelve screens with sixteen sections each, with room to think',\n eval: {\n kinds: ['page', 'template', 'component', 'layout', 'form'],\n scores: 'plans',\n source: 'authored',\n passRate: 1,\n meanScore: null,\n },\n cacheTtl: AI_SITE_JOB_CACHE_TTL,\n },\n}\n\n/**\n * What a step kind's row asks of its model, as the fields a request carries:\n * only those the row names, so a row that names none sends none and the\n * model's own default stands.\n */\nexport function aiRouteSettings(kind: AiStepKind): { thinking?: AiThinking; effort?: AiEffort } {\n const row = AI_ROUTING_TABLE[kind]\n return {\n ...(row.thinking ? { thinking: row.thinking } : {}),\n ...(row.effort ? { effort: row.effort } : {}),\n }\n}\n\n/** The model id alone — what a door records on the meter and the job. */\nexport function aiModelForStep(kind: AiStepKind, settings?: AiPluginSettings): string {\n const route = resolveAiRoute(kind, settings)\n if (!route) {\n // Every door gates on the provider being configured before it asks\n // for a model, so this is a wiring fault rather than a customer path.\n throw new Error('no AI provider is registered')\n }\n return route.model\n}\n"],"names":["AI_SETTING_PLATFORM","AI_STEP_MODEL_SETTING","AI_MODEL_CATALOG","AI_STEP_TIERS","aiCatalogEntry","aiDefaultModelFor","aiProviderById","defaultAiProvider","AI_DEFAULT_MODEL_ENV","ASSIST_MODEL_ENV","aiServingModelId","modelId","current","hops","length","successor","chosen","settings","key","value","undefined","resolveAiProvider","wanted","named","resolveAiRoute","kind","servedBy","process","provider","serving","id","model","env","trim","AI_SITE_JOB_CACHE_TTL","AI_ROUTING_TABLE","thinking","effort","maxTokens","maxTokensBasis","eval","kinds","scores","source","passRate","meanScore","cacheTtl","aiRouteSettings","row","aiModelForStep","route","Error"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/providers/routing.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 { AI_SETTING_PLATFORM, AI_STEP_MODEL_SETTING } from '../plugin-config'\nimport {\n AI_MODEL_CATALOG,\n AI_STEP_TIERS,\n aiCatalogEntry,\n aiDefaultModelFor,\n type AiCatalogEntry,\n type AiStepKind,\n} from './catalog'\nimport type { AiEvalKind } from '../runtime/ai-eval'\nimport type { AiEffort, AiProvider, AiThinking } from './contract'\nimport { aiProviderById, defaultAiProvider } from './registry'\n\n/**\n * The routing table (AGL-2937, AGL-2939): step kind → provider and model,\n * through the catalog and never a vendor literal.\n *\n * Precedence, dearest override first:\n *\n * 1. the org's `pluginSettings/ai` — a provider, and a model per step kind\n * that must be one the provider serves;\n * 2. the deployment's environment — `AI_PROVIDER` for the provider,\n * `AI_DEFAULT_MODEL` for every step, and `ASSIST_MODEL` for the\n * assistant alone (the incident-response override the chat door has\n * always honored);\n * 3. the catalog's tier for the step kind on the resolved provider.\n */\n\n/** The environment override for every step kind. */\nexport const AI_DEFAULT_MODEL_ENV = 'AI_DEFAULT_MODEL'\n/** The assistant's own override, honored before the general one. */\nexport const ASSIST_MODEL_ENV = 'ASSIST_MODEL'\n\n/** The org's resolved `pluginSettings/ai` values, as `getPluginConfig` merges them. */\nexport type AiPluginSettings = Record<string, unknown>\n\n/**\n * The model that serves a catalog id (AGL-3781): the id itself, or for a\n * retired row the successor it names, followed to a current row. An id the\n * catalog does not know is returned as it is, for the caller to refuse.\n */\nexport function aiServingModelId(modelId: string): string {\n let current = modelId\n for (let hops = 0; hops < AI_MODEL_CATALOG.length; hops += 1) {\n const successor = aiCatalogEntry(current)?.successor\n if (!successor) return current\n current = successor\n }\n return current\n}\n\nexport interface AiRoute {\n provider: AiProvider\n model: string\n}\n\n/** A settings value that names a real choice, or `undefined` for the platform default. */\nfunction chosen(settings: AiPluginSettings | undefined, key: string): string | undefined {\n const value = settings?.[key]\n return typeof value === 'string' && value && value !== AI_SETTING_PLATFORM\n ? value\n : undefined\n}\n\n/** The provider a workspace runs on: its own choice when registered, else the platform's. */\nexport function resolveAiProvider(settings?: AiPluginSettings): AiProvider | undefined {\n const wanted = chosen(settings, 'provider')\n if (wanted) {\n const named = aiProviderById(wanted)\n if (named) return named\n }\n return defaultAiProvider()\n}\n\n/**\n * The model a step kind runs on for a workspace, on the resolved provider.\n * A chosen model on another provider is not served — the provider decides\n * what it can run — and falls back to the provider's default for the tier.\n */\nexport function resolveAiRoute(\n kind: AiStepKind,\n settings?: AiPluginSettings,\n): AiRoute | undefined {\n const provider = resolveAiProvider(settings)\n if (!provider) return undefined\n // A setting or an override that names a retired model is served by its\n // successor, never by the retired model itself.\n const servedBy = (modelId: string | undefined): string | undefined => {\n const serving = modelId ? aiServingModelId(modelId) : undefined\n return serving && aiCatalogEntry(serving)?.provider === provider.id ? serving : undefined\n }\n const model =\n servedBy(chosen(settings, AI_STEP_MODEL_SETTING[kind])) ??\n (kind === 'assist.chat' ? servedBy(process.env[ASSIST_MODEL_ENV]?.trim()) : undefined) ??\n servedBy(process.env[AI_DEFAULT_MODEL_ENV]?.trim()) ??\n aiDefaultModelFor(provider.id, AI_STEP_TIERS[kind])\n return model ? { provider, model } : undefined\n}\n\n/**\n * What one step kind asks of its model, beside the tier it is served from\n * (`AI_STEP_TIERS` in the catalog): whether it thinks and how hard, its\n * answer ceiling, and the eval score that tier holds on the step's golden\n * briefs (AGL-2937).\n */\nexport interface AiRoutingRow {\n /**\n * `null` sends no setting: the model's own default, which on every current\n * model is adaptive thinking. A row whose ceiling holds the answer alone\n * says `off` (AGL-3781).\n */\n thinking: AiThinking | null\n effort: AiEffort | null\n /** The answer ceiling, thinking included. */\n maxTokens: number\n /** What the ceiling is sized from. */\n maxTokensBasis: string\n eval: AiRoutingEval\n /**\n * How long the step's prompt cache lives (AGL-3830): `1h` on every step a\n * site job runs, in production as in a live run, and the provider's five\n * minutes on a row that leaves it out. A guided start's routes each write\n * their prefix once and read it only inside the job, a beat or more apart,\n * so a five-minute entry is gone before the next job could read it; at an\n * hour the next site job reads what the last one wrote. The write costs 2x\n * the input price instead of 1.25x, so a step no job runs leaves it out.\n * The hour is the SHARED markers' alone (AGL-4050): a site's block and the\n * plan's own conversation are read by one job only, so they keep five\n * minutes on every row (`aiCacheMarkerTtls` in `providers/contract.ts`).\n * Read by `runValidatedGeneration` into the request's `cacheTtl`; a door\n * that sends its own request on the same step (the copy assistant's blog\n * draft) keeps five minutes.\n */\n cacheTtl?: '1h'\n}\n\n/**\n * The cache lifetime every step a site job runs asks for its shared prompt\n * (AGL-3830, AGL-4050): the plan, the look, the header and footer, every page\n * and its listing, the creations, the first posts and products, and the\n * welcome email.\n */\nconst AI_SITE_JOB_CACHE_TTL = '1h' as const\n\nexport interface AiRoutingEval {\n /** The golden-brief kinds the step answers. */\n kinds: readonly AiEvalKind[]\n /** `answers` scores the step's answers; `plans` scores the plans those kinds' answers carry. */\n scores: 'answers' | 'plans'\n /** `authored` while the score is the hand-written references'; `recorded` once a live run records answers. */\n source: 'authored' | 'recorded'\n passRate: number\n /** The mean answer score; `null` for a plan score, which passes or fails. */\n meanScore: number | null\n}\n\n/**\n * THE ROUTING TABLE (AGL-2937): what each step kind asks of the model, in one\n * place, with the evidence beside it.\n *\n * A step runs on the smallest tier that holds its eval floor. A row moves to a\n * cheaper tier, or a lower effort, only when a recorded eval\n * (`npm run eval:ai-live`) holds the floor there; while a row's score is the\n * authored references', it says so, and the row stays where production has\n * run it. `runtime/ai-eval.spec.ts` recomputes every row's score from the\n * harness, so a row cannot claim a score its briefs do not hold.\n *\n * A ceiling is sized from the p95 output the staff signals page reports for\n * the kind once production has served it; until then `maxTokensBasis` names\n * what it is sized from. The same spec holds every reference answer under its\n * row's ceiling at three characters a token, a reading that errs high for a\n * tokenizer that splits finer than four.\n */\nexport const AI_ROUTING_TABLE: Readonly<Record<AiStepKind, AiRoutingRow>> = {\n 'assist.chat': {\n // A scoped, latency-sensitive chat turn: no thinking, the low effort rung.\n thinking: 'off',\n effort: 'low',\n // 2,048 since AGL-4075: a non-Latin script spends two to four times the\n // tokens per character, and 5 of 17 non-English answers stopped at 1,024\n // against 1 of 33 English ones. Output is billed only as it is written.\n maxTokens: 2048,\n maxTokensBasis:\n 'a docs-grounded answer of a few short paragraphs in any language; the edit rung raises it for its tool call',\n eval: { kinds: ['chat'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 0.9688 },\n },\n 'copy.element': {\n // One element's copy on the fast tier, whose model thinks unless told not\n // to (AGL-3781): the ceiling holds the copy alone, as it always has, and\n // the effort is the model's own.\n thinking: 'off',\n effort: null,\n maxTokens: 1024,\n maxTokensBasis: 'one element of copy, about the length of the text it replaces',\n eval: { kinds: ['element'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 0.9688 },\n },\n 'copy.section': {\n thinking: null,\n effort: null,\n maxTokens: 3000,\n maxTokensBasis: 'a section of four to twelve nodes written as JSON',\n eval: { kinds: ['section'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 0.9688 },\n },\n 'copy.blog': {\n thinking: null,\n effort: null,\n maxTokens: 2048,\n maxTokensBasis: 'one blog post body in markdown-lite',\n eval: { kinds: ['blog'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 0.9688 },\n cacheTtl: AI_SITE_JOB_CACHE_TTL,\n },\n 'generate.section': {\n thinking: null,\n effort: null,\n maxTokens: 3000,\n maxTokensBasis: 'a section of four to twelve nodes written as JSON',\n eval: { kinds: ['section'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 0.9688 },\n },\n 'job.layout': {\n // The plan was reasoned out and confirmed before the step, so it writes without thinking.\n // A site's header and footer in the layout language think adaptively, at\n // low since AGL-3781 (`AI_LAYOUT_LANGUAGE_THINKING`): the live round of\n // 2026-10-14 built 13 of 13 frames at low, none cut off.\n thinking: 'off',\n effort: null,\n maxTokens: 8000,\n maxTokensBasis:\n \"tighter than the doctrine's default for a layout, so one step and its re-ask fit the job beat's budget; the tree is held to its rule 17 budget either way\",\n eval: { kinds: ['layout'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 0.9833 },\n cacheTtl: AI_SITE_JOB_CACHE_TTL,\n },\n 'job.template': {\n // Medium since the golden A/B of 2026-10-14 (AGL-3781): both template\n // briefs passed at medium as at the default, with about a third fewer\n // output tokens.\n thinking: 'off',\n effort: 'medium',\n maxTokens: 8000,\n maxTokensBasis:\n \"tighter than the doctrine's default for a template, so one step and its re-ask fit the job beat's budget; the tree is held to its rule 17 budget either way\",\n eval: { kinds: ['template'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 0.9833 },\n cacheTtl: AI_SITE_JOB_CACHE_TTL,\n },\n 'job.component': {\n // A component's tree and the properties it declares, in one answer, from a\n // plan reasoned out and confirmed before the step (AGL-2908).\n thinking: 'off',\n effort: null,\n maxTokens: 8000,\n maxTokensBasis:\n \"the ceiling the layout and template steps keep, so one step and its re-ask fit the job beat's budget; the tree is held to its rule 17 budget either way\",\n eval: { kinds: ['component'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 0.9833 },\n cacheTtl: AI_SITE_JOB_CACHE_TTL,\n },\n 'job.crm': {\n // CRM by AI (AGL-2917): short answers through a strict tool, written from\n // the facts the CRM reports about the record the member opened, with no\n // thinking. The ceiling fits an inline door, so a member is answered in\n // the request that asked, and has no room for thinking: the fast tier's\n // model thinks unless told not to, so the row says off, and its effort\n // is the low one a short answer read off given facts needs (AGL-3781).\n thinking: 'off',\n effort: 'low',\n maxTokens: 700,\n maxTokensBasis:\n \"the largest answer a CRM tool accepts: sixty columns matched to fields by number, or an email draft at its length limits, at three characters a token with room, as ai-job-crm-step.spec.ts measures it\",\n eval: { kinds: ['crm'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 0.9938 },\n },\n 'job.experiment': {\n // Variants of one piece of copy, or a result explained against a verdict\n // code reached before the request was made (AGL-2914). The judgment is\n // already made either way, so it writes without thinking.\n thinking: 'off',\n effort: null,\n maxTokens: 1500,\n maxTokensBasis:\n \"four variants at the tool's own lengths — a name, a headline, a body and a rationale each — written as JSON, about 3,000 characters at three characters a token with room; an explanation is a headline, four sentences and a next step, well under it, as ai-job-experiment-step.spec.ts measures both\",\n eval: { kinds: ['experiment'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 1 },\n },\n 'job.form': {\n // A form's two halves in one answer: the field declaration and the design\n // that renders it, as JSON, with no extended thinking (AGL-2913). The step\n // asks this ceiling, which is the doctrine's own for a form, and registers\n // the time it takes (AGL-3035).\n thinking: 'off',\n effort: null,\n maxTokens: 6000,\n maxTokensBasis:\n \"the largest form the doctrine's output budget admits, a form's fields, its consent and routing declaration and the design that renders them written as JSON at the wordiest golden's characters a stored byte, under it with room; ai-job-form-step.spec.ts measures it\",\n eval: { kinds: ['form'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 0.9833 },\n cacheTtl: AI_SITE_JOB_CACHE_TTL,\n },\n 'job.insight': {\n // Readers chosen, then their tables phrased (AGL-2915): short sentences\n // over figures code computed, each held to the rows it cites, so no\n // extended thinking. The read call before the answer asks for at most\n // `AI_INSIGHT_READ_MAX_TOKENS` of the same allowance.\n thinking: 'off',\n effort: null,\n maxTokens: 1500,\n maxTokensBasis:\n 'five insights at their 280-character bound, each citing three tables of ten rows, and the gap sentence, written as JSON: about 2,700 characters, under 1,000 tokens at three characters a token, with room',\n eval: { kinds: ['insight'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 0.9688 },\n },\n 'job.page': {\n // One section of a page, written against a plan a member already\n // confirmed, so it writes without thinking (AGL-2907). The ceiling here\n // is the MOST a pass may ask for; each pass sizes its own down from it to\n // what fits the time the job beat can give the step, which on the\n // balanced tier is about half of this. A page in the layout language\n // thinks adaptively, at low since AGL-3781 (`AI_LAYOUT_LANGUAGE_THINKING`):\n // the live round of 2026-10-14 built 39 of 39 pages at low, 64 of 65\n // answers held their rules on the first ask, none cut off.\n thinking: 'off',\n effort: null,\n maxTokens: 2000,\n maxTokensBasis:\n \"a section of a page written as JSON, about forty elements at the step's measured 45 tokens an element; a pass lowers it to the worst case that fits AI_JOB_PAGE_STEP_MINIMUM_MS on the model it runs\",\n eval: { kinds: ['page'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 0.9833 },\n cacheTtl: AI_SITE_JOB_CACHE_TTL,\n },\n 'job.products': {\n // A product's copy from its name, text and photo, or a store's first\n // products, categories and discounts from a brief (AGL-2916): answers held\n // to the storefront claim rules, written with no extended thinking.\n thinking: 'off',\n effort: null,\n maxTokens: 8000,\n maxTokensBasis:\n \"the largest catalog the tool accepts, twelve proposed products at every bound written as JSON, which the balanced tier asks as much of as fits a beat; one product's copy asks 1,500 and categories with discounts 2,000, as ai-job-products-step.spec.ts measures them\",\n eval: {\n kinds: ['product', 'catalog', 'categories'],\n scores: 'answers',\n source: 'authored',\n passRate: 1,\n meanScore: 0.9922,\n },\n cacheTtl: AI_SITE_JOB_CACHE_TTL,\n },\n 'job.email': {\n // One email design from the email palette, written against the brief with\n // no extended thinking (AGL-2912). A campaign job runs the same\n // generation, so it carries the same ceiling.\n thinking: 'off',\n effort: null,\n maxTokens: 6000,\n maxTokensBasis:\n \"an email's node map written as JSON, with three subject lines and three preheaders beside it\",\n eval: { kinds: ['email'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 0.9688 },\n cacheTtl: AI_SITE_JOB_CACHE_TTL,\n },\n 'job.campaign': {\n // The campaign job generates its email through the email step, so it is\n // routed identically; the draft campaign it also writes asks nothing of\n // the model (AGL-2912).\n thinking: 'off',\n effort: null,\n maxTokens: 6000,\n maxTokensBasis:\n \"an email's node map written as JSON, with three subject lines and three preheaders beside it\",\n eval: { kinds: ['email'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 0.9688 },\n },\n 'job.workflow': {\n // An automation drafted from a description, or one explained (AGL-2919):\n // which trigger and which steps a description means is the judgment the\n // step sells, so it thinks before it answers.\n thinking: 'adaptive',\n effort: null,\n maxTokens: 4000,\n maxTokensBasis:\n 'the largest automation the tool accepts, 6,000 characters written out as JSON, at three characters a token with as much again to think in, as ai-job-workflow-step.spec.ts measures it',\n eval: { kinds: ['workflow'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 0.9688 },\n },\n 'job.logic': {\n // A site function or variable proposed, or a function explained\n // (AGL-3603): which conditions and arithmetic a description means is the\n // judgment the step sells, so it thinks before it answers.\n thinking: 'adaptive',\n effort: null,\n maxTokens: 3000,\n maxTokensBasis:\n 'the largest function the tool accepts — twelve parameters, twenty-four operations — is far past any description; a function of eight operations is about 2,400 characters of JSON, at three characters a token with as much again to think in, as ai-job-logic-step.spec.ts measures it',\n eval: { kinds: ['logic'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 1 },\n },\n 'job.edit': {\n // A change to a page or a layout the site has (AGL-3616): which elements\n // a request means, on an outline with no selection, is the judgment the\n // step sells, so it thinks before it answers.\n thinking: 'adaptive',\n effort: null,\n maxTokens: 6144,\n maxTokensBasis:\n \"the Assist edit rung's own ceiling for the proposal's tool call (ASSIST_EDIT_MAX_OUTPUT_TOKENS, 4,096: forty new elements written as name/value pairs), with half as much again to think in, as ai-job-edit-step.spec.ts holds it; the whole of it twice, as a re-ask may, still fits one beat on the balanced tier\",\n eval: { kinds: ['edit'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 1 },\n },\n 'job.seo': {\n // A listing written from the page's own text to fixed lengths, sized for\n // the answer alone: no thinking, which the fast tier's model does unless\n // told not to, at the low effort a short bounded answer needs (AGL-3781).\n // The audit's site proposal and fix batches run on the same row.\n thinking: 'off',\n effort: 'low',\n maxTokens: 1024,\n maxTokensBasis:\n \"the largest listing the tool accepts, at three characters a token with a quarter again, as ai-job-seo-step.spec.ts measures it; an audit's site proposal and fix batches keep ceilings of their own, measured the same way\",\n eval: { kinds: ['seo'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 1 },\n cacheTtl: AI_SITE_JOB_CACHE_TTL,\n },\n 'job.text': {\n // Low since the golden A/B of 2026-10-14 (AGL-3781): the tagline brief\n // passed at low, its copy scored higher than at the default.\n thinking: 'adaptive',\n effort: 'low',\n maxTokens: 1024,\n maxTokensBasis: 'a few paragraphs of copy; a brief asking for more gets a draft to extend',\n eval: { kinds: ['text'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 1 },\n },\n 'job.theme': {\n // Medium since the golden A/B of 2026-10-14 (AGL-3781): the theme brief\n // passed at medium with the default's scores and half its output tokens.\n // A site start's look runs its own setting (`ai-job-site-look.ts`).\n thinking: 'adaptive',\n effort: 'medium',\n maxTokens: 8000,\n maxTokensBasis:\n 'the largest answer the theme tool accepts, about 2,500 tokens of JSON as ai-job-theme-step.spec.ts measures it, with as much again to think in',\n eval: { kinds: ['theme'], scores: 'answers', source: 'authored', passRate: 1, meanScore: 0.9688 },\n cacheTtl: AI_SITE_JOB_CACHE_TTL,\n },\n 'job.plan': {\n // A site's plan is an outline written without thinking (AGL-3594), and a\n // paid site's asks medium (`AI_PAID_SITE_PLAN_EFFORT`, AGL-3781): the live\n // round of 2026-10-14 planned 11 of 11 paid site briefs at medium in 16\n // attempts to the default's 22, $0.129 to $0.164, with no refusal and no\n // rule broken. Every other plan, and a Free site's on the fast tier, asks\n // this row's effort — the model's default — until a round holds it lower.\n thinking: 'adaptive',\n effort: null,\n maxTokens: 8000,\n maxTokensBasis: 'a plan of up to twelve screens with sixteen sections each, with room to think',\n eval: {\n kinds: ['page', 'template', 'component', 'layout', 'form'],\n scores: 'plans',\n source: 'authored',\n passRate: 1,\n meanScore: null,\n },\n cacheTtl: AI_SITE_JOB_CACHE_TTL,\n },\n}\n\n/**\n * What a step kind's row asks of its model, as the fields a request carries:\n * only those the row names, so a row that names none sends none and the\n * model's own default stands.\n */\nexport function aiRouteSettings(kind: AiStepKind): { thinking?: AiThinking; effort?: AiEffort } {\n const row = AI_ROUTING_TABLE[kind]\n return {\n ...(row.thinking ? { thinking: row.thinking } : {}),\n ...(row.effort ? { effort: row.effort } : {}),\n }\n}\n\nconst TIER_RANK: Readonly<Record<AiCatalogEntry['tier'], number>> = { fast: 0, balanced: 1, deep: 2 }\n\n/**\n * The model a step runs on held to at least the step's own tier (AGL-4107):\n * `chosen`, the model the job's switch picked, where it serves the step's\n * tier or a higher one; else the provider's own model of that tier. The\n * deployment's `AI_DEFAULT_MODEL` names a model for EVERY step, so a smaller\n * one named there served the balanced step a page brought in asks its design\n * of, and laid the 10/29 import out wrong. A step this holds keeps its tier\n * whatever the environment says; one the catalog does not know is the\n * provider's own model of the tier.\n */\nexport function aiModelAtLeastStepTier(kind: AiStepKind, chosen: string | undefined, settings?: AiPluginSettings): string {\n const tier = AI_STEP_TIERS[kind]\n const provider = resolveAiProvider(settings)\n const serving = chosen ? aiCatalogEntry(aiServingModelId(chosen)) : undefined\n if (serving && (!provider || serving.provider === provider.id) && TIER_RANK[serving.tier] >= TIER_RANK[tier]) return serving.id\n const floor = provider ? aiDefaultModelFor(provider.id, tier) : undefined\n return floor ?? chosen ?? aiModelForStep(kind, settings)\n}\n\n/** The model id alone — what a door records on the meter and the job. */\nexport function aiModelForStep(kind: AiStepKind, settings?: AiPluginSettings): string {\n const route = resolveAiRoute(kind, settings)\n if (!route) {\n // Every door gates on the provider being configured before it asks\n // for a model, so this is a wiring fault rather than a customer path.\n throw new Error('no AI provider is registered')\n }\n return route.model\n}\n"],"names":["AI_SETTING_PLATFORM","AI_STEP_MODEL_SETTING","AI_MODEL_CATALOG","AI_STEP_TIERS","aiCatalogEntry","aiDefaultModelFor","aiProviderById","defaultAiProvider","AI_DEFAULT_MODEL_ENV","ASSIST_MODEL_ENV","aiServingModelId","modelId","current","hops","length","successor","chosen","settings","key","value","undefined","resolveAiProvider","wanted","named","resolveAiRoute","kind","servedBy","process","provider","serving","id","model","env","trim","AI_SITE_JOB_CACHE_TTL","AI_ROUTING_TABLE","thinking","effort","maxTokens","maxTokensBasis","eval","kinds","scores","source","passRate","meanScore","cacheTtl","aiRouteSettings","row","TIER_RANK","fast","balanced","deep","aiModelAtLeastStepTier","floor","tier","aiModelForStep","route","Error"],"mappings":"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"}
|
|
@@ -129,7 +129,9 @@ export interface AiDoctrineTreeContext extends AiNodeTreeContext {
|
|
|
129
129
|
* The page is its owner's own words, brought in from their website word for
|
|
130
130
|
* word (AGL-4084). Rule 8 does not ask for a dataset for its lists, which
|
|
131
131
|
* are the source's, and rule 14's copy checks (filler, placeholders,
|
|
132
|
-
* unfinished lines) judge copy a generator wrote, never the owner's.
|
|
132
|
+
* unfinished lines) judge copy a generator wrote, never the owner's. Nor
|
|
133
|
+
* does rule 1 ask a component of its repeats (AGL-4107): its cards, steps
|
|
134
|
+
* and questions are the source's, laid out as the source lays them out.
|
|
133
135
|
*/
|
|
134
136
|
ownWords?: boolean;
|
|
135
137
|
/**
|
|
@@ -204,7 +206,7 @@ export declare const AI_TYPED_LIST_MIN_ITEMS = 8;
|
|
|
204
206
|
* A workspace that keeps no reusable components can place no instance, so
|
|
205
207
|
* there a repeated block is drawn where it repeats, and nothing is refused.
|
|
206
208
|
*/
|
|
207
|
-
export declare function detectRepeatedSubtrees(tree: AiDoctrineTree, otherPages?: readonly AiDoctrineTree[], context?: Pick<AiDoctrineTreeContext, 'reusableComponents' | 'repeatsCompiled'>): AiDoctrineViolation[];
|
|
209
|
+
export declare function detectRepeatedSubtrees(tree: AiDoctrineTree, otherPages?: readonly AiDoctrineTree[], context?: Pick<AiDoctrineTreeContext, 'reusableComponents' | 'repeatsCompiled' | 'ownWords'>): AiDoctrineViolation[];
|
|
208
210
|
/**
|
|
209
211
|
* How many copies of one repeated thing a document shows, read as
|
|
210
212
|
* generously as the tree allows (AGL-3024): the largest group of nodes the
|
|
@@ -280,6 +280,10 @@ function listNames(ids, tree) {
|
|
|
280
280
|
* there a repeated block is drawn where it repeats, and nothing is refused.
|
|
281
281
|
*/ export function detectRepeatedSubtrees(tree, otherPages = [], context = {}) {
|
|
282
282
|
if (context.reusableComponents === false) return [];
|
|
283
|
+
// A page brought in repeats what its source repeats (AGL-4107): its cards,
|
|
284
|
+
// its steps and its questions are the source's own, drawn by the compiler,
|
|
285
|
+
// and an import has no component of the source's to place them as.
|
|
286
|
+
if (context.ownWords) return [];
|
|
283
287
|
const index = indexShapes(tree);
|
|
284
288
|
/**
|
|
285
289
|
* A compiled picture card (AGL-3660): a Stack that opens with its picture,
|
|
@@ -3289,8 +3293,9 @@ const BUDGET_METRICS = [
|
|
|
3289
3293
|
* Rule 17. An output over its kind's budget is refused with the figure, the
|
|
3290
3294
|
* budget and the heaviest parts named, so the re-ask knows where to cut.
|
|
3291
3295
|
*/ export function detectOverBudget(score, outputKind, tree, context = {}) {
|
|
3292
|
-
// A page of its owner's own words weighs what their page does (AGL-4084), within the save ceiling
|
|
3293
|
-
|
|
3296
|
+
// A page of its owner's own words weighs what their page does (AGL-4084), within the save ceiling;
|
|
3297
|
+
// and so does a header and footer that is their own menu and footer (AGL-4108).
|
|
3298
|
+
const budget = context.ownWords && (outputKind === 'page' || outputKind === 'template' || outputKind === 'layout') ? _extends({}, AI_OUTPUT_BUDGETS[outputKind], AI_OWN_WORDS_PAGE_BUDGET) : AI_OUTPUT_BUDGETS[outputKind];
|
|
3294
3299
|
const violations = [];
|
|
3295
3300
|
for (const metric of BUDGET_METRICS){
|
|
3296
3301
|
const value = score[metric];
|