@aglyn/plugins-ai 1.0.0-beta.285 → 1.0.0-beta.287
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/assets/site-styles/nonprofit.webp +0 -0
- package/src/lib/assets/site-styles/professional.webp +0 -0
- package/src/lib/assets/site-styles/store.webp +0 -0
- package/src/lib/assets/site-styles/trades.webp +0 -0
- package/src/lib/components/ai-theme-proposal-card.component.js +12 -3
- package/src/lib/components/ai-theme-proposal-card.component.js.map +1 -1
- package/src/lib/declarations.js +5 -2
- package/src/lib/declarations.js.map +1 -1
- package/src/lib/declarations.server.js +12 -0
- package/src/lib/declarations.server.js.map +1 -1
- package/src/lib/jobs/ai-build-capabilities.d.ts +3 -1
- package/src/lib/jobs/ai-build-capabilities.js +27 -2
- package/src/lib/jobs/ai-build-capabilities.js.map +1 -1
- package/src/lib/jobs/ai-image-reads.d.ts +59 -0
- package/src/lib/jobs/ai-image-reads.js +138 -0
- package/src/lib/jobs/ai-image-reads.js.map +1 -0
- package/src/lib/jobs/ai-job-build-step.d.ts +29 -0
- package/src/lib/jobs/ai-job-build-step.js +83 -12
- package/src/lib/jobs/ai-job-build-step.js.map +1 -1
- package/src/lib/jobs/ai-job-duplicate-step.d.ts +2 -1
- package/src/lib/jobs/ai-job-duplicate-step.js +6 -6
- package/src/lib/jobs/ai-job-duplicate-step.js.map +1 -1
- package/src/lib/jobs/ai-job-import-step.d.ts +4 -2
- package/src/lib/jobs/ai-job-import-step.js +15 -11
- package/src/lib/jobs/ai-job-import-step.js.map +1 -1
- package/src/lib/jobs/ai-job-insight-step.d.ts +10 -0
- package/src/lib/jobs/ai-job-insight-step.js +23 -5
- package/src/lib/jobs/ai-job-insight-step.js.map +1 -1
- package/src/lib/jobs/ai-job-layout-language.js +2 -1
- package/src/lib/jobs/ai-job-layout-language.js.map +1 -1
- package/src/lib/jobs/ai-job-media-step.d.ts +2 -1
- package/src/lib/jobs/ai-job-media-step.js +6 -8
- package/src/lib/jobs/ai-job-media-step.js.map +1 -1
- package/src/lib/jobs/ai-job-navigation-step.d.ts +2 -1
- package/src/lib/jobs/ai-job-navigation-step.js +7 -9
- package/src/lib/jobs/ai-job-navigation-step.js.map +1 -1
- package/src/lib/jobs/ai-job-page-language.js +7 -1
- package/src/lib/jobs/ai-job-page-language.js.map +1 -1
- package/src/lib/jobs/ai-job-page-sections.js +16 -3
- package/src/lib/jobs/ai-job-page-sections.js.map +1 -1
- package/src/lib/jobs/ai-job-page-step.js +9 -1
- package/src/lib/jobs/ai-job-page-step.js.map +1 -1
- package/src/lib/jobs/ai-job-plan-step.d.ts +30 -8
- package/src/lib/jobs/ai-job-plan-step.js +78 -13
- package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
- package/src/lib/jobs/ai-job-privacy-step.d.ts +4 -2
- package/src/lib/jobs/ai-job-privacy-step.js +14 -15
- package/src/lib/jobs/ai-job-privacy-step.js.map +1 -1
- package/src/lib/jobs/ai-job-products-step.js +5 -3
- package/src/lib/jobs/ai-job-products-step.js.map +1 -1
- package/src/lib/jobs/ai-job-settings-step.d.ts +2 -1
- package/src/lib/jobs/ai-job-settings-step.js +7 -8
- package/src/lib/jobs/ai-job-settings-step.js.map +1 -1
- package/src/lib/jobs/ai-job-site-content.d.ts +34 -1
- package/src/lib/jobs/ai-job-site-content.js +67 -8
- package/src/lib/jobs/ai-job-site-content.js.map +1 -1
- package/src/lib/jobs/ai-job-site-datasets.d.ts +53 -3
- package/src/lib/jobs/ai-job-site-datasets.js +298 -30
- package/src/lib/jobs/ai-job-site-datasets.js.map +1 -1
- package/src/lib/jobs/ai-job-site-step.js +6 -3
- package/src/lib/jobs/ai-job-site-step.js.map +1 -1
- package/src/lib/jobs/ai-job-site-store-pages.js +3 -3
- package/src/lib/jobs/ai-job-site-store-pages.js.map +1 -1
- package/src/lib/jobs/ai-job-tracking-step.d.ts +2 -1
- package/src/lib/jobs/ai-job-tracking-step.js +7 -8
- package/src/lib/jobs/ai-job-tracking-step.js.map +1 -1
- package/src/lib/jobs/ai-jobs-beat.d.ts +11 -7
- package/src/lib/jobs/ai-jobs-beat.js +18 -8
- package/src/lib/jobs/ai-jobs-beat.js.map +1 -1
- package/src/lib/jobs/ai-jobs-notify.d.ts +66 -1
- package/src/lib/jobs/ai-jobs-notify.js +136 -3
- package/src/lib/jobs/ai-jobs-notify.js.map +1 -1
- package/src/lib/jobs/ai-layout-stock-photos.d.ts +59 -4
- package/src/lib/jobs/ai-layout-stock-photos.js +897 -81
- package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -1
- package/src/lib/jobs/ai-product-image.d.ts +14 -0
- package/src/lib/jobs/ai-product-image.js +73 -21
- package/src/lib/jobs/ai-product-image.js.map +1 -1
- package/src/lib/jobs/ai-theme-brand-inputs.d.ts +9 -1
- package/src/lib/jobs/ai-theme-brand-inputs.js +28 -2
- package/src/lib/jobs/ai-theme-brand-inputs.js.map +1 -1
- package/src/lib/jobs/fixtures/ai-site-agl4065-datasets.d.ts +175 -0
- package/src/lib/jobs/fixtures/ai-site-agl4065-datasets.js +601 -0
- package/src/lib/jobs/fixtures/ai-site-agl4065-datasets.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-site-agl4065-pages.d.ts +46 -0
- package/src/lib/jobs/fixtures/ai-site-agl4065-pages.js +2862 -0
- package/src/lib/jobs/fixtures/ai-site-agl4065-pages.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-site-agl4065-plans.d.ts +74 -0
- package/src/lib/jobs/fixtures/ai-site-agl4065-plans.js +888 -0
- package/src/lib/jobs/fixtures/ai-site-agl4065-plans.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl4065-judge.d.ts +29 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl4065-judge.js +81 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl4065-judge.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl4065-recordings.d.ts +87 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl4065-recordings.js +225 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl4065-recordings.js.map +1 -0
- package/src/lib/layout-language/ai-layout-compiler.d.ts +11 -0
- package/src/lib/layout-language/ai-layout-compiler.js +194 -18
- package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
- package/src/lib/layout-language/ai-layout-copy.d.ts +37 -0
- package/src/lib/layout-language/ai-layout-copy.js +383 -3
- package/src/lib/layout-language/ai-layout-copy.js.map +1 -1
- package/src/lib/layout-language/ai-layout-design.d.ts +19 -0
- package/src/lib/layout-language/ai-layout-design.js +31 -11
- package/src/lib/layout-language/ai-layout-design.js.map +1 -1
- package/src/lib/layout-language/ai-layout-listings.d.ts +7 -1
- package/src/lib/layout-language/ai-layout-listings.js +9 -1
- package/src/lib/layout-language/ai-layout-listings.js.map +1 -1
- package/src/lib/layout-language/ai-layout-pictures.d.ts +30 -0
- package/src/lib/layout-language/ai-layout-pictures.js +131 -3
- package/src/lib/layout-language/ai-layout-pictures.js.map +1 -1
- package/src/lib/layout-language/ai-layout-storefront.d.ts +18 -4
- package/src/lib/layout-language/ai-layout-storefront.js +100 -20
- package/src/lib/layout-language/ai-layout-storefront.js.map +1 -1
- package/src/lib/model/ai-build-job.d.ts +7 -0
- package/src/lib/model/ai-build-job.js +36 -7
- package/src/lib/model/ai-build-job.js.map +1 -1
- package/src/lib/model/ai-build-plan.d.ts +28 -4
- package/src/lib/model/ai-build-plan.js +49 -9
- package/src/lib/model/ai-build-plan.js.map +1 -1
- package/src/lib/model/ai-build-progress.js +3 -1
- package/src/lib/model/ai-build-progress.js.map +1 -1
- package/src/lib/model/ai-job-notice.d.ts +8 -0
- package/src/lib/model/ai-job-notice.js +33 -0
- package/src/lib/model/ai-job-notice.js.map +1 -1
- package/src/lib/model/ai-job-plan-lines.d.ts +2 -1
- package/src/lib/model/ai-job-plan-lines.js +6 -1
- package/src/lib/model/ai-job-plan-lines.js.map +1 -1
- package/src/lib/model/ai-jobs.types.d.ts +8 -0
- package/src/lib/model/ai-jobs.types.js.map +1 -1
- package/src/lib/model/ai-permissions.d.ts +13 -0
- package/src/lib/model/ai-permissions.js +29 -1
- package/src/lib/model/ai-permissions.js.map +1 -1
- package/src/lib/model/ai-products.d.ts +18 -0
- package/src/lib/model/ai-products.js +32 -0
- package/src/lib/model/ai-products.js.map +1 -1
- package/src/lib/model/ai-site-inspiration.d.ts +3 -2
- package/src/lib/model/ai-site-inspiration.js +3 -2
- package/src/lib/model/ai-site-inspiration.js.map +1 -1
- package/src/lib/plugin.js +4 -13
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/providers/anthropic.js +9 -2
- package/src/lib/providers/anthropic.js.map +1 -1
- package/src/lib/providers/catalog.js +14 -5
- package/src/lib/providers/catalog.js.map +1 -1
- package/src/lib/providers/contract.d.ts +24 -1
- package/src/lib/providers/contract.js.map +1 -1
- package/src/lib/providers/routing.js +5 -2
- package/src/lib/providers/routing.js.map +1 -1
- package/src/lib/runtime/ai-dataset-generation.d.ts +99 -1
- package/src/lib/runtime/ai-dataset-generation.js +251 -3
- package/src/lib/runtime/ai-dataset-generation.js.map +1 -1
- package/src/lib/runtime/ai-dev-replay.d.ts +1 -0
- package/src/lib/runtime/ai-dev-replay.js +4 -2
- package/src/lib/runtime/ai-dev-replay.js.map +1 -1
- package/src/lib/runtime/ai-doctrine-validators.d.ts +47 -3
- package/src/lib/runtime/ai-doctrine-validators.js +343 -27
- package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
- package/src/lib/runtime/ai-doctrine.js +8 -2
- package/src/lib/runtime/ai-doctrine.js.map +1 -1
- package/src/lib/runtime/ai-icon-library.d.ts +27 -1
- package/src/lib/runtime/ai-icon-library.js +30 -3
- package/src/lib/runtime/ai-icon-library.js.map +1 -1
- package/src/lib/runtime/ai-products-generation.d.ts +11 -1
- package/src/lib/runtime/ai-products-generation.js +51 -4
- package/src/lib/runtime/ai-products-generation.js.map +1 -1
- package/src/lib/runtime/assist-answer-cache.d.ts +2 -0
- package/src/lib/runtime/assist-answer-cache.js +5 -2
- package/src/lib/runtime/assist-answer-cache.js.map +1 -1
- package/src/lib/server/ai-allotments.js +7 -2
- package/src/lib/server/ai-allotments.js.map +1 -1
- package/src/lib/server/ai-experiment-versions.js +5 -5
- package/src/lib/server/ai-experiment-versions.js.map +1 -1
- package/src/lib/server/ai-host-permissions-roster.d.ts +25 -0
- package/src/lib/server/ai-host-permissions-roster.js +33 -0
- package/src/lib/server/ai-host-permissions-roster.js.map +1 -0
- package/src/lib/server/ai-host-permissions.js +8 -6
- package/src/lib/server/ai-host-permissions.js.map +1 -1
- package/src/lib/server/ai-image-reads-route.d.ts +17 -0
- package/src/lib/server/ai-image-reads-route.js +106 -0
- package/src/lib/server/ai-image-reads-route.js.map +1 -0
- package/src/lib/server/ai-seo-apply.js +5 -5
- package/src/lib/server/ai-seo-apply.js.map +1 -1
- package/src/lib/server/ai-site-import-route.js +7 -4
- package/src/lib/server/ai-site-import-route.js.map +1 -1
- package/src/lib/server/assist-build.js +1 -0
- package/src/lib/server/assist-build.js.map +1 -1
- package/src/lib/server/assist-chat.d.ts +11 -7
- package/src/lib/server/assist-chat.js +185 -48
- package/src/lib/server/assist-chat.js.map +1 -1
- package/src/lib/server/assist-docs-query.d.ts +51 -0
- package/src/lib/server/assist-docs-query.js +57 -0
- package/src/lib/server/assist-docs-query.js.map +1 -0
- package/src/lib/server/assist-jobs-context.d.ts +102 -0
- package/src/lib/server/assist-jobs-context.js +227 -0
- package/src/lib/server/assist-jobs-context.js.map +1 -0
- package/src/lib/server/assist-view-context.d.ts +8 -4
- package/src/lib/server/assist-view-context.js +12 -7
- package/src/lib/server/assist-view-context.js.map +1 -1
- package/src/lib/server.js +12 -0
- package/src/lib/server.js.map +1 -1
- package/src/lib/tools/ai-dataset-tool.d.ts +11 -1
- package/src/lib/tools/ai-dataset-tool.js +24 -7
- package/src/lib/tools/ai-dataset-tool.js.map +1 -1
- package/src/lib/tools/ai-duplicate-resource-tool.js +5 -6
- package/src/lib/tools/ai-duplicate-resource-tool.js.map +1 -1
- package/src/lib/components/ai-collaborator-permissions-column.component.d.ts +0 -32
- package/src/lib/components/ai-collaborator-permissions-column.component.js +0 -132
- package/src/lib/components/ai-collaborator-permissions-column.component.js.map +0 -1
|
@@ -146,7 +146,7 @@ const ANTHROPIC_VERSION = '2023-06-01';
|
|
|
146
146
|
* itself refuses.
|
|
147
147
|
*/ export function buildAnthropicRequestBody(input) {
|
|
148
148
|
var _input_effort, _ANTHROPIC_THINKING_OFF_input_model;
|
|
149
|
-
var _input_tools, _aiCatalogEntry;
|
|
149
|
+
var _input_tools, _aiCatalogEntry, _aiCatalogEntry1;
|
|
150
150
|
const conversation = Boolean(input.cacheConversation) && input.messages.length > 0;
|
|
151
151
|
const breakpoints = input.system.filter((block)=>block.cacheBreakpoint).length + (conversation ? 1 : 0);
|
|
152
152
|
if (breakpoints > ANTHROPIC_MAX_CACHE_BREAKPOINTS) {
|
|
@@ -182,6 +182,10 @@ const ANTHROPIC_VERSION = '2023-06-01';
|
|
|
182
182
|
const thinking = settable ? input.thinking : undefined;
|
|
183
183
|
const effort = settable ? (_input_effort = input.effort) != null ? _input_effort : ANTHROPIC_DEFAULT_EFFORT[input.model] : undefined;
|
|
184
184
|
const thinkingOff = (_ANTHROPIC_THINKING_OFF_input_model = ANTHROPIC_THINKING_OFF[input.model]) != null ? _ANTHROPIC_THINKING_OFF_input_model : 'disabled';
|
|
185
|
+
// A named tool is forced only where the model takes a forced choice and
|
|
186
|
+
// thinking is sent off, which the API requires of one (AGL-4076); every
|
|
187
|
+
// other request, a named one on Claude Sonnet 5.5 included, chooses for itself.
|
|
188
|
+
const forced = input.toolChoice && (tools == null ? void 0 : tools.some((tool)=>tool.name === input.toolChoice)) && ((_aiCatalogEntry1 = aiCatalogEntry(input.model)) == null ? void 0 : _aiCatalogEntry1.capabilities.forcedToolChoice) === true && thinking === 'off' && thinkingOff === 'disabled' ? input.toolChoice : null;
|
|
185
189
|
return _extends({
|
|
186
190
|
model: input.model,
|
|
187
191
|
max_tokens: input.maxTokens
|
|
@@ -208,7 +212,10 @@ const ANTHROPIC_VERSION = '2023-06-01';
|
|
|
208
212
|
}))
|
|
209
213
|
}, (tools == null ? void 0 : tools.length) ? {
|
|
210
214
|
tools,
|
|
211
|
-
tool_choice: {
|
|
215
|
+
tool_choice: forced ? {
|
|
216
|
+
type: 'tool',
|
|
217
|
+
name: forced
|
|
218
|
+
} : {
|
|
212
219
|
type: 'auto'
|
|
213
220
|
}
|
|
214
221
|
} : {});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/providers/anthropic.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 { aiBilledRatesForModel, aiCatalogEntry, aiModelIdsForProvider, estimateAiBilledUsd } from './catalog'\nimport { aiCacheWriteHourSurchargeUsd } from './cache-write-hour'\nimport {\n AiBatchUnfinishedError,\n AiUpstreamError,\n aiCacheMarkerTtls,\n type AiAccountProblem,\n type AiBatchOptions,\n type AiCacheTtl,\n type AiEffort,\n aiRawOutputOf,\n aiStoppedAtCeiling,\n aiTokenCount,\n aiToolInputOf,\n type AiMessage,\n type AiModelDescriptor,\n type AiProvider,\n type AiProviderRequest,\n type AiResult,\n type AiStreamEvent,\n type AiToolSchemaLimits,\n type AiToolUse,\n type AiUsage,\n} from './contract'\n\n/**\n * The Anthropic adapter (AGL-2903, behind the contract since AGL-2939):\n * the Messages API over raw `fetch`. No provider SDK is installed, and the\n * meter prices by model id from the catalog, so nothing an SDK would add\n * is used here. This file and the catalog are the only places in the\n * plugin that name the vendor's URL, header or model ids.\n *\n * ── Errors (AGL-2815) ─────────────────────────────────────────────────────\n *\n * Provider error text describes OUR account with the vendor — a key, a rate\n * limit, a balance — and names the vendor to a white-label org's users. It\n * never leaves this module as a message: a non-2xx answer becomes an\n * `AiUpstreamError` carrying the status, whether the failure is retryable\n * and a fixed customer-safe sentence; the provider's body goes to\n * `console.error` beside the request id, where an operator can find it.\n * A `refusal` stop is not an error at all — the tokens were spent and the\n * model answered — so it comes back as a typed `AiRefusal` result.\n */\n\nexport const ANTHROPIC_PROVIDER_ID = 'anthropic'\nexport const ANTHROPIC_API_KEY_ENV = 'ANTHROPIC_API_KEY'\nconst ANTHROPIC_HOST = 'api.anthropic.com'\nconst ANTHROPIC_URL = `https://${ANTHROPIC_HOST}/v1/messages`\nconst ANTHROPIC_BATCHES_URL = `https://${ANTHROPIC_HOST}/v1/messages/batches`\nconst ANTHROPIC_VERSION = '2023-06-01'\n\n/** The Messages API accepts at most this many `cache_control` markers. */\nexport const ANTHROPIC_MAX_CACHE_BREAKPOINTS = 4\n\n/**\n * What the Messages API compiles of one request's strict schemas, as its\n * structured-outputs documentation states the limits: 20 strict tools, 24\n * optional parameters and 16 parameters with union types, each a total over\n * every strict schema the request carries. Past any of them the request is\n * refused with a 400 before the model runs.\n *\n * `compiledSchemaBytes` is not one of those. The API also refuses a request\n * whose schemas compile to too large a grammar — \"Simplify your tool schemas\n * or reduce the number of strict tools\" — and states no size for it, so this\n * bound is measured rather than read (AGL-3096). Its evidence is two live\n * requests for the automation draft, the largest strict schema anything here\n * sends:\n *\n * - 8,757 bytes, refused for grammar size (`req_011CfC6Fif9iJvmKPTRgtLdp`,\n * 2026-09-19), with 1 strict tool, 0 optional parameters and 2 unions:\n * every published count was green;\n * - 3,807 bytes, served (`req_011CfELn62WVLeaNzwK4TWgb`, 2026-09-20), the\n * same tool with the guard lifted out of the steps' union and one variant\n * per set of fields.\n *\n * Everything else the plugin sends is smaller still, the next largest being\n * the theme tool at 2,410 bytes. The bound sits at what has been served, so a\n * schema that grows past it has to be proved live before the bound moves.\n */\nexport const ANTHROPIC_TOOL_SCHEMA_LIMITS: AiToolSchemaLimits = {\n strictTools: 20,\n optionalParameters: 24,\n unionParameters: 16,\n compiledSchemaBytes: 3_807,\n}\n\n/**\n * Whether a provider failure is the kind that clears on its own. Matched on\n * the status AND the error type, because the in-stream `error` event has no\n * status to go by.\n */\nexport function anthropicFailureIsRetryable(\n status: number | null,\n errorType: string | undefined,\n): boolean {\n return (\n status === 429 ||\n status === 529 ||\n errorType === 'rate_limit_error' ||\n errorType === 'overloaded_error'\n )\n}\n\n/**\n * Whether a failure is about the platform's Anthropic account rather than the\n * request (AGL-3377): a refused key, or a balance too low to answer.\n */\nexport function anthropicAccountProblem(\n status: number | null,\n error: { type?: string; message?: string } | null | undefined,\n): AiAccountProblem | null {\n if (status === 401 || status === 403) return 'credentials'\n if (error?.type === 'authentication_error' || error?.type === 'permission_error') {\n return 'credentials'\n }\n if (error?.type === 'billing_error' || /credit balance/i.test(error?.message ?? '')) {\n return 'credit'\n }\n return null\n}\n\n/** Anthropic's `usage` object, in the meter's shape. Missing fields read 0. */\nexport function anthropicUsageFrom(usage: unknown): AiUsage {\n const record = (usage ?? {}) as Record<string, unknown>\n // Part of `output_tokens`, and carried only where the response breaks them\n // down, so an answer that reports none says nothing rather than zero.\n const details = record['output_tokens_details']\n const thinking =\n details && typeof details === 'object'\n ? (details as Record<string, unknown>)['thinking_tokens']\n : undefined\n // The writes split by lifetime (AGL-3830). Only an hour-long write is kept,\n // because it is the one billed above the rate table's write rate, and only\n // where there was one, so every five-minute exchange keeps its shape.\n const creation = record['cache_creation']\n const hour =\n creation && typeof creation === 'object'\n ? aiTokenCount((creation as Record<string, unknown>)['ephemeral_1h_input_tokens'])\n : 0\n return {\n inputTokens: aiTokenCount(record['input_tokens']),\n outputTokens: aiTokenCount(record['output_tokens']),\n cacheReadTokens: aiTokenCount(record['cache_read_input_tokens']),\n cacheWriteTokens: aiTokenCount(record['cache_creation_input_tokens']),\n ...(hour > 0 ? { cacheWriteHourTokens: hour } : {}),\n ...(thinking === undefined ? {} : { thinkingTokens: aiTokenCount(thinking) }),\n }\n}\n\n/** What an exchange draws, its hour-long cache writes included (AGL-3830). */\nfunction anthropicBilledUsd(usage: AiUsage, model: string): number {\n const usd = estimateAiBilledUsd(usage, model) + aiCacheWriteHourSurchargeUsd(usage, aiBilledRatesForModel(model))\n return Math.round(usd * 1_000_000) / 1_000_000\n}\n\n/**\n * How \"thinking off\" is said to a model that refuses `{type: \"disabled\"}`.\n * Claude Sonnet 5.5 turns it off only through `between_tools` (accepted at\n * effort high or below, which is every effort the contract names); Claude\n * Opus 5.5 cannot turn it off at all, so the field is left out and the\n * model's adaptive thinking runs. Every other model takes `disabled`.\n */\nconst ANTHROPIC_THINKING_OFF: Readonly<Record<string, 'between_tools' | 'omit'>> = {\n 'claude-sonnet-5-5': 'between_tools',\n 'claude-opus-5-5': 'omit',\n}\n\n/**\n * The effort a request that names none is sent, for a model whose own\n * default is lower than its siblings': Claude Opus 5.5 defaults to medium,\n * where Claude Opus 5 defaults to high.\n */\nconst ANTHROPIC_DEFAULT_EFFORT: Readonly<Record<string, AiEffort>> = {\n 'claude-opus-5-5': 'high',\n}\n\n/**\n * The Messages API body for a request. Exported so a spec can assert the\n * wire shape without a network. The cache-prefix rule is enforced by the\n * runtime before the request reaches any adapter; this maps the surviving\n * breakpoints onto `cache_control` and refuses only the count the API\n * itself refuses.\n */\nexport function buildAnthropicRequestBody(\n input: Omit<AiProviderRequest, 'apiKey' | 'signal'> & { stream: boolean },\n): Record<string, unknown> {\n const conversation = Boolean(input.cacheConversation) && input.messages.length > 0\n const breakpoints = input.system.filter((block) => block.cacheBreakpoint).length + (conversation ? 1 : 0)\n if (breakpoints > ANTHROPIC_MAX_CACHE_BREAKPOINTS) {\n throw new Error(\n `${breakpoints} cache breakpoints; the Messages API allows ${ANTHROPIC_MAX_CACHE_BREAKPOINTS}`,\n )\n }\n // A lifetime per breakpoint (AGL-4050): the shared prompt's markers at the\n // route's lifetime, a site's block and the conversation at five minutes,\n // and never an hour after five minutes, which the API refuses.\n const ttls = aiCacheMarkerTtls({ ...input, cacheConversation: conversation })\n const system = input.system.map((block, index) => {\n const ttl = ttls.system[index]\n return { type: 'text', text: block.text, ...(ttl ? { cache_control: anthropicCacheControl(ttl) } : {}) }\n })\n const tools = input.tools?.map((tool) => ({\n name: tool.name,\n description: tool.description,\n input_schema: { ...tool.inputSchema, additionalProperties: false },\n strict: true,\n }))\n // A model that rejects an explicit thinking setting gets none, whatever\n // the door asked for, and no effort either: effort rides the same rule\n // (see the contract), and the catalog says which models those are.\n const settable = aiCatalogEntry(input.model)?.capabilities.thinking !== false\n const thinking = settable ? input.thinking : undefined\n const effort = settable ? (input.effort ?? ANTHROPIC_DEFAULT_EFFORT[input.model]) : undefined\n const thinkingOff = ANTHROPIC_THINKING_OFF[input.model] ?? 'disabled'\n return {\n model: input.model,\n max_tokens: input.maxTokens,\n ...(input.stream ? { stream: true } : {}),\n ...(thinking === 'off'\n ? thinkingOff === 'omit'\n ? {}\n : { thinking: { type: thinkingOff } }\n : thinking === 'adaptive'\n ? { thinking: { type: 'adaptive' } }\n : {}),\n ...(effort ? { output_config: { effort } } : {}),\n ...(system.length ? { system } : {}),\n messages: input.messages.map((message, index) => ({\n role: message.role,\n content: conversation\n ? anthropicBlocksOf(\n message,\n index === input.messages.length - 1 && ttls.conversation ? anthropicCacheControl(ttls.conversation) : null,\n )\n : anthropicContentOf(message),\n })),\n ...(tools?.length ? { tools, tool_choice: { type: 'auto' } } : {}),\n }\n}\n\n/** One marker's `cache_control`: the five minutes are the API's default, so only the hour is named. */\nfunction anthropicCacheControl(ttl: AiCacheTtl): Record<string, unknown> {\n return ttl === '1h' ? { type: 'ephemeral', ttl: '1h' } : { type: 'ephemeral' }\n}\n\n/**\n * A turn's content in the Messages API's shape: a text-only turn as the\n * string it is, and a turn with pictures as content blocks in order, each\n * picture a base64 image block (AGL-2916).\n */\nfunction anthropicContentOf(message: AiMessage): string | Array<Record<string, unknown>> {\n if (typeof message.content === 'string') return message.content\n return message.content.map((part) =>\n part.type === 'image'\n ? { type: 'image', source: { type: 'base64', media_type: part.mediaType, data: part.data } }\n : { type: 'text', text: part.text },\n )\n}\n\n/**\n * A turn as content blocks whatever its shape, the last block carrying the\n * conversation's breakpoint when it is the request's last turn (AGL-3809).\n * Every turn of a request that caches its conversation is sent as blocks, so\n * a turn reads the same on the call that marked it and on every call after,\n * where it is no longer last.\n */\nfunction anthropicBlocksOf(\n message: AiMessage,\n cacheControl: Record<string, unknown> | null,\n): Array<Record<string, unknown>> {\n const content = anthropicContentOf(message)\n const blocks = typeof content === 'string' ? [{ type: 'text', text: content }] : content\n if (!cacheControl || !blocks.length) return blocks\n const last = blocks.length - 1\n return blocks.map((block, index) => (index === last ? { ...block, cache_control: cacheControl } : block))\n}\n\n/** The provider's request id, when it sent one — the log's join key. */\nfunction requestIdOf(response: Response): string | null {\n return response.headers?.get?.('request-id') ?? null\n}\n\nasync function send(\n input: AiProviderRequest,\n stream: boolean,\n): Promise<Response> {\n const body = buildAnthropicRequestBody({ ...input, stream })\n const response = await fetch(ANTHROPIC_URL, {\n method: 'POST',\n headers: {\n 'x-api-key': input.apiKey,\n 'anthropic-version': ANTHROPIC_VERSION,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n ...(input.signal ? { signal: input.signal } : {}),\n })\n if (!response.ok || (stream && !response.body)) {\n const requestId = requestIdOf(response)\n const payload = (await response.json().catch(() => null)) as {\n error?: { type?: string; message?: string }\n } | null\n console.error('ai upstream error', {\n provider: ANTHROPIC_PROVIDER_ID,\n status: response.status,\n requestId,\n model: input.model,\n error: payload?.error ?? null,\n })\n throw new AiUpstreamError(\n response.status,\n anthropicFailureIsRetryable(response.status, payload?.error?.type),\n requestId,\n anthropicAccountProblem(response.status, payload?.error),\n )\n }\n return response\n}\n\nasync function complete(input: AiProviderRequest): Promise<AiResult> {\n const response = await send(input, false)\n return anthropicResultFrom(await response.json(), input.model)\n}\n\n/**\n * A Messages API answer as the contract's result: the shape `complete` reads\n * off the wire and a batch's succeeded entry carries. `priceFactor` is what a\n * discount leaves of the price (a batch's half).\n */\nexport function anthropicResultFrom(raw: unknown, model: string, priceFactor = 1): AiResult {\n const payload = raw as {\n content?: Array<Record<string, unknown>>\n stop_reason?: unknown\n usage?: unknown\n } | null\n const blocks = Array.isArray(payload?.content) ? payload.content : []\n const text = blocks\n .filter((block) => block?.['type'] === 'text')\n .map((block) => String(block['text'] ?? ''))\n .join('')\n const toolUse: AiToolUse[] = blocks\n .filter((block) => block?.['type'] === 'tool_use')\n .map((block) => ({\n name: String(block['name'] ?? ''),\n input: aiToolInputOf(block['input']),\n }))\n const usage = anthropicUsageFrom(payload?.usage)\n const estCostUsd = Math.round(anthropicBilledUsd(usage, model) * priceFactor * 1_000_000) / 1_000_000\n const stopReason =\n typeof payload?.stop_reason === 'string' && payload.stop_reason\n ? payload.stop_reason\n : null\n if (stopReason === 'refusal') {\n return { kind: 'refusal', text, usage, estCostUsd, stopReason }\n }\n return {\n kind: 'completion',\n text,\n toolUse,\n usage,\n estCostUsd,\n stopReason,\n // The blocks as the provider answered them, for a call its ceiling cut\n // off (AGL-3143): `toolUse` holds only what still parsed out of them.\n ...(aiStoppedAtCeiling(stopReason) ? { rawOutput: aiRawOutputOf(blocks) } : {}),\n }\n}\n\nasync function stream(input: AiProviderRequest): Promise<AsyncIterable<AiStreamEvent>> {\n const response = await send(input, true)\n return streamEvents(\n response.body as ReadableStream<Uint8Array>,\n input.model,\n requestIdOf(response),\n )\n}\n\n/**\n * Anthropic's SSE stream as contract events. Usage is taken from\n * `message_start` (input and cache figures) and `message_delta` (the\n * output count, and any cumulative input figures a newer API sends); the\n * `done` event carries whatever was known when the body ended, so a stream\n * cut short still meters what it cost.\n */\nasync function* streamEvents(\n body: ReadableStream<Uint8Array>,\n model: string,\n requestId: string | null,\n): AsyncGenerator<AiStreamEvent> {\n const decoder = new TextDecoder()\n const reader = body.getReader()\n const usage: AiUsage = {\n inputTokens: 0,\n outputTokens: 0,\n cacheReadTokens: 0,\n cacheWriteTokens: 0,\n }\n let stopReason: string | null = null\n /** Tool-use blocks in flight, by content index; input arrives in pieces. */\n const tools = new Map<number, { name: string; json: string }>()\n /**\n * What each tool call was actually written in, in the order its block\n * opened (AGL-3143). The `tool` events below carry only as much of these\n * as `aiToolInputOf` could still parse, so for a call the ceiling cut off\n * this is the one place the emitted bytes survive.\n */\n const written: string[] = []\n let buffer = ''\n let drained = false\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) {\n drained = true\n break\n }\n buffer += decoder.decode(value, { stream: true })\n const lines = buffer.split('\\n')\n buffer = lines.pop() ?? ''\n for (const line of lines) {\n if (!line.startsWith('data: ')) continue\n let event: Record<string, unknown>\n try {\n event = JSON.parse(line.slice('data: '.length))\n } catch {\n continue\n }\n const index = Number(event['index'])\n switch (event['type']) {\n case 'message_start': {\n const start = anthropicUsageFrom(\n (event['message'] as { usage?: unknown } | undefined)?.usage,\n )\n usage.inputTokens = start.inputTokens\n usage.cacheReadTokens = start.cacheReadTokens\n usage.cacheWriteTokens = start.cacheWriteTokens\n if (start.cacheWriteHourTokens) usage.cacheWriteHourTokens = start.cacheWriteHourTokens\n break\n }\n case 'content_block_start': {\n const block = event['content_block'] as\n | { type?: string; name?: string }\n | undefined\n if (block?.type === 'tool_use') {\n tools.set(index, { name: String(block.name ?? ''), json: '' })\n }\n break\n }\n case 'content_block_delta': {\n const delta = event['delta'] as\n | { type?: string; text?: string; partial_json?: string }\n | undefined\n if (delta?.type === 'text_delta' && delta.text) {\n yield { type: 'delta', text: delta.text }\n } else if (delta?.type === 'input_json_delta') {\n const tool = tools.get(index)\n if (tool) tool.json += delta.partial_json ?? ''\n }\n break\n }\n case 'content_block_stop': {\n const tool = tools.get(index)\n if (tool) {\n tools.delete(index)\n written.push(tool.json)\n yield { type: 'tool', name: tool.name, input: aiToolInputOf(tool.json) }\n }\n break\n }\n case 'message_delta': {\n const delta = anthropicUsageFrom(event['usage'])\n usage.outputTokens = delta.outputTokens || usage.outputTokens\n usage.inputTokens = delta.inputTokens || usage.inputTokens\n usage.cacheReadTokens = delta.cacheReadTokens || usage.cacheReadTokens\n usage.cacheWriteTokens = delta.cacheWriteTokens || usage.cacheWriteTokens\n // Kept where the breakdown is reported and left absent where it\n // is not (AGL-3143), never set to a zero the provider did not\n // send. A stream needs it for the reason a completion does: it\n // is the figure that accounts for a spent ceiling first, and it\n // arrives in the same usage object as the four above.\n if (delta.thinkingTokens !== undefined) usage.thinkingTokens = delta.thinkingTokens\n const reason = (event['delta'] as { stop_reason?: unknown } | undefined)\n ?.stop_reason\n if (typeof reason === 'string' && reason) stopReason = reason\n break\n }\n case 'error': {\n const error = event['error'] as\n | { type?: string; message?: string }\n | undefined\n console.error('ai upstream stream error', {\n provider: ANTHROPIC_PROVIDER_ID,\n requestId,\n model,\n error: error ?? null,\n })\n yield { type: 'error', retryable: anthropicFailureIsRetryable(null, error?.type) }\n break\n }\n default:\n break\n }\n }\n }\n } finally {\n // A consumer that stops iterating early — a client that hung up — must\n // not leave the provider generating into a socket nobody reads: cancel\n // tells the upstream to stop, and the tokens it has already produced are\n // the only ones billed.\n if (!drained) await reader.cancel().catch(() => undefined)\n reader.releaseLock()\n }\n // A message the ceiling ends mid-block never reaches that block's stop\n // event, so what it had written is still held in flight.\n for (const tool of tools.values()) written.push(tool.json)\n yield {\n type: 'done',\n usage,\n estCostUsd: anthropicBilledUsd(usage, model),\n stopReason,\n // What the model emitted into its tool calls, for a stream its ceiling\n // cut off (AGL-3143): the `tool` events carry only what parsed out.\n ...(aiStoppedAtCeiling(stopReason) ? { rawOutput: aiRawOutputOf(written.join('')) } : {}),\n }\n}\n\n/** What a batch's discount leaves of a request's price. */\nexport const ANTHROPIC_BATCH_PRICE_FACTOR = 0.5\n\nfunction batchHeaders(apiKey: string): Record<string, string> {\n return {\n 'x-api-key': apiKey,\n 'anthropic-version': ANTHROPIC_VERSION,\n 'Content-Type': 'application/json',\n }\n}\n\n/** A batch call that did not answer 2xx, as the contract's error. */\nasync function batchFailure(response: Response, model: string): Promise<AiUpstreamError> {\n const requestId = requestIdOf(response)\n const payload = (await response.json().catch(() => null)) as {\n error?: { type?: string; message?: string }\n } | null\n console.error('ai upstream batch error', {\n provider: ANTHROPIC_PROVIDER_ID,\n status: response.status,\n requestId,\n model,\n error: payload?.error ?? null,\n })\n return new AiUpstreamError(\n response.status,\n anthropicFailureIsRetryable(response.status, payload?.error?.type),\n requestId,\n anthropicAccountProblem(response.status, payload?.error),\n )\n}\n\n/** The batch as its create and poll calls describe it. */\ninterface AnthropicBatch {\n id: string\n processing_status?: string\n results_url?: string | null\n}\n\n/** Results a batch can end a request with that answer nothing yet: asked again, not failed (AGL-3781). */\nconst ANTHROPIC_BATCH_UNFINISHED = new Set(['canceled', 'expired'])\n\n/**\n * Many requests through the Message Batches API (AGL-3660): created as one\n * batch, polled until it has ended, its results read by `custom_id` — they\n * come back in any order — and each turned into the result `complete` would\n * have returned, at half the price. Development only: the live evals' batch\n * mode is the one caller, and no door waits minutes for an answer.\n *\n * A batch still processing when its wait runs out is canceled, and read once\n * the cancel has ended it (AGL-3781): a cancel keeps every answer the batch\n * already has, so those come back as results, and only the requests it never\n * reached come back as `AiBatchUnfinishedError`, for the caller to ask on\n * their own. Throwing away a round's paid-for answers because one batch was\n * slow is how a whole golden run lost its grades.\n */\nasync function completeBatch(\n requests: readonly AiProviderRequest[],\n options: AiBatchOptions = {},\n): Promise<Array<AiResult | Error>> {\n if (!requests.length) return []\n const apiKey = requests[0].apiKey\n const model = requests[0].model\n const pollMs = options.pollMs ?? 10_000\n const timeoutMs = options.timeoutMs ?? 60 * 60_000\n const cancelGraceMs = options.cancelGraceMs ?? 10 * 60_000\n const unfinished = (id: string, reason: string) => requests.map(() => new AiBatchUnfinishedError(id, reason))\n const created = await fetch(ANTHROPIC_BATCHES_URL, {\n method: 'POST',\n headers: batchHeaders(apiKey),\n body: JSON.stringify({\n requests: requests.map((request, index) => {\n const { apiKey: _key, signal: _signal, ...rest } = request\n return { custom_id: `r${index}`, params: buildAnthropicRequestBody({ ...rest, stream: false }) }\n }),\n }),\n })\n if (!created.ok) throw await batchFailure(created, model)\n let batch = (await created.json()) as AnthropicBatch\n const deadline = Date.now() + timeoutMs\n let cancelDeadline: number | null = null\n while (batch.processing_status !== 'ended') {\n if (cancelDeadline === null && Date.now() >= deadline) {\n console.warn(`[ai] batch ${batch.id} has not ended after ${timeoutMs} ms; canceling it to read what it answered`)\n await fetch(`${ANTHROPIC_BATCHES_URL}/${batch.id}/cancel`, { method: 'POST', headers: batchHeaders(apiKey) }).catch(\n () => undefined,\n )\n cancelDeadline = Date.now() + cancelGraceMs\n }\n // A cancel that never ends leaves no results to read; every request goes back unanswered.\n if (cancelDeadline !== null && Date.now() >= cancelDeadline) return unfinished(batch.id, 'cancel did not end')\n await new Promise((resolve) => setTimeout(resolve, pollMs))\n const polled = await fetch(`${ANTHROPIC_BATCHES_URL}/${batch.id}`, { headers: batchHeaders(apiKey) })\n if (!polled.ok) throw await batchFailure(polled, model)\n batch = (await polled.json()) as AnthropicBatch\n }\n if (!batch.results_url) {\n if (cancelDeadline !== null) return unfinished(batch.id, 'canceled with no results')\n throw new Error(`batch ${batch.id} ended with no results`)\n }\n const results = await fetch(batch.results_url, { headers: batchHeaders(apiKey) })\n if (!results.ok) throw await batchFailure(results, model)\n const byId = new Map<string, { type?: string; message?: unknown; error?: unknown }>()\n for (const line of (await results.text()).split('\\n')) {\n if (!line.trim()) continue\n const entry = JSON.parse(line) as { custom_id: string; result?: { type?: string; message?: unknown; error?: unknown } }\n byId.set(entry.custom_id, entry.result ?? {})\n }\n return requests.map((request, index) => {\n const result = byId.get(`r${index}`)\n if (result?.type === 'succeeded') {\n return anthropicResultFrom(result.message, request.model, ANTHROPIC_BATCH_PRICE_FACTOR)\n }\n const type = result?.type ?? 'missing'\n if (ANTHROPIC_BATCH_UNFINISHED.has(type) || type === 'missing') return new AiBatchUnfinishedError(batch.id, type)\n console.error('ai batch request not answered', {\n provider: ANTHROPIC_PROVIDER_ID,\n batchId: batch.id,\n customId: `r${index}`,\n result: type,\n error: result?.error ?? null,\n })\n return new AiUpstreamError(null, type === 'errored', batch.id, null)\n })\n}\n\nexport const anthropicProvider: AiProvider = {\n id: ANTHROPIC_PROVIDER_ID,\n label: 'Anthropic',\n apiKeyEnv: ANTHROPIC_API_KEY_ENV,\n readApiKey: () => process.env.ANTHROPIC_API_KEY?.trim() || undefined,\n endpointHost: ANTHROPIC_HOST,\n toolSchemaLimits: ANTHROPIC_TOOL_SCHEMA_LIMITS,\n models(): readonly AiModelDescriptor[] {\n return aiModelIdsForProvider(ANTHROPIC_PROVIDER_ID)\n .map((id) => aiCatalogEntry(id))\n .filter((entry): entry is NonNullable<typeof entry> => Boolean(entry))\n },\n complete,\n stream,\n completeBatch,\n}\n"],"names":["aiBilledRatesForModel","aiCatalogEntry","aiModelIdsForProvider","estimateAiBilledUsd","aiCacheWriteHourSurchargeUsd","AiBatchUnfinishedError","AiUpstreamError","aiCacheMarkerTtls","aiRawOutputOf","aiStoppedAtCeiling","aiTokenCount","aiToolInputOf","ANTHROPIC_PROVIDER_ID","ANTHROPIC_API_KEY_ENV","ANTHROPIC_HOST","ANTHROPIC_URL","ANTHROPIC_BATCHES_URL","ANTHROPIC_VERSION","ANTHROPIC_MAX_CACHE_BREAKPOINTS","ANTHROPIC_TOOL_SCHEMA_LIMITS","strictTools","optionalParameters","unionParameters","compiledSchemaBytes","anthropicFailureIsRetryable","status","errorType","anthropicAccountProblem","error","type","test","message","anthropicUsageFrom","usage","record","details","thinking","undefined","creation","hour","inputTokens","outputTokens","cacheReadTokens","cacheWriteTokens","cacheWriteHourTokens","thinkingTokens","anthropicBilledUsd","model","usd","Math","round","ANTHROPIC_THINKING_OFF","ANTHROPIC_DEFAULT_EFFORT","buildAnthropicRequestBody","input","conversation","Boolean","cacheConversation","messages","length","breakpoints","system","filter","block","cacheBreakpoint","Error","ttls","map","index","ttl","text","cache_control","anthropicCacheControl","tools","tool","name","description","input_schema","inputSchema","additionalProperties","strict","settable","capabilities","effort","thinkingOff","max_tokens","maxTokens","stream","output_config","role","content","anthropicBlocksOf","anthropicContentOf","tool_choice","part","source","media_type","mediaType","data","cacheControl","blocks","last","requestIdOf","response","headers","get","send","body","fetch","method","apiKey","JSON","stringify","signal","ok","payload","requestId","json","catch","console","provider","complete","anthropicResultFrom","raw","priceFactor","Array","isArray","String","join","toolUse","estCostUsd","stopReason","stop_reason","kind","rawOutput","streamEvents","decoder","TextDecoder","reader","getReader","Map","written","buffer","drained","lines","done","value","read","decode","split","pop","line","startsWith","event","parse","slice","Number","start","set","delta","partial_json","delete","push","reason","retryable","cancel","releaseLock","values","ANTHROPIC_BATCH_PRICE_FACTOR","batchHeaders","batchFailure","ANTHROPIC_BATCH_UNFINISHED","Set","completeBatch","requests","options","pollMs","timeoutMs","cancelGraceMs","unfinished","id","created","request","_key","_signal","rest","custom_id","params","batch","deadline","Date","now","cancelDeadline","processing_status","warn","Promise","resolve","setTimeout","polled","results_url","results","byId","entry","trim","result","has","batchId","customId","anthropicProvider","label","apiKeyEnv","readApiKey","process","env","ANTHROPIC_API_KEY","endpointHost","toolSchemaLimits","models"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/providers/anthropic.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 { aiBilledRatesForModel, aiCatalogEntry, aiModelIdsForProvider, estimateAiBilledUsd } from './catalog'\nimport { aiCacheWriteHourSurchargeUsd } from './cache-write-hour'\nimport {\n AiBatchUnfinishedError,\n AiUpstreamError,\n aiCacheMarkerTtls,\n type AiAccountProblem,\n type AiBatchOptions,\n type AiCacheTtl,\n type AiEffort,\n aiRawOutputOf,\n aiStoppedAtCeiling,\n aiTokenCount,\n aiToolInputOf,\n type AiMessage,\n type AiModelDescriptor,\n type AiProvider,\n type AiProviderRequest,\n type AiResult,\n type AiStreamEvent,\n type AiToolSchemaLimits,\n type AiToolUse,\n type AiUsage,\n} from './contract'\n\n/**\n * The Anthropic adapter (AGL-2903, behind the contract since AGL-2939):\n * the Messages API over raw `fetch`. No provider SDK is installed, and the\n * meter prices by model id from the catalog, so nothing an SDK would add\n * is used here. This file and the catalog are the only places in the\n * plugin that name the vendor's URL, header or model ids.\n *\n * ── Errors (AGL-2815) ─────────────────────────────────────────────────────\n *\n * Provider error text describes OUR account with the vendor — a key, a rate\n * limit, a balance — and names the vendor to a white-label org's users. It\n * never leaves this module as a message: a non-2xx answer becomes an\n * `AiUpstreamError` carrying the status, whether the failure is retryable\n * and a fixed customer-safe sentence; the provider's body goes to\n * `console.error` beside the request id, where an operator can find it.\n * A `refusal` stop is not an error at all — the tokens were spent and the\n * model answered — so it comes back as a typed `AiRefusal` result.\n */\n\nexport const ANTHROPIC_PROVIDER_ID = 'anthropic'\nexport const ANTHROPIC_API_KEY_ENV = 'ANTHROPIC_API_KEY'\nconst ANTHROPIC_HOST = 'api.anthropic.com'\nconst ANTHROPIC_URL = `https://${ANTHROPIC_HOST}/v1/messages`\nconst ANTHROPIC_BATCHES_URL = `https://${ANTHROPIC_HOST}/v1/messages/batches`\nconst ANTHROPIC_VERSION = '2023-06-01'\n\n/** The Messages API accepts at most this many `cache_control` markers. */\nexport const ANTHROPIC_MAX_CACHE_BREAKPOINTS = 4\n\n/**\n * What the Messages API compiles of one request's strict schemas, as its\n * structured-outputs documentation states the limits: 20 strict tools, 24\n * optional parameters and 16 parameters with union types, each a total over\n * every strict schema the request carries. Past any of them the request is\n * refused with a 400 before the model runs.\n *\n * `compiledSchemaBytes` is not one of those. The API also refuses a request\n * whose schemas compile to too large a grammar — \"Simplify your tool schemas\n * or reduce the number of strict tools\" — and states no size for it, so this\n * bound is measured rather than read (AGL-3096). Its evidence is two live\n * requests for the automation draft, the largest strict schema anything here\n * sends:\n *\n * - 8,757 bytes, refused for grammar size (`req_011CfC6Fif9iJvmKPTRgtLdp`,\n * 2026-09-19), with 1 strict tool, 0 optional parameters and 2 unions:\n * every published count was green;\n * - 3,807 bytes, served (`req_011CfELn62WVLeaNzwK4TWgb`, 2026-09-20), the\n * same tool with the guard lifted out of the steps' union and one variant\n * per set of fields.\n *\n * Everything else the plugin sends is smaller still, the next largest being\n * the theme tool at 2,410 bytes. The bound sits at what has been served, so a\n * schema that grows past it has to be proved live before the bound moves.\n */\nexport const ANTHROPIC_TOOL_SCHEMA_LIMITS: AiToolSchemaLimits = {\n strictTools: 20,\n optionalParameters: 24,\n unionParameters: 16,\n compiledSchemaBytes: 3_807,\n}\n\n/**\n * Whether a provider failure is the kind that clears on its own. Matched on\n * the status AND the error type, because the in-stream `error` event has no\n * status to go by.\n */\nexport function anthropicFailureIsRetryable(\n status: number | null,\n errorType: string | undefined,\n): boolean {\n return (\n status === 429 ||\n status === 529 ||\n errorType === 'rate_limit_error' ||\n errorType === 'overloaded_error'\n )\n}\n\n/**\n * Whether a failure is about the platform's Anthropic account rather than the\n * request (AGL-3377): a refused key, or a balance too low to answer.\n */\nexport function anthropicAccountProblem(\n status: number | null,\n error: { type?: string; message?: string } | null | undefined,\n): AiAccountProblem | null {\n if (status === 401 || status === 403) return 'credentials'\n if (error?.type === 'authentication_error' || error?.type === 'permission_error') {\n return 'credentials'\n }\n if (error?.type === 'billing_error' || /credit balance/i.test(error?.message ?? '')) {\n return 'credit'\n }\n return null\n}\n\n/** Anthropic's `usage` object, in the meter's shape. Missing fields read 0. */\nexport function anthropicUsageFrom(usage: unknown): AiUsage {\n const record = (usage ?? {}) as Record<string, unknown>\n // Part of `output_tokens`, and carried only where the response breaks them\n // down, so an answer that reports none says nothing rather than zero.\n const details = record['output_tokens_details']\n const thinking =\n details && typeof details === 'object'\n ? (details as Record<string, unknown>)['thinking_tokens']\n : undefined\n // The writes split by lifetime (AGL-3830). Only an hour-long write is kept,\n // because it is the one billed above the rate table's write rate, and only\n // where there was one, so every five-minute exchange keeps its shape.\n const creation = record['cache_creation']\n const hour =\n creation && typeof creation === 'object'\n ? aiTokenCount((creation as Record<string, unknown>)['ephemeral_1h_input_tokens'])\n : 0\n return {\n inputTokens: aiTokenCount(record['input_tokens']),\n outputTokens: aiTokenCount(record['output_tokens']),\n cacheReadTokens: aiTokenCount(record['cache_read_input_tokens']),\n cacheWriteTokens: aiTokenCount(record['cache_creation_input_tokens']),\n ...(hour > 0 ? { cacheWriteHourTokens: hour } : {}),\n ...(thinking === undefined ? {} : { thinkingTokens: aiTokenCount(thinking) }),\n }\n}\n\n/** What an exchange draws, its hour-long cache writes included (AGL-3830). */\nfunction anthropicBilledUsd(usage: AiUsage, model: string): number {\n const usd = estimateAiBilledUsd(usage, model) + aiCacheWriteHourSurchargeUsd(usage, aiBilledRatesForModel(model))\n return Math.round(usd * 1_000_000) / 1_000_000\n}\n\n/**\n * How \"thinking off\" is said to a model that refuses `{type: \"disabled\"}`.\n * Claude Sonnet 5.5 turns it off only through `between_tools` (accepted at\n * effort high or below, which is every effort the contract names); Claude\n * Opus 5.5 cannot turn it off at all, so the field is left out and the\n * model's adaptive thinking runs. Every other model takes `disabled`.\n */\nconst ANTHROPIC_THINKING_OFF: Readonly<Record<string, 'between_tools' | 'omit'>> = {\n 'claude-sonnet-5-5': 'between_tools',\n 'claude-opus-5-5': 'omit',\n}\n\n/**\n * The effort a request that names none is sent, for a model whose own\n * default is lower than its siblings': Claude Opus 5.5 defaults to medium,\n * where Claude Opus 5 defaults to high.\n */\nconst ANTHROPIC_DEFAULT_EFFORT: Readonly<Record<string, AiEffort>> = {\n 'claude-opus-5-5': 'high',\n}\n\n/**\n * The Messages API body for a request. Exported so a spec can assert the\n * wire shape without a network. The cache-prefix rule is enforced by the\n * runtime before the request reaches any adapter; this maps the surviving\n * breakpoints onto `cache_control` and refuses only the count the API\n * itself refuses.\n */\nexport function buildAnthropicRequestBody(\n input: Omit<AiProviderRequest, 'apiKey' | 'signal'> & { stream: boolean },\n): Record<string, unknown> {\n const conversation = Boolean(input.cacheConversation) && input.messages.length > 0\n const breakpoints = input.system.filter((block) => block.cacheBreakpoint).length + (conversation ? 1 : 0)\n if (breakpoints > ANTHROPIC_MAX_CACHE_BREAKPOINTS) {\n throw new Error(\n `${breakpoints} cache breakpoints; the Messages API allows ${ANTHROPIC_MAX_CACHE_BREAKPOINTS}`,\n )\n }\n // A lifetime per breakpoint (AGL-4050): the shared prompt's markers at the\n // route's lifetime, a site's block and the conversation at five minutes,\n // and never an hour after five minutes, which the API refuses.\n const ttls = aiCacheMarkerTtls({ ...input, cacheConversation: conversation })\n const system = input.system.map((block, index) => {\n const ttl = ttls.system[index]\n return { type: 'text', text: block.text, ...(ttl ? { cache_control: anthropicCacheControl(ttl) } : {}) }\n })\n const tools = input.tools?.map((tool) => ({\n name: tool.name,\n description: tool.description,\n input_schema: { ...tool.inputSchema, additionalProperties: false },\n strict: true,\n }))\n // A model that rejects an explicit thinking setting gets none, whatever\n // the door asked for, and no effort either: effort rides the same rule\n // (see the contract), and the catalog says which models those are.\n const settable = aiCatalogEntry(input.model)?.capabilities.thinking !== false\n const thinking = settable ? input.thinking : undefined\n const effort = settable ? (input.effort ?? ANTHROPIC_DEFAULT_EFFORT[input.model]) : undefined\n const thinkingOff = ANTHROPIC_THINKING_OFF[input.model] ?? 'disabled'\n // A named tool is forced only where the model takes a forced choice and\n // thinking is sent off, which the API requires of one (AGL-4076); every\n // other request, a named one on Claude Sonnet 5.5 included, chooses for itself.\n const forced =\n input.toolChoice &&\n tools?.some((tool) => tool.name === input.toolChoice) &&\n aiCatalogEntry(input.model)?.capabilities.forcedToolChoice === true &&\n thinking === 'off' &&\n thinkingOff === 'disabled'\n ? input.toolChoice\n : null\n return {\n model: input.model,\n max_tokens: input.maxTokens,\n ...(input.stream ? { stream: true } : {}),\n ...(thinking === 'off'\n ? thinkingOff === 'omit'\n ? {}\n : { thinking: { type: thinkingOff } }\n : thinking === 'adaptive'\n ? { thinking: { type: 'adaptive' } }\n : {}),\n ...(effort ? { output_config: { effort } } : {}),\n ...(system.length ? { system } : {}),\n messages: input.messages.map((message, index) => ({\n role: message.role,\n content: conversation\n ? anthropicBlocksOf(\n message,\n index === input.messages.length - 1 && ttls.conversation ? anthropicCacheControl(ttls.conversation) : null,\n )\n : anthropicContentOf(message),\n })),\n ...(tools?.length ? { tools, tool_choice: forced ? { type: 'tool', name: forced } : { type: 'auto' } } : {}),\n }\n}\n\n/** One marker's `cache_control`: the five minutes are the API's default, so only the hour is named. */\nfunction anthropicCacheControl(ttl: AiCacheTtl): Record<string, unknown> {\n return ttl === '1h' ? { type: 'ephemeral', ttl: '1h' } : { type: 'ephemeral' }\n}\n\n/**\n * A turn's content in the Messages API's shape: a text-only turn as the\n * string it is, and a turn with pictures as content blocks in order, each\n * picture a base64 image block (AGL-2916).\n */\nfunction anthropicContentOf(message: AiMessage): string | Array<Record<string, unknown>> {\n if (typeof message.content === 'string') return message.content\n return message.content.map((part) =>\n part.type === 'image'\n ? { type: 'image', source: { type: 'base64', media_type: part.mediaType, data: part.data } }\n : { type: 'text', text: part.text },\n )\n}\n\n/**\n * A turn as content blocks whatever its shape, the last block carrying the\n * conversation's breakpoint when it is the request's last turn (AGL-3809).\n * Every turn of a request that caches its conversation is sent as blocks, so\n * a turn reads the same on the call that marked it and on every call after,\n * where it is no longer last.\n */\nfunction anthropicBlocksOf(\n message: AiMessage,\n cacheControl: Record<string, unknown> | null,\n): Array<Record<string, unknown>> {\n const content = anthropicContentOf(message)\n const blocks = typeof content === 'string' ? [{ type: 'text', text: content }] : content\n if (!cacheControl || !blocks.length) return blocks\n const last = blocks.length - 1\n return blocks.map((block, index) => (index === last ? { ...block, cache_control: cacheControl } : block))\n}\n\n/** The provider's request id, when it sent one — the log's join key. */\nfunction requestIdOf(response: Response): string | null {\n return response.headers?.get?.('request-id') ?? null\n}\n\nasync function send(\n input: AiProviderRequest,\n stream: boolean,\n): Promise<Response> {\n const body = buildAnthropicRequestBody({ ...input, stream })\n const response = await fetch(ANTHROPIC_URL, {\n method: 'POST',\n headers: {\n 'x-api-key': input.apiKey,\n 'anthropic-version': ANTHROPIC_VERSION,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n ...(input.signal ? { signal: input.signal } : {}),\n })\n if (!response.ok || (stream && !response.body)) {\n const requestId = requestIdOf(response)\n const payload = (await response.json().catch(() => null)) as {\n error?: { type?: string; message?: string }\n } | null\n console.error('ai upstream error', {\n provider: ANTHROPIC_PROVIDER_ID,\n status: response.status,\n requestId,\n model: input.model,\n error: payload?.error ?? null,\n })\n throw new AiUpstreamError(\n response.status,\n anthropicFailureIsRetryable(response.status, payload?.error?.type),\n requestId,\n anthropicAccountProblem(response.status, payload?.error),\n )\n }\n return response\n}\n\nasync function complete(input: AiProviderRequest): Promise<AiResult> {\n const response = await send(input, false)\n return anthropicResultFrom(await response.json(), input.model)\n}\n\n/**\n * A Messages API answer as the contract's result: the shape `complete` reads\n * off the wire and a batch's succeeded entry carries. `priceFactor` is what a\n * discount leaves of the price (a batch's half).\n */\nexport function anthropicResultFrom(raw: unknown, model: string, priceFactor = 1): AiResult {\n const payload = raw as {\n content?: Array<Record<string, unknown>>\n stop_reason?: unknown\n usage?: unknown\n } | null\n const blocks = Array.isArray(payload?.content) ? payload.content : []\n const text = blocks\n .filter((block) => block?.['type'] === 'text')\n .map((block) => String(block['text'] ?? ''))\n .join('')\n const toolUse: AiToolUse[] = blocks\n .filter((block) => block?.['type'] === 'tool_use')\n .map((block) => ({\n name: String(block['name'] ?? ''),\n input: aiToolInputOf(block['input']),\n }))\n const usage = anthropicUsageFrom(payload?.usage)\n const estCostUsd = Math.round(anthropicBilledUsd(usage, model) * priceFactor * 1_000_000) / 1_000_000\n const stopReason =\n typeof payload?.stop_reason === 'string' && payload.stop_reason\n ? payload.stop_reason\n : null\n if (stopReason === 'refusal') {\n return { kind: 'refusal', text, usage, estCostUsd, stopReason }\n }\n return {\n kind: 'completion',\n text,\n toolUse,\n usage,\n estCostUsd,\n stopReason,\n // The blocks as the provider answered them, for a call its ceiling cut\n // off (AGL-3143): `toolUse` holds only what still parsed out of them.\n ...(aiStoppedAtCeiling(stopReason) ? { rawOutput: aiRawOutputOf(blocks) } : {}),\n }\n}\n\nasync function stream(input: AiProviderRequest): Promise<AsyncIterable<AiStreamEvent>> {\n const response = await send(input, true)\n return streamEvents(\n response.body as ReadableStream<Uint8Array>,\n input.model,\n requestIdOf(response),\n )\n}\n\n/**\n * Anthropic's SSE stream as contract events. Usage is taken from\n * `message_start` (input and cache figures) and `message_delta` (the\n * output count, and any cumulative input figures a newer API sends); the\n * `done` event carries whatever was known when the body ended, so a stream\n * cut short still meters what it cost.\n */\nasync function* streamEvents(\n body: ReadableStream<Uint8Array>,\n model: string,\n requestId: string | null,\n): AsyncGenerator<AiStreamEvent> {\n const decoder = new TextDecoder()\n const reader = body.getReader()\n const usage: AiUsage = {\n inputTokens: 0,\n outputTokens: 0,\n cacheReadTokens: 0,\n cacheWriteTokens: 0,\n }\n let stopReason: string | null = null\n /** Tool-use blocks in flight, by content index; input arrives in pieces. */\n const tools = new Map<number, { name: string; json: string }>()\n /**\n * What each tool call was actually written in, in the order its block\n * opened (AGL-3143). The `tool` events below carry only as much of these\n * as `aiToolInputOf` could still parse, so for a call the ceiling cut off\n * this is the one place the emitted bytes survive.\n */\n const written: string[] = []\n let buffer = ''\n let drained = false\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) {\n drained = true\n break\n }\n buffer += decoder.decode(value, { stream: true })\n const lines = buffer.split('\\n')\n buffer = lines.pop() ?? ''\n for (const line of lines) {\n if (!line.startsWith('data: ')) continue\n let event: Record<string, unknown>\n try {\n event = JSON.parse(line.slice('data: '.length))\n } catch {\n continue\n }\n const index = Number(event['index'])\n switch (event['type']) {\n case 'message_start': {\n const start = anthropicUsageFrom(\n (event['message'] as { usage?: unknown } | undefined)?.usage,\n )\n usage.inputTokens = start.inputTokens\n usage.cacheReadTokens = start.cacheReadTokens\n usage.cacheWriteTokens = start.cacheWriteTokens\n if (start.cacheWriteHourTokens) usage.cacheWriteHourTokens = start.cacheWriteHourTokens\n break\n }\n case 'content_block_start': {\n const block = event['content_block'] as\n | { type?: string; name?: string }\n | undefined\n if (block?.type === 'tool_use') {\n tools.set(index, { name: String(block.name ?? ''), json: '' })\n }\n break\n }\n case 'content_block_delta': {\n const delta = event['delta'] as\n | { type?: string; text?: string; partial_json?: string }\n | undefined\n if (delta?.type === 'text_delta' && delta.text) {\n yield { type: 'delta', text: delta.text }\n } else if (delta?.type === 'input_json_delta') {\n const tool = tools.get(index)\n if (tool) tool.json += delta.partial_json ?? ''\n }\n break\n }\n case 'content_block_stop': {\n const tool = tools.get(index)\n if (tool) {\n tools.delete(index)\n written.push(tool.json)\n yield { type: 'tool', name: tool.name, input: aiToolInputOf(tool.json) }\n }\n break\n }\n case 'message_delta': {\n const delta = anthropicUsageFrom(event['usage'])\n usage.outputTokens = delta.outputTokens || usage.outputTokens\n usage.inputTokens = delta.inputTokens || usage.inputTokens\n usage.cacheReadTokens = delta.cacheReadTokens || usage.cacheReadTokens\n usage.cacheWriteTokens = delta.cacheWriteTokens || usage.cacheWriteTokens\n // Kept where the breakdown is reported and left absent where it\n // is not (AGL-3143), never set to a zero the provider did not\n // send. A stream needs it for the reason a completion does: it\n // is the figure that accounts for a spent ceiling first, and it\n // arrives in the same usage object as the four above.\n if (delta.thinkingTokens !== undefined) usage.thinkingTokens = delta.thinkingTokens\n const reason = (event['delta'] as { stop_reason?: unknown } | undefined)\n ?.stop_reason\n if (typeof reason === 'string' && reason) stopReason = reason\n break\n }\n case 'error': {\n const error = event['error'] as\n | { type?: string; message?: string }\n | undefined\n console.error('ai upstream stream error', {\n provider: ANTHROPIC_PROVIDER_ID,\n requestId,\n model,\n error: error ?? null,\n })\n yield { type: 'error', retryable: anthropicFailureIsRetryable(null, error?.type) }\n break\n }\n default:\n break\n }\n }\n }\n } finally {\n // A consumer that stops iterating early — a client that hung up — must\n // not leave the provider generating into a socket nobody reads: cancel\n // tells the upstream to stop, and the tokens it has already produced are\n // the only ones billed.\n if (!drained) await reader.cancel().catch(() => undefined)\n reader.releaseLock()\n }\n // A message the ceiling ends mid-block never reaches that block's stop\n // event, so what it had written is still held in flight.\n for (const tool of tools.values()) written.push(tool.json)\n yield {\n type: 'done',\n usage,\n estCostUsd: anthropicBilledUsd(usage, model),\n stopReason,\n // What the model emitted into its tool calls, for a stream its ceiling\n // cut off (AGL-3143): the `tool` events carry only what parsed out.\n ...(aiStoppedAtCeiling(stopReason) ? { rawOutput: aiRawOutputOf(written.join('')) } : {}),\n }\n}\n\n/** What a batch's discount leaves of a request's price. */\nexport const ANTHROPIC_BATCH_PRICE_FACTOR = 0.5\n\nfunction batchHeaders(apiKey: string): Record<string, string> {\n return {\n 'x-api-key': apiKey,\n 'anthropic-version': ANTHROPIC_VERSION,\n 'Content-Type': 'application/json',\n }\n}\n\n/** A batch call that did not answer 2xx, as the contract's error. */\nasync function batchFailure(response: Response, model: string): Promise<AiUpstreamError> {\n const requestId = requestIdOf(response)\n const payload = (await response.json().catch(() => null)) as {\n error?: { type?: string; message?: string }\n } | null\n console.error('ai upstream batch error', {\n provider: ANTHROPIC_PROVIDER_ID,\n status: response.status,\n requestId,\n model,\n error: payload?.error ?? null,\n })\n return new AiUpstreamError(\n response.status,\n anthropicFailureIsRetryable(response.status, payload?.error?.type),\n requestId,\n anthropicAccountProblem(response.status, payload?.error),\n )\n}\n\n/** The batch as its create and poll calls describe it. */\ninterface AnthropicBatch {\n id: string\n processing_status?: string\n results_url?: string | null\n}\n\n/** Results a batch can end a request with that answer nothing yet: asked again, not failed (AGL-3781). */\nconst ANTHROPIC_BATCH_UNFINISHED = new Set(['canceled', 'expired'])\n\n/**\n * Many requests through the Message Batches API (AGL-3660): created as one\n * batch, polled until it has ended, its results read by `custom_id` — they\n * come back in any order — and each turned into the result `complete` would\n * have returned, at half the price. Development only: the live evals' batch\n * mode is the one caller, and no door waits minutes for an answer.\n *\n * A batch still processing when its wait runs out is canceled, and read once\n * the cancel has ended it (AGL-3781): a cancel keeps every answer the batch\n * already has, so those come back as results, and only the requests it never\n * reached come back as `AiBatchUnfinishedError`, for the caller to ask on\n * their own. Throwing away a round's paid-for answers because one batch was\n * slow is how a whole golden run lost its grades.\n */\nasync function completeBatch(\n requests: readonly AiProviderRequest[],\n options: AiBatchOptions = {},\n): Promise<Array<AiResult | Error>> {\n if (!requests.length) return []\n const apiKey = requests[0].apiKey\n const model = requests[0].model\n const pollMs = options.pollMs ?? 10_000\n const timeoutMs = options.timeoutMs ?? 60 * 60_000\n const cancelGraceMs = options.cancelGraceMs ?? 10 * 60_000\n const unfinished = (id: string, reason: string) => requests.map(() => new AiBatchUnfinishedError(id, reason))\n const created = await fetch(ANTHROPIC_BATCHES_URL, {\n method: 'POST',\n headers: batchHeaders(apiKey),\n body: JSON.stringify({\n requests: requests.map((request, index) => {\n const { apiKey: _key, signal: _signal, ...rest } = request\n return { custom_id: `r${index}`, params: buildAnthropicRequestBody({ ...rest, stream: false }) }\n }),\n }),\n })\n if (!created.ok) throw await batchFailure(created, model)\n let batch = (await created.json()) as AnthropicBatch\n const deadline = Date.now() + timeoutMs\n let cancelDeadline: number | null = null\n while (batch.processing_status !== 'ended') {\n if (cancelDeadline === null && Date.now() >= deadline) {\n console.warn(`[ai] batch ${batch.id} has not ended after ${timeoutMs} ms; canceling it to read what it answered`)\n await fetch(`${ANTHROPIC_BATCHES_URL}/${batch.id}/cancel`, { method: 'POST', headers: batchHeaders(apiKey) }).catch(\n () => undefined,\n )\n cancelDeadline = Date.now() + cancelGraceMs\n }\n // A cancel that never ends leaves no results to read; every request goes back unanswered.\n if (cancelDeadline !== null && Date.now() >= cancelDeadline) return unfinished(batch.id, 'cancel did not end')\n await new Promise((resolve) => setTimeout(resolve, pollMs))\n const polled = await fetch(`${ANTHROPIC_BATCHES_URL}/${batch.id}`, { headers: batchHeaders(apiKey) })\n if (!polled.ok) throw await batchFailure(polled, model)\n batch = (await polled.json()) as AnthropicBatch\n }\n if (!batch.results_url) {\n if (cancelDeadline !== null) return unfinished(batch.id, 'canceled with no results')\n throw new Error(`batch ${batch.id} ended with no results`)\n }\n const results = await fetch(batch.results_url, { headers: batchHeaders(apiKey) })\n if (!results.ok) throw await batchFailure(results, model)\n const byId = new Map<string, { type?: string; message?: unknown; error?: unknown }>()\n for (const line of (await results.text()).split('\\n')) {\n if (!line.trim()) continue\n const entry = JSON.parse(line) as { custom_id: string; result?: { type?: string; message?: unknown; error?: unknown } }\n byId.set(entry.custom_id, entry.result ?? {})\n }\n return requests.map((request, index) => {\n const result = byId.get(`r${index}`)\n if (result?.type === 'succeeded') {\n return anthropicResultFrom(result.message, request.model, ANTHROPIC_BATCH_PRICE_FACTOR)\n }\n const type = result?.type ?? 'missing'\n if (ANTHROPIC_BATCH_UNFINISHED.has(type) || type === 'missing') return new AiBatchUnfinishedError(batch.id, type)\n console.error('ai batch request not answered', {\n provider: ANTHROPIC_PROVIDER_ID,\n batchId: batch.id,\n customId: `r${index}`,\n result: type,\n error: result?.error ?? null,\n })\n return new AiUpstreamError(null, type === 'errored', batch.id, null)\n })\n}\n\nexport const anthropicProvider: AiProvider = {\n id: ANTHROPIC_PROVIDER_ID,\n label: 'Anthropic',\n apiKeyEnv: ANTHROPIC_API_KEY_ENV,\n readApiKey: () => process.env.ANTHROPIC_API_KEY?.trim() || undefined,\n endpointHost: ANTHROPIC_HOST,\n toolSchemaLimits: ANTHROPIC_TOOL_SCHEMA_LIMITS,\n models(): readonly AiModelDescriptor[] {\n return aiModelIdsForProvider(ANTHROPIC_PROVIDER_ID)\n .map((id) => aiCatalogEntry(id))\n .filter((entry): entry is NonNullable<typeof entry> => Boolean(entry))\n },\n complete,\n stream,\n completeBatch,\n}\n"],"names":["aiBilledRatesForModel","aiCatalogEntry","aiModelIdsForProvider","estimateAiBilledUsd","aiCacheWriteHourSurchargeUsd","AiBatchUnfinishedError","AiUpstreamError","aiCacheMarkerTtls","aiRawOutputOf","aiStoppedAtCeiling","aiTokenCount","aiToolInputOf","ANTHROPIC_PROVIDER_ID","ANTHROPIC_API_KEY_ENV","ANTHROPIC_HOST","ANTHROPIC_URL","ANTHROPIC_BATCHES_URL","ANTHROPIC_VERSION","ANTHROPIC_MAX_CACHE_BREAKPOINTS","ANTHROPIC_TOOL_SCHEMA_LIMITS","strictTools","optionalParameters","unionParameters","compiledSchemaBytes","anthropicFailureIsRetryable","status","errorType","anthropicAccountProblem","error","type","test","message","anthropicUsageFrom","usage","record","details","thinking","undefined","creation","hour","inputTokens","outputTokens","cacheReadTokens","cacheWriteTokens","cacheWriteHourTokens","thinkingTokens","anthropicBilledUsd","model","usd","Math","round","ANTHROPIC_THINKING_OFF","ANTHROPIC_DEFAULT_EFFORT","buildAnthropicRequestBody","input","conversation","Boolean","cacheConversation","messages","length","breakpoints","system","filter","block","cacheBreakpoint","Error","ttls","map","index","ttl","text","cache_control","anthropicCacheControl","tools","tool","name","description","input_schema","inputSchema","additionalProperties","strict","settable","capabilities","effort","thinkingOff","forced","toolChoice","some","forcedToolChoice","max_tokens","maxTokens","stream","output_config","role","content","anthropicBlocksOf","anthropicContentOf","tool_choice","part","source","media_type","mediaType","data","cacheControl","blocks","last","requestIdOf","response","headers","get","send","body","fetch","method","apiKey","JSON","stringify","signal","ok","payload","requestId","json","catch","console","provider","complete","anthropicResultFrom","raw","priceFactor","Array","isArray","String","join","toolUse","estCostUsd","stopReason","stop_reason","kind","rawOutput","streamEvents","decoder","TextDecoder","reader","getReader","Map","written","buffer","drained","lines","done","value","read","decode","split","pop","line","startsWith","event","parse","slice","Number","start","set","delta","partial_json","delete","push","reason","retryable","cancel","releaseLock","values","ANTHROPIC_BATCH_PRICE_FACTOR","batchHeaders","batchFailure","ANTHROPIC_BATCH_UNFINISHED","Set","completeBatch","requests","options","pollMs","timeoutMs","cancelGraceMs","unfinished","id","created","request","_key","_signal","rest","custom_id","params","batch","deadline","Date","now","cancelDeadline","processing_status","warn","Promise","resolve","setTimeout","polled","results_url","results","byId","entry","trim","result","has","batchId","customId","anthropicProvider","label","apiKeyEnv","readApiKey","process","env","ANTHROPIC_API_KEY","endpointHost","toolSchemaLimits","models"],"mappings":"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"}
|
|
@@ -133,7 +133,8 @@ export const AI_MODEL_CATALOG = [
|
|
|
133
133
|
// `aiDefaultModelFor` answers, so Free, "Auto" and every step routed to
|
|
134
134
|
// balanced run here. Rejects `thinking: {type: "disabled"}` and forced
|
|
135
135
|
// tool choice: the adapter sends thinking off as `between_tools` and
|
|
136
|
-
// every tool call with `tool_choice: auto
|
|
136
|
+
// every tool call with `tool_choice: auto`, a request's `toolChoice`
|
|
137
|
+
// included (no `forcedToolChoice`, AGL-4076).
|
|
137
138
|
id: 'claude-sonnet-5-5',
|
|
138
139
|
provider: ANTHROPIC,
|
|
139
140
|
label: 'Claude Sonnet 5.5',
|
|
@@ -169,7 +170,9 @@ export const AI_MODEL_CATALOG = [
|
|
|
169
170
|
id: 'claude-sonnet-5',
|
|
170
171
|
provider: ANTHROPIC,
|
|
171
172
|
label: 'Claude Sonnet 5',
|
|
172
|
-
capabilities: anthropicCapabilities,
|
|
173
|
+
capabilities: _extends({}, anthropicCapabilities, {
|
|
174
|
+
forcedToolChoice: true
|
|
175
|
+
}),
|
|
173
176
|
providerRates: aiRatesPerMTok(2, 10),
|
|
174
177
|
billedRates: aiRatesPerMTok(3, 15),
|
|
175
178
|
tier: 'balanced',
|
|
@@ -180,7 +183,9 @@ export const AI_MODEL_CATALOG = [
|
|
|
180
183
|
id: 'claude-sonnet-4-6',
|
|
181
184
|
provider: ANTHROPIC,
|
|
182
185
|
label: 'Claude Sonnet 4.6',
|
|
183
|
-
capabilities: anthropicCapabilities
|
|
186
|
+
capabilities: _extends({}, anthropicCapabilities, {
|
|
187
|
+
forcedToolChoice: true
|
|
188
|
+
})
|
|
184
189
|
}, aiRatesAtList(3, 15), {
|
|
185
190
|
tier: 'balanced',
|
|
186
191
|
cacheMinTokens: 1024
|
|
@@ -228,7 +233,9 @@ export const AI_MODEL_CATALOG = [
|
|
|
228
233
|
id: 'claude-opus-5',
|
|
229
234
|
provider: ANTHROPIC,
|
|
230
235
|
label: 'Claude Opus 5',
|
|
231
|
-
capabilities: anthropicCapabilities
|
|
236
|
+
capabilities: _extends({}, anthropicCapabilities, {
|
|
237
|
+
forcedToolChoice: true
|
|
238
|
+
})
|
|
232
239
|
}, aiRatesAtList(5, 25), {
|
|
233
240
|
tier: 'deep',
|
|
234
241
|
cacheMinTokens: 512
|
|
@@ -251,7 +258,9 @@ export const AI_MODEL_CATALOG = [
|
|
|
251
258
|
id: 'claude-opus-4-8',
|
|
252
259
|
provider: ANTHROPIC,
|
|
253
260
|
label: 'Claude Opus 4.8',
|
|
254
|
-
capabilities: anthropicCapabilities
|
|
261
|
+
capabilities: _extends({}, anthropicCapabilities, {
|
|
262
|
+
forcedToolChoice: true
|
|
263
|
+
})
|
|
255
264
|
}, aiRatesAtList(5, 25), {
|
|
256
265
|
tier: 'deep',
|
|
257
266
|
cacheMinTokens: 1024
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/providers/catalog.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 { PluginSubprocessorDeclaration } from '@aglyn/aglyn/plugin-manager/plugin-subprocessors'\nimport type { AiModelDescriptor, AiUsage } from './contract'\nimport type { AiImageSize } from './image-contract'\n\n/**\n * The model catalog (AGL-2939): every model id the plugin will route to,\n * with its provider, its display name, its capabilities and its list rates.\n * The ONE place a model id is written outside a provider adapter — the\n * routing table maps a step kind to an id through here, the meter prices\n * usage by id through here, and a settings form offers ids from here.\n *\n * ## Two rates, because one figure was answering two questions\n *\n * Every row carries a PROVIDER rate and a BILLED rate (AGL-3015):\n *\n * - `providerRates` is what the vendor charges us. It is money leaving the\n * company, so cost accounting, the margin surfaces and every staff spend\n * meter price usage through this one and no other.\n * - `billedRates` is what a customer's credits are charged at. The credit\n * meter, the band, the overage ladder and the model selector price usage\n * through this one, because it is the figure a customer's balance moves by.\n *\n * They are equal on nearly every row, and a helper writes the pair from one\n * figure so an unmarked row cannot drift apart by a typo. A row may be\n * billed ABOVE its provider rate deliberately — the markup is carried in the\n * rate rather than in the credit conversion, which keeps a credit a fixed\n * quantity of billed spend on every model and leaves the band, the ladder\n * and the invoice on the one arithmetic they were sized with. A row billed\n * BELOW its provider rate would sell tokens at a loss, and\n * `billed-rate-is-not-provider-cost.spec.ts` refuses one.\n *\n * Both are keyed by model rather than fixed at one model's rates because the\n * default is an env override: a one-line incident swap to a dearer model\n * would otherwise keep reporting the cheaper money, and per-org cost would\n * read as roughly right — the failure mode this whole meter exists to\n * prevent. An unknown id falls back to the most EXPENSIVE known tier on\n * purpose, on both rates: an estimate that errs low is worse than one that\n * errs high, whether the figure is our bill or the customer's.\n */\n\nexport interface AiTokenRates {\n inputPerToken: number\n outputPerToken: number\n cacheReadPerToken: number\n cacheWritePerToken: number\n}\n\n/** List price per MTok → per-token rates, cache read at 0.1x, write 1.25x. */\nexport function aiRatesPerMTok(inputPerMTok: number, outputPerMTok: number): AiTokenRates {\n return {\n inputPerToken: inputPerMTok / 1_000_000,\n outputPerToken: outputPerMTok / 1_000_000,\n cacheReadPerToken: (inputPerMTok * 0.1) / 1_000_000,\n cacheWritePerToken: (inputPerMTok * 1.25) / 1_000_000,\n }\n}\n\n/**\n * The two rate tables a catalog row carries. Separate fields rather than one\n * table and a multiplier: a reader that wants our cost has to name it, and\n * a reader that wants the customer's has to name that, so neither can be\n * reached by accident.\n */\nexport interface AiCatalogRates {\n /** What the provider bills us for this model. */\n providerRates: AiTokenRates\n /** What a customer's credits are charged at for this model. */\n billedRates: AiTokenRates\n}\n\n/**\n * A row billed at exactly the provider's list rate — the usual case, written\n * once so the pair cannot drift.\n */\nexport function aiRatesAtList(\n inputPerMTok: number,\n outputPerMTok: number,\n): AiCatalogRates {\n return {\n providerRates: aiRatesPerMTok(inputPerMTok, outputPerMTok),\n billedRates: aiRatesPerMTok(inputPerMTok, outputPerMTok),\n }\n}\n\n/**\n * THE PLATFORM'S MARKUP over provider cost (AGL-3781): what a customer's\n * credits are charged for a model over what the model costs us, on every\n * figure. The balanced tier's list (Sonnet, $3 / $15 billed over $2 / $10),\n * a picture and the fast tier are billed at it, so a credit carries the same\n * margin whichever of them it is spent on.\n */\nexport const AI_BILLED_MARKUP = 1.5\n\n/** `rates` at the platform's markup: every figure times {@link AI_BILLED_MARKUP}. */\nexport function aiRatesMarkedUp(rates: AiTokenRates): AiTokenRates {\n return {\n inputPerToken: rates.inputPerToken * AI_BILLED_MARKUP,\n outputPerToken: rates.outputPerToken * AI_BILLED_MARKUP,\n cacheReadPerToken: rates.cacheReadPerToken * AI_BILLED_MARKUP,\n cacheWritePerToken: rates.cacheWritePerToken * AI_BILLED_MARKUP,\n }\n}\n\n/** A row billed at the platform's markup over the provider's list price per MTok. */\nexport function aiRatesAtMarkup(inputPerMTok: number, outputPerMTok: number): AiCatalogRates {\n const providerRates = aiRatesPerMTok(inputPerMTok, outputPerMTok)\n return { providerRates, billedRates: aiRatesMarkedUp(providerRates) }\n}\n\n/** {@link aiRatesAtList} for a model whose cache read is not a tenth of its input price. */\nexport function aiRatesAtListWithCacheRead(\n inputPerMTok: number,\n outputPerMTok: number,\n cacheReadPerMTok: number,\n): AiCatalogRates {\n const rates = { ...aiRatesPerMTok(inputPerMTok, outputPerMTok), cacheReadPerToken: cacheReadPerMTok / 1_000_000 }\n return { providerRates: rates, billedRates: { ...rates } }\n}\n\nexport interface AiCatalogEntry extends AiModelDescriptor, AiCatalogRates {\n /**\n * The tier a routing decision reads: `fast` for short, constrained\n * answers; `balanced` for the assistant and briefs; `deep` for the\n * dearest, slowest class.\n */\n tier: 'fast' | 'balanced' | 'deep'\n /**\n * The shortest prefix this model's provider will cache (AGL-2937). A\n * request whose cached span falls under it is served with the markers\n * honored and NOTHING cached: no error, no warning, and a usage report\n * that reads as a permanent cache miss.\n *\n * It is a property of the model rather than of the tier or the vendor,\n * and it does not fall as a generation advances — so the number has to be\n * written beside the model, and a door that means to cache has to be held\n * to it (`aiCachedPrefixCaches` in the runtime, and the door table in\n * `runtime/ai-prompt-cache.spec.ts`). Without it, \"this block carries a\n * breakpoint\" is a claim nothing checks, and a prompt can be designed\n * around a cache it never had.\n */\n cacheMinTokens: number\n /**\n * A RETIRED row names the model that serves in its place (AGL-3781). The\n * row stays so usage recorded under its id keeps its price, but nothing\n * offers it or routes to it: a setting, an environment override or a pick\n * that names it is served by the successor, so one model per tier holds\n * the tier's traffic and its one cache namespace.\n */\n successor?: string\n}\n\n/**\n * The sentinels a docs-only answer is metered under (AGL-2486): not\n * models, but ids the meter sees, priced at zero so a deflected turn lands\n * in the same rollup as a served one and a keyless deployment does not\n * read as the most efficient one on the platform.\n */\nexport const AI_METER_SENTINELS = {\n docsRetrieval: 'docs-retrieval',\n docsLinks: 'docs-links',\n answerCache: 'assist-cache',\n} as const\n\nconst ANTHROPIC = 'anthropic'\nconst OPENAI_COMPATIBLE = 'openai-compatible'\n\n/**\n * A provider's row on the published subprocessor list: every field but the\n * host, which the registered adapter reports as its `endpointHost`.\n * `{apiKeyEnv}` anywhere in the wording stands for the adapter's\n * `apiKeyEnv`, so a credential's name is written in its adapter alone and\n * never in this module, which the browser bundle carries.\n */\nexport type AiProviderSubprocessorWording = Omit<PluginSubprocessorDeclaration, 'host'>\n\n/** A provider the catalog carries models for. */\nexport interface AiCatalogProvider {\n id: string\n /** The name a settings form shows. */\n label: string\n /**\n * The vendor's row on the published subprocessor list, written here and\n * nowhere else: `aiSubprocessors` derives the plugin's declarations from\n * it. Absent for a provider whose endpoint an operator names, which has\n * no fixed recipient to publish.\n */\n subprocessor?: AiProviderSubprocessorWording\n}\n\n/**\n * The Anthropic row's data cell up to its CRM sentence: every door but CRM\n * assistance, worded once for both of the CRM sentences below.\n */\nconst ANTHROPIC_DATA_RECEIVED_LEAD =\n \"What the user submits — a question, instruction or brief, with the earlier messages of the same Assist conversation — and the content of the element, post, section or page being worked on, with the generated response. On Pro and above, the organization's name and the console route and host travel with an Assist question. For an edit the assistant proposes in the besigner, an outline of the open page, component or layout: element and component ids, layer names, shortened setting values and the selected element's styles. For a generation job, the site inventory: the names and addresses of its pages and collections, the names of its components, layouts, templates, forms and datasets with their prop and field names, and the theme's summary, colors and fonts. For a theme change, the site's current theme settings and brand colors as hex values, from the organization's brand settings, the site logo in the media library or a public page the brief links to. For features that review or write search information, the text and structure of the pages concerned. For product copy, the store's name, the product's name, type, description, tags, options and search listing, the store's category names, and the product's first media-library photo as a copy at most 768 px on its longer edge with its metadata stripped; never another media file, a price, stock, an order or a customer. For products, categories and discounts proposed from a brief, the store's name and its existing category names. For an automation drafted from a brief, which of CRM, webhooks and bookings the plan includes; for an explanation, the automation's outline (trigger, conditions, each step's text with the names of the lists, campaigns, workflows, webhooks and datasets it uses and whether each exists, and a workflow's function names and expressions) and, for a failed run, its time, steps and recorded errors, with email addresses removed and never the triggering event's data. For an insight, the figure reports available and aggregate tables: traffic with top page paths, referrers and campaign tags; form views and submissions; revenue, orders and best-selling product names; bookings by service; campaign subjects with delivery, open and click rates; A/B test and variant conversions; and, for a dataset the member can see, field names and types, record and fill counts, number ranges and totals grouped by a value at least three records share. Email addresses and phone numbers are removed, and no individual record is sent. \"\n\n/** What every CRM door adds after its record sentence: drafts and imports. */\nconst ANTHROPIC_DATA_RECEIVED_CRM_DRAFTS_AND_IMPORTS =\n \"An email draft adds the request and the record's merge field names; an import sends the field names and types and each column's header and value kind, never a row.\"\n\n/** How the data cell words CRM assistance: what a record sends, and what never leaves. */\nexport interface AnthropicCrmAssistanceWording {\n record: string\n never: string\n}\n\n/**\n * CRM assistance once the whole record is sent (AGL-3520): the open-ended\n * wording the Subprocessors row and Privacy Policy section 2 were\n * republished with on October 5, 2026 (legal v10), before\n * `release_crm_assist_whole_record` may be turned on. The catalog row below\n * carries it in `dataReceived`.\n */\nexport const ANTHROPIC_CRM_ASSISTANCE_WHOLE_RECORD: AnthropicCrmAssistanceWording = {\n record:\n 'For CRM assistance, the opened record as the CRM shows it, with all of its standard and custom fields, including contact details, notes, timeline and related records.',\n never: 'No account identifiers or authentication tokens, and no email address outside an opened CRM record.',\n}\n\n/** The Anthropic row's data cell, with CRM assistance worded as `crm` words it. */\nexport function anthropicDataReceived(crm: AnthropicCrmAssistanceWording): string {\n return `${ANTHROPIC_DATA_RECEIVED_LEAD}${crm.record} ${ANTHROPIC_DATA_RECEIVED_CRM_DRAFTS_AND_IMPORTS} ${crm.never}`\n}\n\n/**\n * The providers the catalog carries models for, with the name a settings\n * form shows. A form offers providers from here for the reason it offers\n * models from here: nothing outside this folder names a vendor. For the\n * same reason a vendor's subprocessor row is written here too.\n */\nexport const AI_CATALOG_PROVIDERS: readonly AiCatalogProvider[] = [\n {\n id: ANTHROPIC,\n label: 'Anthropic',\n subprocessor: {\n entity: 'Anthropic, PBC',\n region: 'United States',\n purpose:\n \"AI features of the Services, including the Aglyn Assist helper: creating, editing and reviewing content, drafts and settings for a customer’s site, store and CRM, and explaining and summarizing the customer’s own setup and data\",\n publishedOn: '2026-10-07',\n reason:\n \"Reached through the AI plugin's Anthropic adapter (`libs/plugins/ai/src/lib/providers/anthropic.ts`) by the doors that call the AI runtime. `libs/plugins/ai/src/lib/server/assist-chat.ts` is gated by `release_assist` AND the key, and a generation job's text step by `release_ai_generative`; `libs/plugins/ai/src/lib/server/ai-assist.ts` carries NO release flag, so setting `{apiKeyEnv}` in production is by itself what starts this flow. `assist-anthropic-subprocessor-gate.spec.ts` holds the per-door detail and is the deeper guard for this one vendor.\",\n dataReceived: anthropicDataReceived(ANTHROPIC_CRM_ASSISTANCE_WHOLE_RECORD),\n },\n },\n { id: OPENAI_COMPATIBLE, label: 'OpenAI-compatible endpoint' },\n]\n\n/**\n * `vision` is written on every row rather than assumed (AGL-2916): each model\n * below reads a picture in a user turn, in the four formats\n * `AI_IMAGE_MEDIA_TYPES` names, as its vendor documents. A row added without\n * it reads as a model that does not, and is never sent one.\n */\nconst anthropicCapabilities = {\n streaming: true,\n tools: true,\n thinking: true,\n promptCache: true,\n vision: true,\n}\n\nexport const AI_MODEL_CATALOG: readonly AiCatalogEntry[] = [\n {\n // THE BALANCED TIER'S DEFAULT (AGL-3660): the first balanced row is what\n // `aiDefaultModelFor` answers, so Free, \"Auto\" and every step routed to\n // balanced run here. Rejects `thinking: {type: \"disabled\"}` and forced\n // tool choice: the adapter sends thinking off as `between_tools` and\n // every tool call with `tool_choice: auto`.\n id: 'claude-sonnet-5-5',\n provider: ANTHROPIC,\n label: 'Claude Sonnet 5.5',\n capabilities: anthropicCapabilities,\n /*\n * THE ROWS BILLED ABOVE THEIR PROVIDER RATE (AGL-3015).\n *\n * The balanced tier prices most requests, so this markup is most of the\n * platform's AI margin. It is carried in the rate and not in the credit\n * conversion for the reason the module head gives: a credit stays a\n * fixed quantity of billed spend on every model, so the band, the\n * overage ladder and the invoice keep the arithmetic they were sized\n * with, and nothing below has to know which model served a request.\n *\n * Everything that reasons about what we PAY — the margin surfaces, the\n * staff spend meters, the discount guardrail's cost of goods — reads\n * `providerRates`, which is the vendor's published list. Sonnet 5.5's\n * list is Sonnet 5's, except a cache read: $0.10/MTok, a twentieth of\n * input. A customer is billed exactly what Sonnet 5 billed, so the\n * balanced tier's prices do not move when its default does.\n */\n providerRates: { ...aiRatesPerMTok(2, 10), cacheReadPerToken: 0.1 / 1_000_000 },\n billedRates: aiRatesPerMTok(3, 15),\n tier: 'balanced',\n cacheMinTokens: 512,\n },\n {\n // The balanced default until AGL-3660, retired to Sonnet 5.5 (AGL-3781):\n // the same price, a cache read half as dear, and a cache namespace of\n // its own that every request on it split the tier's prefixes into. Kept\n // so the usage and recordings that name it still price at its rates.\n id: 'claude-sonnet-5',\n provider: ANTHROPIC,\n label: 'Claude Sonnet 5',\n capabilities: anthropicCapabilities,\n providerRates: aiRatesPerMTok(2, 10),\n billedRates: aiRatesPerMTok(3, 15),\n tier: 'balanced',\n cacheMinTokens: 1_024,\n successor: 'claude-sonnet-5-5',\n },\n {\n id: 'claude-sonnet-4-6',\n provider: ANTHROPIC,\n label: 'Claude Sonnet 4.6',\n capabilities: anthropicCapabilities,\n ...aiRatesAtList(3, 15),\n tier: 'balanced',\n cacheMinTokens: 1_024,\n },\n {\n // THE FAST TIER'S DEFAULT (AGL-3781): the first fast row, so every step\n // routed to fast, a Free site's plan and look, and a page's listing run\n // here. Thinking is adaptive and ON when a request names none, so each\n // fast route says what it wants (`providers/routing.ts`); it accepts\n // `disabled` at effort high or below, refuses budgets, sampling\n // parameters and an assistant prefill, which no door sends, and has no\n // server-side fallback, which none asks for.\n //\n // The provider list is $0.10 / $0.50 for a prompt of 100,000 tokens or\n // fewer and five times that above it; no door sends a prompt near it.\n // Billed at the platform's markup on every figure, $0.15 / $0.75, as the\n // balanced tier and pictures are: Haiku 4.5 was billed at its cost, with\n // no margin at all. Its tokenizer counts the same text as about 30% more\n // tokens than Haiku 4.5's, which the credit figures derived from it say.\n id: 'claude-haiku-5-5',\n provider: ANTHROPIC,\n label: 'Claude Haiku 5.5',\n capabilities: anthropicCapabilities,\n ...aiRatesAtMarkup(0.1, 0.5),\n tier: 'fast',\n cacheMinTokens: 512,\n },\n {\n // The fast default until AGL-3781, retired to Haiku 5.5. Rejects an\n // explicit `thinking` setting; the runtime omits it.\n id: 'claude-haiku-4-5',\n provider: ANTHROPIC,\n label: 'Claude Haiku 4.5',\n capabilities: { ...anthropicCapabilities, thinking: false },\n ...aiRatesAtList(1, 5),\n tier: 'fast',\n // Four times the balanced tier's minimum: the cheapest model per token\n // was the hardest one to cache for, so no fast-tier prompt ever cached.\n cacheMinTokens: 4_096,\n successor: 'claude-haiku-5-5',\n },\n {\n id: 'claude-opus-5',\n provider: ANTHROPIC,\n label: 'Claude Opus 5',\n capabilities: anthropicCapabilities,\n ...aiRatesAtList(5, 25),\n tier: 'deep',\n cacheMinTokens: 512,\n },\n {\n // Listed for a side-by-side comparison (AGL-3660); the deep tier's\n // default stays claude-opus-5 above. Thinking cannot be disabled and its\n // effort defaults to medium, so the adapter omits thinking where a step\n // asks for it off and names effort high where a step names none — Opus\n // 5's own default. Forced tool choice is refused; the adapter sends auto.\n id: 'claude-opus-5-5',\n provider: ANTHROPIC,\n label: 'Claude Opus 5.5',\n capabilities: anthropicCapabilities,\n // At list, like its deep-tier siblings. A cache read is $0.20/MTok, a\n // twentieth of input rather than the usual tenth.\n ...aiRatesAtListWithCacheRead(4, 20, 0.2),\n tier: 'deep',\n cacheMinTokens: 512,\n },\n {\n id: 'claude-opus-4-8',\n provider: ANTHROPIC,\n label: 'Claude Opus 4.8',\n capabilities: anthropicCapabilities,\n ...aiRatesAtList(5, 25),\n tier: 'deep',\n cacheMinTokens: 1_024,\n },\n /**\n * The OpenAI-compatible adapter serves whatever the endpoint behind\n * `AI_OPENAI_COMPAT_BASE_URL` serves; these are the ids the routing table\n * may name on it. The figures are the vendor's public list, billed at\n * list: a deployment that reaches its own gateway at a negotiated price\n * is paying less than this says, so its margin reads low rather than\n * high — the direction a cost figure may be wrong in.\n */\n {\n id: 'gpt-5',\n provider: OPENAI_COMPATIBLE,\n label: 'GPT-5',\n capabilities: { streaming: true, tools: true, thinking: false, promptCache: true, vision: true },\n ...aiRatesAtList(1.25, 10),\n tier: 'balanced',\n cacheMinTokens: 1_024,\n },\n {\n id: 'gpt-5-mini',\n provider: OPENAI_COMPATIBLE,\n label: 'GPT-5 mini',\n capabilities: { streaming: true, tools: true, thinking: false, promptCache: true, vision: true },\n ...aiRatesAtList(0.25, 2),\n tier: 'fast',\n cacheMinTokens: 1_024,\n },\n]\n\n/**\n * The IMAGE models (AGL-3602): every model id the Media library's \"Create\n * with AI\" photo mode may route to — Google's Gemini image models on Vertex\n * AI — with a per-picture provider rate and a per-picture billed rate, and the\n * token rates the same request's prompt and thinking are billed at. Kept\n * apart from `AI_MODEL_CATALOG` because nothing that lists text models — the\n * model selector, the routing table, the allotments' allowlists — may ever\n * offer one of these for a conversation.\n *\n * ## The rates\n *\n * Google prices an output picture as image-output tokens: Gemini 3.1 Flash\n * Image writes a 1K picture as 1,120 tokens at $60 per million on the global\n * endpoint, so $0.0672 a picture. Its prompt is input tokens ($0.50 per\n * million) and its thinking is text output ($3.00 per million). Every figure\n * here is the global endpoint's list price, read from Google's Vertex AI\n * pricing page on 2026-10-06; a regional endpoint lists 10% higher, so a\n * deployment that moves off `global` reads its cost low by that much.\n *\n * Every billed figure is the provider figure at `AI_BILLED_MARKUP`:\n * the same ratio the balanced text tier is billed at over its provider rate\n * (Claude Sonnet 5, $3/$15 billed over $2/$10), so a credit buys the same\n * share of margin whether it is spent on words or on pictures. A picture is\n * NEVER billed at provider cost; `billed-rate-is-not-provider-cost.spec.ts`\n * refuses a row that is.\n *\n * A credit is $0.001 of billed spend (`ASSIST_CREDIT_COST_USD`), so the\n * default model's picture is 101 credits before its prompt and thinking.\n *\n * Every per-picture figure on a row is the 1K picture's. A 512 px picture —\n * what the Free plan makes — is written as fewer image tokens at the same\n * per-token rate (`AI_IMAGE_SIZE_OUTPUT_TOKENS`), so it is priced at the 1K\n * figure scaled by its share of tokens: $0.04482 from the provider and\n * $0.06723 billed on the default model, before its prompt and thinking.\n */\nexport interface AiImageCatalogEntry extends AiCatalogRates {\n id: string\n /** The image provider the model is served by. */\n provider: string\n label: string\n /** What the provider bills us for one generated picture. */\n providerUsdPerImage: number\n /** What one picture draws from a customer's credits. */\n billedUsdPerImage: number\n}\n\n/**\n * An image row's four figures from Google's list prices — USD per output\n * picture, and USD per million input and text-output tokens — each billed at\n * the platform's markup, `AI_BILLED_MARKUP`, so an image row cannot be written\n * at list by accident.\n */\nexport function aiImageRatesAtMarkup(\n providerUsdPerImage: number,\n inputPerMTok: number,\n outputPerMTok: number,\n): Pick<\n AiImageCatalogEntry,\n 'providerUsdPerImage' | 'billedUsdPerImage' | 'providerRates' | 'billedRates'\n> {\n return {\n providerUsdPerImage,\n billedUsdPerImage: roundUsd(providerUsdPerImage * AI_BILLED_MARKUP),\n ...aiRatesAtMarkup(inputPerMTok, outputPerMTok),\n }\n}\n\n/**\n * The image-output tokens Google writes a picture as, by size (AGL-3602),\n * read from the usage of real Gemini 3.1 Flash Image answers on 2026-10-07:\n * 747 at 512 px and 1,120 at 1K. A row's per-picture figures are the 1K\n * picture's; a 512 px picture is priced at its share of them.\n */\nexport const AI_IMAGE_SIZE_OUTPUT_TOKENS: Readonly<Record<AiImageSize, number>> = {\n '512': 747,\n '1K': 1_120,\n}\n\n/** A 1K per-picture figure at `size`, by the size's share of image tokens. */\nfunction atImageSize(usdAt1K: number, size: AiImageSize | undefined): number {\n const tokens = AI_IMAGE_SIZE_OUTPUT_TOKENS[size ?? '1K'] ?? AI_IMAGE_SIZE_OUTPUT_TOKENS['1K']\n return roundUsd((usdAt1K * tokens) / AI_IMAGE_SIZE_OUTPUT_TOKENS['1K'])\n}\n\n/** The image model a photo is made with when the operator names none. */\nexport const AI_IMAGE_DEFAULT_MODEL = 'gemini-3.1-flash-image'\n\n/** The image provider's id: Google's models on Vertex AI. */\nexport const AI_IMAGE_VERTEX_PROVIDER_ID = 'google-vertex'\n\n/**\n * The image providers' rows on the published subprocessor list, kept apart\n * from `AI_CATALOG_PROVIDERS` for the reason the image catalog is kept apart\n * from the text one: a settings form offers text providers from that list,\n * and an image provider answers no conversation. The host is the adapter's\n * published endpoint (`VERTEX_IMAGE_PUBLISHED_HOST`).\n *\n * Google's row is dated to its change-log entry on `/legal/subprocessors`,\n * published with the Privacy Policy §2 sentence naming Google for image\n * generation (legal v12).\n */\nexport const AI_IMAGE_CATALOG_PROVIDERS: readonly AiCatalogProvider[] = [\n {\n id: AI_IMAGE_VERTEX_PROVIDER_ID,\n label: 'Google Vertex AI',\n subprocessor: {\n entity: 'Google LLC (Google Cloud Vertex AI)',\n // The global endpoint, which Google documents as routing and\n // processing a request anywhere in the world, with no data residency\n // guarantee: Google, not Aglyn, chooses the location.\n region: 'Global — Google selects where requests are processed',\n purpose:\n \"AI image generation: creating images for a customer's media library from a description a user writes\",\n publishedOn: '2026-10-08',\n reason:\n \"Reached through the AI plugin's Vertex AI image adapter (`libs/plugins/ai/src/lib/providers/vertex-image.ts`) by the Media library's Create with AI door (`libs/plugins/ai/src/lib/server/ai-media-image.ts`) for every kind that is not drawn as SVG, as the platform's own service account. Off unless `AI_IMAGE_VERTEX_PROJECT` names a Google Cloud project; the console offers those kinds only where `NEXT_PUBLIC_AI_IMAGE_PHOTOS` is `on`. The request carries the description and the kind's fixed style wording, the shape and fixed settings, and nothing else.\",\n dataReceived:\n \"The description the user writes and the shape requested, and the generated image returned. No account identifiers, email addresses, or other content of the customer's site.\",\n },\n },\n]\n\nexport const AI_IMAGE_MODEL_CATALOG: readonly AiImageCatalogEntry[] = [\n {\n // The default: Google's own replacement for Imagen 4, which Vertex AI\n // discontinued in 2026.\n id: 'gemini-3.1-flash-image',\n provider: AI_IMAGE_VERTEX_PROVIDER_ID,\n label: 'Gemini 3.1 Flash Image',\n ...aiImageRatesAtMarkup(0.0672, 0.5, 3),\n },\n {\n id: 'gemini-3.1-flash-lite-image',\n provider: AI_IMAGE_VERTEX_PROVIDER_ID,\n label: 'Gemini 3.1 Flash-Lite Image',\n ...aiImageRatesAtMarkup(0.0336, 0.25, 1.5),\n },\n {\n id: 'gemini-3-pro-image',\n provider: AI_IMAGE_VERTEX_PROVIDER_ID,\n label: 'Gemini 3 Pro Image',\n ...aiImageRatesAtMarkup(0.1344, 2, 12),\n },\n]\n\n/**\n * The per-picture rates an unknown image model id is priced at: the dearest\n * row, on both rates, for the reason `AI_FALLBACK_RATES` gives — an estimate\n * that errs low is worse than one that errs high.\n */\nexport const AI_IMAGE_FALLBACK_RATES: Pick<\n AiImageCatalogEntry,\n 'providerUsdPerImage' | 'billedUsdPerImage'\n> = {\n providerUsdPerImage: Math.max(...AI_IMAGE_MODEL_CATALOG.map((row) => row.providerUsdPerImage)),\n billedUsdPerImage: Math.max(...AI_IMAGE_MODEL_CATALOG.map((row) => row.billedUsdPerImage)),\n}\n\n/** The image catalog row for a model id, or `undefined` for an unknown id. */\nexport function aiImageCatalogEntry(modelId: string): AiImageCatalogEntry | undefined {\n return AI_IMAGE_MODEL_CATALOG.find((entry) => entry.id === modelId)\n}\n\n/** What the provider charges us for one picture from `modelId`, at `size` (1K when absent). */\nexport function aiImageProviderUsdPerImage(modelId: string, size?: AiImageSize): number {\n return atImageSize((aiImageCatalogEntry(modelId) ?? AI_IMAGE_FALLBACK_RATES).providerUsdPerImage, size)\n}\n\n/** What one picture from `modelId` at `size` (1K when absent) draws from a customer's credits. */\nexport function aiImageBilledUsdPerImage(modelId: string, size?: AiImageSize): number {\n return atImageSize((aiImageCatalogEntry(modelId) ?? AI_IMAGE_FALLBACK_RATES).billedUsdPerImage, size)\n}\n\n/**\n * Usage as the meter prices it: a text exchange's tokens, and, for a door\n * that makes pictures, how many it delivered and at what size (1K when\n * absent). `images` is absent on every text exchange, which prices exactly\n * as it always did.\n */\nexport type AiMeteredUsage = AiUsage & { images?: number; imageSize?: AiImageSize }\n\n/** Pictures on a usage record: whole, finite, non-negative, else 0. */\nfunction aiImageCount(usage: AiMeteredUsage): number {\n const value = Number(usage.images ?? 0)\n return Number.isFinite(value) && value > 0 ? Math.floor(value) : 0\n}\n\nfunction roundUsd(value: number): number {\n return Math.round(value * 1_000_000) / 1_000_000\n}\n\n/** The dearest known tier, used when a model id is not in the catalog. */\nexport const AI_FALLBACK_RATES: AiTokenRates = aiRatesPerMTok(10, 50)\n\n/**\n * The minimum an unknown model id is assumed to have: the largest one the\n * catalog knows. It errs the way the rate fallback errs — toward the answer\n * that costs more — so an unrecognized id reads as \"this prompt does not\n * cache\" rather than promising a saving nobody measured.\n */\nexport const AI_FALLBACK_CACHE_MIN_TOKENS = 4_096\n\n/** The shortest prefix a model's provider will cache; the dearest assumption for an unknown id. */\nexport function aiModelCacheMinTokens(modelId: string): number {\n return aiCatalogEntry(modelId)?.cacheMinTokens ?? AI_FALLBACK_CACHE_MIN_TOKENS\n}\n\nconst ZERO_RATES = aiRatesPerMTok(0, 0)\n\n/** The catalog row for a model id, or `undefined` for an unknown id. */\nexport function aiCatalogEntry(modelId: string): AiCatalogEntry | undefined {\n return AI_MODEL_CATALOG.find((entry) => entry.id === modelId)\n}\n\nconst isSentinel = (modelId: string): boolean =>\n (Object.values(AI_METER_SENTINELS) as string[]).includes(modelId)\n\n/**\n * What the PROVIDER charges for a model id — our bill. A meter sentinel is\n * free; an image model's prompt and thinking are priced at its image row's\n * token rates (AGL-3602); an unknown id is priced at the dearest tier.\n *\n * The figure every cost and margin surface prices usage at. Answering the\n * customer's question from here would report a margin the platform does not\n * earn, and answering ours from `aiBilledRatesForModel` reports one it does\n * not pay; the two are separate functions so neither is reachable by\n * forgetting which one was meant.\n */\nexport function aiProviderRatesForModel(modelId: string): AiTokenRates {\n if (isSentinel(modelId)) return ZERO_RATES\n return (\n aiCatalogEntry(modelId)?.providerRates ??\n aiImageCatalogEntry(modelId)?.providerRates ??\n AI_FALLBACK_RATES\n )\n}\n\n/**\n * What a CUSTOMER'S CREDITS are charged at for a model id. A meter sentinel\n * is free; an unknown id is priced at the dearest tier.\n *\n * The figure the credit meter, the band and the model selector price usage\n * at. It is at or above `aiProviderRatesForModel` on every row.\n */\nexport function aiBilledRatesForModel(modelId: string): AiTokenRates {\n if (isSentinel(modelId)) return ZERO_RATES\n return (\n aiCatalogEntry(modelId)?.billedRates ??\n aiImageCatalogEntry(modelId)?.billedRates ??\n AI_FALLBACK_RATES\n )\n}\n\nfunction priceUsage(usage: AiUsage, rate: AiTokenRates): number {\n const raw =\n usage.inputTokens * rate.inputPerToken +\n usage.outputTokens * rate.outputPerToken +\n usage.cacheReadTokens * rate.cacheReadPerToken +\n usage.cacheWriteTokens * rate.cacheWritePerToken\n return Math.round(raw * 1_000_000) / 1_000_000\n}\n\n/**\n * What one exchange COST US, at the serving model's provider rates, rounded\n * to 6dp. Real money, and the only figure a margin may be taken against.\n */\nexport function estimateAiProviderCostUsd(usage: AiMeteredUsage, modelId: string): number {\n return roundUsd(\n priceUsage(usage, aiProviderRatesForModel(modelId)) +\n aiImageCount(usage) * aiImageProviderUsdPerImage(modelId, usage.imageSize),\n )\n}\n\n/**\n * What one exchange DRAWS FROM A CUSTOMER, at the serving model's billed\n * rates, rounded to 6dp — the figure `assistCreditsFromUsd` turns into\n * credits. At or above `estimateAiProviderCostUsd` for the same exchange.\n */\nexport function estimateAiBilledUsd(usage: AiMeteredUsage, modelId: string): number {\n return roundUsd(\n priceUsage(usage, aiBilledRatesForModel(modelId)) +\n aiImageCount(usage) * aiImageBilledUsdPerImage(modelId, usage.imageSize),\n )\n}\n\n/** Every catalog id a provider serves. */\nexport function aiModelIdsForProvider(providerId: string): string[] {\n return AI_MODEL_CATALOG.filter((entry) => entry.provider === providerId).map(\n (entry) => entry.id,\n )\n}\n\n/**\n * What a step asks for, and what the routing table answers with. Every\n * door names its kind here rather than a model, so a model swap — an\n * incident override, an org's own setting, a cheaper model for a cheap\n * step — is one row rather than a search through the doors (AGL-2937).\n */\nexport type AiStepKind =\n | 'assist.chat'\n | 'copy.element'\n | 'copy.section'\n | 'copy.blog'\n | 'generate.section'\n | 'job.component'\n | 'job.crm'\n | 'job.edit'\n | 'job.experiment'\n | 'job.form'\n | 'job.insight'\n | 'job.layout'\n | 'job.logic'\n | 'job.template'\n | 'job.page'\n | 'job.products'\n | 'job.seo'\n | 'job.text'\n | 'job.theme'\n | 'job.plan'\n | 'job.email'\n | 'job.campaign'\n | 'job.workflow'\n\n/** The tier each step kind is served from when no setting overrides it. */\nexport const AI_STEP_TIERS: Record<AiStepKind, AiCatalogEntry['tier']> = {\n 'assist.chat': 'balanced',\n 'copy.element': 'fast',\n 'copy.section': 'balanced',\n 'copy.blog': 'balanced',\n 'generate.section': 'balanced',\n // A reusable component is one structured tree with the typed props it\n // declares, and choosing what becomes a prop is the judgment the step sells.\n 'job.component': 'balanced',\n // CRM by AI (AGL-2917): a record's summary and next step, a deal's stage, a\n // lead's standing, a one-to-one email draft and an import's column matches.\n // Short answers through a strict tool, held to the facts the CRM reports\n // about the record the member opened.\n 'job.crm': 'fast',\n // A change to a page or a layout the site has (AGL-3616): the Assist edit\n // rung's protocol run as a job, held to the closed world of the document's\n // own element ids and to the palette validators. Finding the element a\n // request means, and changing only it, is the judgment; the chat door that\n // proposes the same edits runs on this tier.\n 'job.edit': 'balanced',\n // A/B tests by AI (AGL-2914): variants of one piece of copy, and a\n // result put into words for a verdict code already reached. Short answers\n // through a strict tool, but the judgment a variant sells — which ONE idea\n // to vary so the result says something — is the balanced tier's.\n 'job.experiment': 'balanced',\n // A form is one small tree held to the building rules and to the contract\n // its submissions are read by; a re-ask costs more than the tier saves.\n 'job.form': 'balanced',\n // An insight (AGL-2915) chooses which figures answer a question and says\n // what they show; the trace holds every number, and the judgment of what is\n // worth saying is what the fast tier does worse.\n 'job.insight': 'balanced',\n // A layout or a page template is one structured tree held to every\n // building rule; the fast tier re-asks more than it saves.\n 'job.layout': 'balanced',\n // A site function or variable (AGL-3603): a small structured answer held\n // to the evaluator's grammar, the names it may read and a first run, whose\n // judgment is turning a description into conditions and arithmetic; the\n // fast tier re-asks more than it saves.\n 'job.logic': 'balanced',\n 'job.template': 'balanced',\n // A page section (AGL-2907) is held to the whole page's building rules on\n // every pass, for the same reason.\n 'job.page': 'balanced',\n // A product's copy, a store's first products, or its categories and\n // discounts (AGL-2916): judgment about what a photo shows and what a shopper\n // needs, held to storefront claim rules a re-ask costs more to meet than the\n // tier saves.\n 'job.products': 'balanced',\n // SEO fields, alt text and an audit's fixes (AGL-2910): short answers\n // through a strict tool, held to a length and to the page's own text.\n 'job.seo': 'fast',\n 'job.text': 'balanced',\n // A theme is one structured answer over a small, fixed control set; the\n // judgment is in the color choices, which the fast tier makes worse.\n 'job.theme': 'balanced',\n 'job.plan': 'balanced',\n // An email is one tree held to every building rule, with subject lines\n // whose judgment is the point of asking; the fast tier re-asks more than it\n // saves. A campaign is the same email, drafted into a campaign.\n 'job.email': 'balanced',\n 'job.campaign': 'balanced',\n // An automation is a small structured answer whose judgment is choosing the\n // trigger and steps a description means, and an explanation reads one\n // closely; the fast tier re-asks more than it saves on both (AGL-2919).\n 'job.workflow': 'balanced',\n}\n\n/** The first current catalog model of a tier on a provider, or the provider's first current model. */\nexport function aiDefaultModelFor(providerId: string, tier: AiCatalogEntry['tier']): string | undefined {\n const onProvider = AI_MODEL_CATALOG.filter((entry) => entry.provider === providerId && !entry.successor)\n return (onProvider.find((entry) => entry.tier === tier) ?? onProvider[0])?.id\n}\n"],"names":["aiRatesPerMTok","inputPerMTok","outputPerMTok","inputPerToken","outputPerToken","cacheReadPerToken","cacheWritePerToken","aiRatesAtList","providerRates","billedRates","AI_BILLED_MARKUP","aiRatesMarkedUp","rates","aiRatesAtMarkup","aiRatesAtListWithCacheRead","cacheReadPerMTok","AI_METER_SENTINELS","docsRetrieval","docsLinks","answerCache","ANTHROPIC","OPENAI_COMPATIBLE","ANTHROPIC_DATA_RECEIVED_LEAD","ANTHROPIC_DATA_RECEIVED_CRM_DRAFTS_AND_IMPORTS","ANTHROPIC_CRM_ASSISTANCE_WHOLE_RECORD","record","never","anthropicDataReceived","crm","AI_CATALOG_PROVIDERS","id","label","subprocessor","entity","region","purpose","publishedOn","reason","dataReceived","anthropicCapabilities","streaming","tools","thinking","promptCache","vision","AI_MODEL_CATALOG","provider","capabilities","tier","cacheMinTokens","successor","aiImageRatesAtMarkup","providerUsdPerImage","billedUsdPerImage","roundUsd","AI_IMAGE_SIZE_OUTPUT_TOKENS","atImageSize","usdAt1K","size","tokens","AI_IMAGE_DEFAULT_MODEL","AI_IMAGE_VERTEX_PROVIDER_ID","AI_IMAGE_CATALOG_PROVIDERS","AI_IMAGE_MODEL_CATALOG","AI_IMAGE_FALLBACK_RATES","Math","max","map","row","aiImageCatalogEntry","modelId","find","entry","aiImageProviderUsdPerImage","aiImageBilledUsdPerImage","aiImageCount","usage","value","Number","images","isFinite","floor","round","AI_FALLBACK_RATES","AI_FALLBACK_CACHE_MIN_TOKENS","aiModelCacheMinTokens","aiCatalogEntry","ZERO_RATES","isSentinel","Object","values","includes","aiProviderRatesForModel","aiBilledRatesForModel","priceUsage","rate","raw","inputTokens","outputTokens","cacheReadTokens","cacheWriteTokens","estimateAiProviderCostUsd","imageSize","estimateAiBilledUsd","aiModelIdsForProvider","providerId","filter","AI_STEP_TIERS","aiDefaultModelFor","onProvider"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/providers/catalog.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 { PluginSubprocessorDeclaration } from '@aglyn/aglyn/plugin-manager/plugin-subprocessors'\nimport type { AiModelDescriptor, AiUsage } from './contract'\nimport type { AiImageSize } from './image-contract'\n\n/**\n * The model catalog (AGL-2939): every model id the plugin will route to,\n * with its provider, its display name, its capabilities and its list rates.\n * The ONE place a model id is written outside a provider adapter — the\n * routing table maps a step kind to an id through here, the meter prices\n * usage by id through here, and a settings form offers ids from here.\n *\n * ## Two rates, because one figure was answering two questions\n *\n * Every row carries a PROVIDER rate and a BILLED rate (AGL-3015):\n *\n * - `providerRates` is what the vendor charges us. It is money leaving the\n * company, so cost accounting, the margin surfaces and every staff spend\n * meter price usage through this one and no other.\n * - `billedRates` is what a customer's credits are charged at. The credit\n * meter, the band, the overage ladder and the model selector price usage\n * through this one, because it is the figure a customer's balance moves by.\n *\n * They are equal on nearly every row, and a helper writes the pair from one\n * figure so an unmarked row cannot drift apart by a typo. A row may be\n * billed ABOVE its provider rate deliberately — the markup is carried in the\n * rate rather than in the credit conversion, which keeps a credit a fixed\n * quantity of billed spend on every model and leaves the band, the ladder\n * and the invoice on the one arithmetic they were sized with. A row billed\n * BELOW its provider rate would sell tokens at a loss, and\n * `billed-rate-is-not-provider-cost.spec.ts` refuses one.\n *\n * Both are keyed by model rather than fixed at one model's rates because the\n * default is an env override: a one-line incident swap to a dearer model\n * would otherwise keep reporting the cheaper money, and per-org cost would\n * read as roughly right — the failure mode this whole meter exists to\n * prevent. An unknown id falls back to the most EXPENSIVE known tier on\n * purpose, on both rates: an estimate that errs low is worse than one that\n * errs high, whether the figure is our bill or the customer's.\n */\n\nexport interface AiTokenRates {\n inputPerToken: number\n outputPerToken: number\n cacheReadPerToken: number\n cacheWritePerToken: number\n}\n\n/** List price per MTok → per-token rates, cache read at 0.1x, write 1.25x. */\nexport function aiRatesPerMTok(inputPerMTok: number, outputPerMTok: number): AiTokenRates {\n return {\n inputPerToken: inputPerMTok / 1_000_000,\n outputPerToken: outputPerMTok / 1_000_000,\n cacheReadPerToken: (inputPerMTok * 0.1) / 1_000_000,\n cacheWritePerToken: (inputPerMTok * 1.25) / 1_000_000,\n }\n}\n\n/**\n * The two rate tables a catalog row carries. Separate fields rather than one\n * table and a multiplier: a reader that wants our cost has to name it, and\n * a reader that wants the customer's has to name that, so neither can be\n * reached by accident.\n */\nexport interface AiCatalogRates {\n /** What the provider bills us for this model. */\n providerRates: AiTokenRates\n /** What a customer's credits are charged at for this model. */\n billedRates: AiTokenRates\n}\n\n/**\n * A row billed at exactly the provider's list rate — the usual case, written\n * once so the pair cannot drift.\n */\nexport function aiRatesAtList(\n inputPerMTok: number,\n outputPerMTok: number,\n): AiCatalogRates {\n return {\n providerRates: aiRatesPerMTok(inputPerMTok, outputPerMTok),\n billedRates: aiRatesPerMTok(inputPerMTok, outputPerMTok),\n }\n}\n\n/**\n * THE PLATFORM'S MARKUP over provider cost (AGL-3781): what a customer's\n * credits are charged for a model over what the model costs us, on every\n * figure. The balanced tier's list (Sonnet, $3 / $15 billed over $2 / $10),\n * a picture and the fast tier are billed at it, so a credit carries the same\n * margin whichever of them it is spent on.\n */\nexport const AI_BILLED_MARKUP = 1.5\n\n/** `rates` at the platform's markup: every figure times {@link AI_BILLED_MARKUP}. */\nexport function aiRatesMarkedUp(rates: AiTokenRates): AiTokenRates {\n return {\n inputPerToken: rates.inputPerToken * AI_BILLED_MARKUP,\n outputPerToken: rates.outputPerToken * AI_BILLED_MARKUP,\n cacheReadPerToken: rates.cacheReadPerToken * AI_BILLED_MARKUP,\n cacheWritePerToken: rates.cacheWritePerToken * AI_BILLED_MARKUP,\n }\n}\n\n/** A row billed at the platform's markup over the provider's list price per MTok. */\nexport function aiRatesAtMarkup(inputPerMTok: number, outputPerMTok: number): AiCatalogRates {\n const providerRates = aiRatesPerMTok(inputPerMTok, outputPerMTok)\n return { providerRates, billedRates: aiRatesMarkedUp(providerRates) }\n}\n\n/** {@link aiRatesAtList} for a model whose cache read is not a tenth of its input price. */\nexport function aiRatesAtListWithCacheRead(\n inputPerMTok: number,\n outputPerMTok: number,\n cacheReadPerMTok: number,\n): AiCatalogRates {\n const rates = { ...aiRatesPerMTok(inputPerMTok, outputPerMTok), cacheReadPerToken: cacheReadPerMTok / 1_000_000 }\n return { providerRates: rates, billedRates: { ...rates } }\n}\n\nexport interface AiCatalogEntry extends AiModelDescriptor, AiCatalogRates {\n /**\n * The tier a routing decision reads: `fast` for short, constrained\n * answers; `balanced` for the assistant and briefs; `deep` for the\n * dearest, slowest class.\n */\n tier: 'fast' | 'balanced' | 'deep'\n /**\n * The shortest prefix this model's provider will cache (AGL-2937). A\n * request whose cached span falls under it is served with the markers\n * honored and NOTHING cached: no error, no warning, and a usage report\n * that reads as a permanent cache miss.\n *\n * It is a property of the model rather than of the tier or the vendor,\n * and it does not fall as a generation advances — so the number has to be\n * written beside the model, and a door that means to cache has to be held\n * to it (`aiCachedPrefixCaches` in the runtime, and the door table in\n * `runtime/ai-prompt-cache.spec.ts`). Without it, \"this block carries a\n * breakpoint\" is a claim nothing checks, and a prompt can be designed\n * around a cache it never had.\n */\n cacheMinTokens: number\n /**\n * A RETIRED row names the model that serves in its place (AGL-3781). The\n * row stays so usage recorded under its id keeps its price, but nothing\n * offers it or routes to it: a setting, an environment override or a pick\n * that names it is served by the successor, so one model per tier holds\n * the tier's traffic and its one cache namespace.\n */\n successor?: string\n}\n\n/**\n * The sentinels a docs-only answer is metered under (AGL-2486): not\n * models, but ids the meter sees, priced at zero so a deflected turn lands\n * in the same rollup as a served one and a keyless deployment does not\n * read as the most efficient one on the platform.\n */\nexport const AI_METER_SENTINELS = {\n docsRetrieval: 'docs-retrieval',\n docsLinks: 'docs-links',\n answerCache: 'assist-cache',\n} as const\n\nconst ANTHROPIC = 'anthropic'\nconst OPENAI_COMPATIBLE = 'openai-compatible'\n\n/**\n * A provider's row on the published subprocessor list: every field but the\n * host, which the registered adapter reports as its `endpointHost`.\n * `{apiKeyEnv}` anywhere in the wording stands for the adapter's\n * `apiKeyEnv`, so a credential's name is written in its adapter alone and\n * never in this module, which the browser bundle carries.\n */\nexport type AiProviderSubprocessorWording = Omit<PluginSubprocessorDeclaration, 'host'>\n\n/** A provider the catalog carries models for. */\nexport interface AiCatalogProvider {\n id: string\n /** The name a settings form shows. */\n label: string\n /**\n * The vendor's row on the published subprocessor list, written here and\n * nowhere else: `aiSubprocessors` derives the plugin's declarations from\n * it. Absent for a provider whose endpoint an operator names, which has\n * no fixed recipient to publish.\n */\n subprocessor?: AiProviderSubprocessorWording\n}\n\n/**\n * The Anthropic row's data cell up to its CRM sentence: every door but CRM\n * assistance, worded once for both of the CRM sentences below.\n */\nconst ANTHROPIC_DATA_RECEIVED_LEAD =\n \"What the user submits — a question, instruction or brief, with the earlier messages of the same Assist conversation — and the content of the element, post, section or page being worked on, with the generated response. On Pro and above, the organization's name and the console route and host travel with an Assist question. For an edit the assistant proposes in the besigner, an outline of the open page, component or layout: element and component ids, layer names, shortened setting values and the selected element's styles. For a generation job, the site inventory: the names and addresses of its pages and collections, the names of its components, layouts, templates, forms and datasets with their prop and field names, and the theme's summary, colors and fonts. For a theme change, the site's current theme settings and brand colors as hex values, from the organization's brand settings, the site logo in the media library or a public page the brief links to. For features that review or write search information, the text and structure of the pages concerned. For product copy, the store's name, the product's name, type, description, tags, options and search listing, the store's category names, and the product's first media-library photo as a copy at most 768 px on its longer edge with its metadata stripped; never another media file, a price, stock, an order or a customer. For products, categories and discounts proposed from a brief, the store's name and its existing category names. For an automation drafted from a brief, which of CRM, webhooks and bookings the plan includes; for an explanation, the automation's outline (trigger, conditions, each step's text with the names of the lists, campaigns, workflows, webhooks and datasets it uses and whether each exists, and a workflow's function names and expressions) and, for a failed run, its time, steps and recorded errors, with email addresses removed and never the triggering event's data. For an insight, the figure reports available and aggregate tables: traffic with top page paths, referrers and campaign tags; form views and submissions; revenue, orders and best-selling product names; bookings by service; campaign subjects with delivery, open and click rates; A/B test and variant conversions; and, for a dataset the member can see, field names and types, record and fill counts, number ranges and totals grouped by a value at least three records share. Email addresses and phone numbers are removed, and no individual record is sent. \"\n\n/** What every CRM door adds after its record sentence: drafts and imports. */\nconst ANTHROPIC_DATA_RECEIVED_CRM_DRAFTS_AND_IMPORTS =\n \"An email draft adds the request and the record's merge field names; an import sends the field names and types and each column's header and value kind, never a row.\"\n\n/** How the data cell words CRM assistance: what a record sends, and what never leaves. */\nexport interface AnthropicCrmAssistanceWording {\n record: string\n never: string\n}\n\n/**\n * CRM assistance once the whole record is sent (AGL-3520): the open-ended\n * wording the Subprocessors row and Privacy Policy section 2 were\n * republished with on October 5, 2026 (legal v10), before\n * `release_crm_assist_whole_record` may be turned on. The catalog row below\n * carries it in `dataReceived`.\n */\nexport const ANTHROPIC_CRM_ASSISTANCE_WHOLE_RECORD: AnthropicCrmAssistanceWording = {\n record:\n 'For CRM assistance, the opened record as the CRM shows it, with all of its standard and custom fields, including contact details, notes, timeline and related records.',\n never: 'No account identifiers or authentication tokens, and no email address outside an opened CRM record.',\n}\n\n/** The Anthropic row's data cell, with CRM assistance worded as `crm` words it. */\nexport function anthropicDataReceived(crm: AnthropicCrmAssistanceWording): string {\n return `${ANTHROPIC_DATA_RECEIVED_LEAD}${crm.record} ${ANTHROPIC_DATA_RECEIVED_CRM_DRAFTS_AND_IMPORTS} ${crm.never}`\n}\n\n/**\n * The providers the catalog carries models for, with the name a settings\n * form shows. A form offers providers from here for the reason it offers\n * models from here: nothing outside this folder names a vendor. For the\n * same reason a vendor's subprocessor row is written here too.\n */\nexport const AI_CATALOG_PROVIDERS: readonly AiCatalogProvider[] = [\n {\n id: ANTHROPIC,\n label: 'Anthropic',\n subprocessor: {\n entity: 'Anthropic, PBC',\n region: 'United States',\n purpose:\n \"AI features of the Services, including the Aglyn Assist helper: creating, editing and reviewing content, drafts and settings for a customer’s site, store and CRM, and explaining and summarizing the customer’s own setup and data\",\n publishedOn: '2026-10-07',\n reason:\n \"Reached through the AI plugin's Anthropic adapter (`libs/plugins/ai/src/lib/providers/anthropic.ts`) by the doors that call the AI runtime. `libs/plugins/ai/src/lib/server/assist-chat.ts` is gated by `release_assist` AND the key, and a generation job's text step by `release_ai_generative`; `libs/plugins/ai/src/lib/server/ai-assist.ts` carries NO release flag, so setting `{apiKeyEnv}` in production is by itself what starts this flow. `assist-anthropic-subprocessor-gate.spec.ts` holds the per-door detail and is the deeper guard for this one vendor.\",\n dataReceived: anthropicDataReceived(ANTHROPIC_CRM_ASSISTANCE_WHOLE_RECORD),\n },\n },\n { id: OPENAI_COMPATIBLE, label: 'OpenAI-compatible endpoint' },\n]\n\n/**\n * `vision` is written on every row rather than assumed (AGL-2916): each model\n * below reads a picture in a user turn, in the four formats\n * `AI_IMAGE_MEDIA_TYPES` names, as its vendor documents. A row added without\n * it reads as a model that does not, and is never sent one.\n */\nconst anthropicCapabilities = {\n streaming: true,\n tools: true,\n thinking: true,\n promptCache: true,\n vision: true,\n}\n\nexport const AI_MODEL_CATALOG: readonly AiCatalogEntry[] = [\n {\n // THE BALANCED TIER'S DEFAULT (AGL-3660): the first balanced row is what\n // `aiDefaultModelFor` answers, so Free, \"Auto\" and every step routed to\n // balanced run here. Rejects `thinking: {type: \"disabled\"}` and forced\n // tool choice: the adapter sends thinking off as `between_tools` and\n // every tool call with `tool_choice: auto`, a request's `toolChoice`\n // included (no `forcedToolChoice`, AGL-4076).\n id: 'claude-sonnet-5-5',\n provider: ANTHROPIC,\n label: 'Claude Sonnet 5.5',\n capabilities: anthropicCapabilities,\n /*\n * THE ROWS BILLED ABOVE THEIR PROVIDER RATE (AGL-3015).\n *\n * The balanced tier prices most requests, so this markup is most of the\n * platform's AI margin. It is carried in the rate and not in the credit\n * conversion for the reason the module head gives: a credit stays a\n * fixed quantity of billed spend on every model, so the band, the\n * overage ladder and the invoice keep the arithmetic they were sized\n * with, and nothing below has to know which model served a request.\n *\n * Everything that reasons about what we PAY — the margin surfaces, the\n * staff spend meters, the discount guardrail's cost of goods — reads\n * `providerRates`, which is the vendor's published list. Sonnet 5.5's\n * list is Sonnet 5's, except a cache read: $0.10/MTok, a twentieth of\n * input. A customer is billed exactly what Sonnet 5 billed, so the\n * balanced tier's prices do not move when its default does.\n */\n providerRates: { ...aiRatesPerMTok(2, 10), cacheReadPerToken: 0.1 / 1_000_000 },\n billedRates: aiRatesPerMTok(3, 15),\n tier: 'balanced',\n cacheMinTokens: 512,\n },\n {\n // The balanced default until AGL-3660, retired to Sonnet 5.5 (AGL-3781):\n // the same price, a cache read half as dear, and a cache namespace of\n // its own that every request on it split the tier's prefixes into. Kept\n // so the usage and recordings that name it still price at its rates.\n id: 'claude-sonnet-5',\n provider: ANTHROPIC,\n label: 'Claude Sonnet 5',\n capabilities: { ...anthropicCapabilities, forcedToolChoice: true },\n providerRates: aiRatesPerMTok(2, 10),\n billedRates: aiRatesPerMTok(3, 15),\n tier: 'balanced',\n cacheMinTokens: 1_024,\n successor: 'claude-sonnet-5-5',\n },\n {\n id: 'claude-sonnet-4-6',\n provider: ANTHROPIC,\n label: 'Claude Sonnet 4.6',\n capabilities: { ...anthropicCapabilities, forcedToolChoice: true },\n ...aiRatesAtList(3, 15),\n tier: 'balanced',\n cacheMinTokens: 1_024,\n },\n {\n // THE FAST TIER'S DEFAULT (AGL-3781): the first fast row, so every step\n // routed to fast, a Free site's plan and look, and a page's listing run\n // here. Thinking is adaptive and ON when a request names none, so each\n // fast route says what it wants (`providers/routing.ts`); it accepts\n // `disabled` at effort high or below, refuses budgets, sampling\n // parameters and an assistant prefill, which no door sends, and has no\n // server-side fallback, which none asks for.\n //\n // The provider list is $0.10 / $0.50 for a prompt of 100,000 tokens or\n // fewer and five times that above it; no door sends a prompt near it.\n // Billed at the platform's markup on every figure, $0.15 / $0.75, as the\n // balanced tier and pictures are: Haiku 4.5 was billed at its cost, with\n // no margin at all. Its tokenizer counts the same text as about 30% more\n // tokens than Haiku 4.5's, which the credit figures derived from it say.\n id: 'claude-haiku-5-5',\n provider: ANTHROPIC,\n label: 'Claude Haiku 5.5',\n capabilities: anthropicCapabilities,\n ...aiRatesAtMarkup(0.1, 0.5),\n tier: 'fast',\n cacheMinTokens: 512,\n },\n {\n // The fast default until AGL-3781, retired to Haiku 5.5. Rejects an\n // explicit `thinking` setting; the runtime omits it.\n id: 'claude-haiku-4-5',\n provider: ANTHROPIC,\n label: 'Claude Haiku 4.5',\n capabilities: { ...anthropicCapabilities, thinking: false },\n ...aiRatesAtList(1, 5),\n tier: 'fast',\n // Four times the balanced tier's minimum: the cheapest model per token\n // was the hardest one to cache for, so no fast-tier prompt ever cached.\n cacheMinTokens: 4_096,\n successor: 'claude-haiku-5-5',\n },\n {\n id: 'claude-opus-5',\n provider: ANTHROPIC,\n label: 'Claude Opus 5',\n capabilities: { ...anthropicCapabilities, forcedToolChoice: true },\n ...aiRatesAtList(5, 25),\n tier: 'deep',\n cacheMinTokens: 512,\n },\n {\n // Listed for a side-by-side comparison (AGL-3660); the deep tier's\n // default stays claude-opus-5 above. Thinking cannot be disabled and its\n // effort defaults to medium, so the adapter omits thinking where a step\n // asks for it off and names effort high where a step names none — Opus\n // 5's own default. Forced tool choice is refused; the adapter sends auto.\n id: 'claude-opus-5-5',\n provider: ANTHROPIC,\n label: 'Claude Opus 5.5',\n capabilities: anthropicCapabilities,\n // At list, like its deep-tier siblings. A cache read is $0.20/MTok, a\n // twentieth of input rather than the usual tenth.\n ...aiRatesAtListWithCacheRead(4, 20, 0.2),\n tier: 'deep',\n cacheMinTokens: 512,\n },\n {\n id: 'claude-opus-4-8',\n provider: ANTHROPIC,\n label: 'Claude Opus 4.8',\n capabilities: { ...anthropicCapabilities, forcedToolChoice: true },\n ...aiRatesAtList(5, 25),\n tier: 'deep',\n cacheMinTokens: 1_024,\n },\n /**\n * The OpenAI-compatible adapter serves whatever the endpoint behind\n * `AI_OPENAI_COMPAT_BASE_URL` serves; these are the ids the routing table\n * may name on it. The figures are the vendor's public list, billed at\n * list: a deployment that reaches its own gateway at a negotiated price\n * is paying less than this says, so its margin reads low rather than\n * high — the direction a cost figure may be wrong in.\n */\n {\n id: 'gpt-5',\n provider: OPENAI_COMPATIBLE,\n label: 'GPT-5',\n capabilities: { streaming: true, tools: true, thinking: false, promptCache: true, vision: true },\n ...aiRatesAtList(1.25, 10),\n tier: 'balanced',\n cacheMinTokens: 1_024,\n },\n {\n id: 'gpt-5-mini',\n provider: OPENAI_COMPATIBLE,\n label: 'GPT-5 mini',\n capabilities: { streaming: true, tools: true, thinking: false, promptCache: true, vision: true },\n ...aiRatesAtList(0.25, 2),\n tier: 'fast',\n cacheMinTokens: 1_024,\n },\n]\n\n/**\n * The IMAGE models (AGL-3602): every model id the Media library's \"Create\n * with AI\" photo mode may route to — Google's Gemini image models on Vertex\n * AI — with a per-picture provider rate and a per-picture billed rate, and the\n * token rates the same request's prompt and thinking are billed at. Kept\n * apart from `AI_MODEL_CATALOG` because nothing that lists text models — the\n * model selector, the routing table, the allotments' allowlists — may ever\n * offer one of these for a conversation.\n *\n * ## The rates\n *\n * Google prices an output picture as image-output tokens: Gemini 3.1 Flash\n * Image writes a 1K picture as 1,120 tokens at $60 per million on the global\n * endpoint, so $0.0672 a picture. Its prompt is input tokens ($0.50 per\n * million) and its thinking is text output ($3.00 per million). Every figure\n * here is the global endpoint's list price, read from Google's Vertex AI\n * pricing page on 2026-10-06; a regional endpoint lists 10% higher, so a\n * deployment that moves off `global` reads its cost low by that much.\n *\n * Every billed figure is the provider figure at `AI_BILLED_MARKUP`:\n * the same ratio the balanced text tier is billed at over its provider rate\n * (Claude Sonnet 5, $3/$15 billed over $2/$10), so a credit buys the same\n * share of margin whether it is spent on words or on pictures. A picture is\n * NEVER billed at provider cost; `billed-rate-is-not-provider-cost.spec.ts`\n * refuses a row that is.\n *\n * A credit is $0.001 of billed spend (`ASSIST_CREDIT_COST_USD`), so the\n * default model's picture is 101 credits before its prompt and thinking.\n *\n * Every per-picture figure on a row is the 1K picture's. A 512 px picture —\n * what the Free plan makes — is written as fewer image tokens at the same\n * per-token rate (`AI_IMAGE_SIZE_OUTPUT_TOKENS`), so it is priced at the 1K\n * figure scaled by its share of tokens: $0.04482 from the provider and\n * $0.06723 billed on the default model, before its prompt and thinking.\n */\nexport interface AiImageCatalogEntry extends AiCatalogRates {\n id: string\n /** The image provider the model is served by. */\n provider: string\n label: string\n /** What the provider bills us for one generated picture. */\n providerUsdPerImage: number\n /** What one picture draws from a customer's credits. */\n billedUsdPerImage: number\n}\n\n/**\n * An image row's four figures from Google's list prices — USD per output\n * picture, and USD per million input and text-output tokens — each billed at\n * the platform's markup, `AI_BILLED_MARKUP`, so an image row cannot be written\n * at list by accident.\n */\nexport function aiImageRatesAtMarkup(\n providerUsdPerImage: number,\n inputPerMTok: number,\n outputPerMTok: number,\n): Pick<\n AiImageCatalogEntry,\n 'providerUsdPerImage' | 'billedUsdPerImage' | 'providerRates' | 'billedRates'\n> {\n return {\n providerUsdPerImage,\n billedUsdPerImage: roundUsd(providerUsdPerImage * AI_BILLED_MARKUP),\n ...aiRatesAtMarkup(inputPerMTok, outputPerMTok),\n }\n}\n\n/**\n * The image-output tokens Google writes a picture as, by size (AGL-3602),\n * read from the usage of real Gemini 3.1 Flash Image answers on 2026-10-07:\n * 747 at 512 px and 1,120 at 1K. A row's per-picture figures are the 1K\n * picture's; a 512 px picture is priced at its share of them.\n */\nexport const AI_IMAGE_SIZE_OUTPUT_TOKENS: Readonly<Record<AiImageSize, number>> = {\n '512': 747,\n '1K': 1_120,\n}\n\n/** A 1K per-picture figure at `size`, by the size's share of image tokens. */\nfunction atImageSize(usdAt1K: number, size: AiImageSize | undefined): number {\n const tokens = AI_IMAGE_SIZE_OUTPUT_TOKENS[size ?? '1K'] ?? AI_IMAGE_SIZE_OUTPUT_TOKENS['1K']\n return roundUsd((usdAt1K * tokens) / AI_IMAGE_SIZE_OUTPUT_TOKENS['1K'])\n}\n\n/** The image model a photo is made with when the operator names none. */\nexport const AI_IMAGE_DEFAULT_MODEL = 'gemini-3.1-flash-image'\n\n/** The image provider's id: Google's models on Vertex AI. */\nexport const AI_IMAGE_VERTEX_PROVIDER_ID = 'google-vertex'\n\n/**\n * The image providers' rows on the published subprocessor list, kept apart\n * from `AI_CATALOG_PROVIDERS` for the reason the image catalog is kept apart\n * from the text one: a settings form offers text providers from that list,\n * and an image provider answers no conversation. The host is the adapter's\n * published endpoint (`VERTEX_IMAGE_PUBLISHED_HOST`).\n *\n * Google's row is dated to its change-log entry on `/legal/subprocessors`,\n * published with the Privacy Policy §2 sentence naming Google for image\n * generation (legal v12).\n */\nexport const AI_IMAGE_CATALOG_PROVIDERS: readonly AiCatalogProvider[] = [\n {\n id: AI_IMAGE_VERTEX_PROVIDER_ID,\n label: 'Google Vertex AI',\n subprocessor: {\n entity: 'Google LLC (Google Cloud Vertex AI)',\n // The global endpoint, which Google documents as routing and\n // processing a request anywhere in the world, with no data residency\n // guarantee: Google, not Aglyn, chooses the location.\n region: 'Global — Google selects where requests are processed',\n purpose:\n \"AI image generation: creating images for a customer's media library from a description a user writes\",\n publishedOn: '2026-10-08',\n reason:\n \"Reached through the AI plugin's Vertex AI image adapter (`libs/plugins/ai/src/lib/providers/vertex-image.ts`) by the Media library's Create with AI door (`libs/plugins/ai/src/lib/server/ai-media-image.ts`) for every kind that is not drawn as SVG, as the platform's own service account. Off unless `AI_IMAGE_VERTEX_PROJECT` names a Google Cloud project; the console offers those kinds only where `NEXT_PUBLIC_AI_IMAGE_PHOTOS` is `on`. The request carries the description and the kind's fixed style wording, the shape and fixed settings, and nothing else.\",\n dataReceived:\n \"The description the user writes and the shape requested, and the generated image returned. No account identifiers, email addresses, or other content of the customer's site.\",\n },\n },\n]\n\nexport const AI_IMAGE_MODEL_CATALOG: readonly AiImageCatalogEntry[] = [\n {\n // The default: Google's own replacement for Imagen 4, which Vertex AI\n // discontinued in 2026.\n id: 'gemini-3.1-flash-image',\n provider: AI_IMAGE_VERTEX_PROVIDER_ID,\n label: 'Gemini 3.1 Flash Image',\n ...aiImageRatesAtMarkup(0.0672, 0.5, 3),\n },\n {\n id: 'gemini-3.1-flash-lite-image',\n provider: AI_IMAGE_VERTEX_PROVIDER_ID,\n label: 'Gemini 3.1 Flash-Lite Image',\n ...aiImageRatesAtMarkup(0.0336, 0.25, 1.5),\n },\n {\n id: 'gemini-3-pro-image',\n provider: AI_IMAGE_VERTEX_PROVIDER_ID,\n label: 'Gemini 3 Pro Image',\n ...aiImageRatesAtMarkup(0.1344, 2, 12),\n },\n]\n\n/**\n * The per-picture rates an unknown image model id is priced at: the dearest\n * row, on both rates, for the reason `AI_FALLBACK_RATES` gives — an estimate\n * that errs low is worse than one that errs high.\n */\nexport const AI_IMAGE_FALLBACK_RATES: Pick<\n AiImageCatalogEntry,\n 'providerUsdPerImage' | 'billedUsdPerImage'\n> = {\n providerUsdPerImage: Math.max(...AI_IMAGE_MODEL_CATALOG.map((row) => row.providerUsdPerImage)),\n billedUsdPerImage: Math.max(...AI_IMAGE_MODEL_CATALOG.map((row) => row.billedUsdPerImage)),\n}\n\n/** The image catalog row for a model id, or `undefined` for an unknown id. */\nexport function aiImageCatalogEntry(modelId: string): AiImageCatalogEntry | undefined {\n return AI_IMAGE_MODEL_CATALOG.find((entry) => entry.id === modelId)\n}\n\n/** What the provider charges us for one picture from `modelId`, at `size` (1K when absent). */\nexport function aiImageProviderUsdPerImage(modelId: string, size?: AiImageSize): number {\n return atImageSize((aiImageCatalogEntry(modelId) ?? AI_IMAGE_FALLBACK_RATES).providerUsdPerImage, size)\n}\n\n/** What one picture from `modelId` at `size` (1K when absent) draws from a customer's credits. */\nexport function aiImageBilledUsdPerImage(modelId: string, size?: AiImageSize): number {\n return atImageSize((aiImageCatalogEntry(modelId) ?? AI_IMAGE_FALLBACK_RATES).billedUsdPerImage, size)\n}\n\n/**\n * Usage as the meter prices it: a text exchange's tokens, and, for a door\n * that makes pictures, how many it delivered and at what size (1K when\n * absent). `images` is absent on every text exchange, which prices exactly\n * as it always did.\n */\nexport type AiMeteredUsage = AiUsage & { images?: number; imageSize?: AiImageSize }\n\n/** Pictures on a usage record: whole, finite, non-negative, else 0. */\nfunction aiImageCount(usage: AiMeteredUsage): number {\n const value = Number(usage.images ?? 0)\n return Number.isFinite(value) && value > 0 ? Math.floor(value) : 0\n}\n\nfunction roundUsd(value: number): number {\n return Math.round(value * 1_000_000) / 1_000_000\n}\n\n/** The dearest known tier, used when a model id is not in the catalog. */\nexport const AI_FALLBACK_RATES: AiTokenRates = aiRatesPerMTok(10, 50)\n\n/**\n * The minimum an unknown model id is assumed to have: the largest one the\n * catalog knows. It errs the way the rate fallback errs — toward the answer\n * that costs more — so an unrecognized id reads as \"this prompt does not\n * cache\" rather than promising a saving nobody measured.\n */\nexport const AI_FALLBACK_CACHE_MIN_TOKENS = 4_096\n\n/** The shortest prefix a model's provider will cache; the dearest assumption for an unknown id. */\nexport function aiModelCacheMinTokens(modelId: string): number {\n return aiCatalogEntry(modelId)?.cacheMinTokens ?? AI_FALLBACK_CACHE_MIN_TOKENS\n}\n\nconst ZERO_RATES = aiRatesPerMTok(0, 0)\n\n/** The catalog row for a model id, or `undefined` for an unknown id. */\nexport function aiCatalogEntry(modelId: string): AiCatalogEntry | undefined {\n return AI_MODEL_CATALOG.find((entry) => entry.id === modelId)\n}\n\nconst isSentinel = (modelId: string): boolean =>\n (Object.values(AI_METER_SENTINELS) as string[]).includes(modelId)\n\n/**\n * What the PROVIDER charges for a model id — our bill. A meter sentinel is\n * free; an image model's prompt and thinking are priced at its image row's\n * token rates (AGL-3602); an unknown id is priced at the dearest tier.\n *\n * The figure every cost and margin surface prices usage at. Answering the\n * customer's question from here would report a margin the platform does not\n * earn, and answering ours from `aiBilledRatesForModel` reports one it does\n * not pay; the two are separate functions so neither is reachable by\n * forgetting which one was meant.\n */\nexport function aiProviderRatesForModel(modelId: string): AiTokenRates {\n if (isSentinel(modelId)) return ZERO_RATES\n return (\n aiCatalogEntry(modelId)?.providerRates ??\n aiImageCatalogEntry(modelId)?.providerRates ??\n AI_FALLBACK_RATES\n )\n}\n\n/**\n * What a CUSTOMER'S CREDITS are charged at for a model id. A meter sentinel\n * is free; an unknown id is priced at the dearest tier.\n *\n * The figure the credit meter, the band and the model selector price usage\n * at. It is at or above `aiProviderRatesForModel` on every row.\n */\nexport function aiBilledRatesForModel(modelId: string): AiTokenRates {\n if (isSentinel(modelId)) return ZERO_RATES\n return (\n aiCatalogEntry(modelId)?.billedRates ??\n aiImageCatalogEntry(modelId)?.billedRates ??\n AI_FALLBACK_RATES\n )\n}\n\nfunction priceUsage(usage: AiUsage, rate: AiTokenRates): number {\n const raw =\n usage.inputTokens * rate.inputPerToken +\n usage.outputTokens * rate.outputPerToken +\n usage.cacheReadTokens * rate.cacheReadPerToken +\n usage.cacheWriteTokens * rate.cacheWritePerToken\n return Math.round(raw * 1_000_000) / 1_000_000\n}\n\n/**\n * What one exchange COST US, at the serving model's provider rates, rounded\n * to 6dp. Real money, and the only figure a margin may be taken against.\n */\nexport function estimateAiProviderCostUsd(usage: AiMeteredUsage, modelId: string): number {\n return roundUsd(\n priceUsage(usage, aiProviderRatesForModel(modelId)) +\n aiImageCount(usage) * aiImageProviderUsdPerImage(modelId, usage.imageSize),\n )\n}\n\n/**\n * What one exchange DRAWS FROM A CUSTOMER, at the serving model's billed\n * rates, rounded to 6dp — the figure `assistCreditsFromUsd` turns into\n * credits. At or above `estimateAiProviderCostUsd` for the same exchange.\n */\nexport function estimateAiBilledUsd(usage: AiMeteredUsage, modelId: string): number {\n return roundUsd(\n priceUsage(usage, aiBilledRatesForModel(modelId)) +\n aiImageCount(usage) * aiImageBilledUsdPerImage(modelId, usage.imageSize),\n )\n}\n\n/** Every catalog id a provider serves. */\nexport function aiModelIdsForProvider(providerId: string): string[] {\n return AI_MODEL_CATALOG.filter((entry) => entry.provider === providerId).map(\n (entry) => entry.id,\n )\n}\n\n/**\n * What a step asks for, and what the routing table answers with. Every\n * door names its kind here rather than a model, so a model swap — an\n * incident override, an org's own setting, a cheaper model for a cheap\n * step — is one row rather than a search through the doors (AGL-2937).\n */\nexport type AiStepKind =\n | 'assist.chat'\n | 'copy.element'\n | 'copy.section'\n | 'copy.blog'\n | 'generate.section'\n | 'job.component'\n | 'job.crm'\n | 'job.edit'\n | 'job.experiment'\n | 'job.form'\n | 'job.insight'\n | 'job.layout'\n | 'job.logic'\n | 'job.template'\n | 'job.page'\n | 'job.products'\n | 'job.seo'\n | 'job.text'\n | 'job.theme'\n | 'job.plan'\n | 'job.email'\n | 'job.campaign'\n | 'job.workflow'\n\n/** The tier each step kind is served from when no setting overrides it. */\nexport const AI_STEP_TIERS: Record<AiStepKind, AiCatalogEntry['tier']> = {\n 'assist.chat': 'balanced',\n 'copy.element': 'fast',\n 'copy.section': 'balanced',\n 'copy.blog': 'balanced',\n 'generate.section': 'balanced',\n // A reusable component is one structured tree with the typed props it\n // declares, and choosing what becomes a prop is the judgment the step sells.\n 'job.component': 'balanced',\n // CRM by AI (AGL-2917): a record's summary and next step, a deal's stage, a\n // lead's standing, a one-to-one email draft and an import's column matches.\n // Short answers through a strict tool, held to the facts the CRM reports\n // about the record the member opened.\n 'job.crm': 'fast',\n // A change to a page or a layout the site has (AGL-3616): the Assist edit\n // rung's protocol run as a job, held to the closed world of the document's\n // own element ids and to the palette validators. Finding the element a\n // request means, and changing only it, is the judgment; the chat door that\n // proposes the same edits runs on this tier.\n 'job.edit': 'balanced',\n // A/B tests by AI (AGL-2914): variants of one piece of copy, and a\n // result put into words for a verdict code already reached. Short answers\n // through a strict tool, but the judgment a variant sells — which ONE idea\n // to vary so the result says something — is the balanced tier's.\n 'job.experiment': 'balanced',\n // A form is one small tree held to the building rules and to the contract\n // its submissions are read by; a re-ask costs more than the tier saves.\n 'job.form': 'balanced',\n // An insight (AGL-2915) chooses which figures answer a question and says\n // what they show; the trace holds every number, and the judgment of what is\n // worth saying is what the fast tier does worse.\n 'job.insight': 'balanced',\n // A layout or a page template is one structured tree held to every\n // building rule; the fast tier re-asks more than it saves.\n 'job.layout': 'balanced',\n // A site function or variable (AGL-3603): a small structured answer held\n // to the evaluator's grammar, the names it may read and a first run, whose\n // judgment is turning a description into conditions and arithmetic; the\n // fast tier re-asks more than it saves.\n 'job.logic': 'balanced',\n 'job.template': 'balanced',\n // A page section (AGL-2907) is held to the whole page's building rules on\n // every pass, for the same reason.\n 'job.page': 'balanced',\n // A product's copy, a store's first products, or its categories and\n // discounts (AGL-2916): judgment about what a photo shows and what a shopper\n // needs, held to storefront claim rules a re-ask costs more to meet than the\n // tier saves.\n 'job.products': 'balanced',\n // SEO fields, alt text and an audit's fixes (AGL-2910): short answers\n // through a strict tool, held to a length and to the page's own text.\n 'job.seo': 'fast',\n 'job.text': 'balanced',\n // A theme is one structured answer over a small, fixed control set; the\n // judgment is in the color choices, which the fast tier makes worse.\n 'job.theme': 'balanced',\n 'job.plan': 'balanced',\n // An email is one tree held to every building rule, with subject lines\n // whose judgment is the point of asking; the fast tier re-asks more than it\n // saves. A campaign is the same email, drafted into a campaign.\n 'job.email': 'balanced',\n 'job.campaign': 'balanced',\n // An automation is a small structured answer whose judgment is choosing the\n // trigger and steps a description means, and an explanation reads one\n // closely; the fast tier re-asks more than it saves on both (AGL-2919).\n 'job.workflow': 'balanced',\n}\n\n/** The first current catalog model of a tier on a provider, or the provider's first current model. */\nexport function aiDefaultModelFor(providerId: string, tier: AiCatalogEntry['tier']): string | undefined {\n const onProvider = AI_MODEL_CATALOG.filter((entry) => entry.provider === providerId && !entry.successor)\n return (onProvider.find((entry) => entry.tier === tier) ?? onProvider[0])?.id\n}\n"],"names":["aiRatesPerMTok","inputPerMTok","outputPerMTok","inputPerToken","outputPerToken","cacheReadPerToken","cacheWritePerToken","aiRatesAtList","providerRates","billedRates","AI_BILLED_MARKUP","aiRatesMarkedUp","rates","aiRatesAtMarkup","aiRatesAtListWithCacheRead","cacheReadPerMTok","AI_METER_SENTINELS","docsRetrieval","docsLinks","answerCache","ANTHROPIC","OPENAI_COMPATIBLE","ANTHROPIC_DATA_RECEIVED_LEAD","ANTHROPIC_DATA_RECEIVED_CRM_DRAFTS_AND_IMPORTS","ANTHROPIC_CRM_ASSISTANCE_WHOLE_RECORD","record","never","anthropicDataReceived","crm","AI_CATALOG_PROVIDERS","id","label","subprocessor","entity","region","purpose","publishedOn","reason","dataReceived","anthropicCapabilities","streaming","tools","thinking","promptCache","vision","AI_MODEL_CATALOG","provider","capabilities","tier","cacheMinTokens","forcedToolChoice","successor","aiImageRatesAtMarkup","providerUsdPerImage","billedUsdPerImage","roundUsd","AI_IMAGE_SIZE_OUTPUT_TOKENS","atImageSize","usdAt1K","size","tokens","AI_IMAGE_DEFAULT_MODEL","AI_IMAGE_VERTEX_PROVIDER_ID","AI_IMAGE_CATALOG_PROVIDERS","AI_IMAGE_MODEL_CATALOG","AI_IMAGE_FALLBACK_RATES","Math","max","map","row","aiImageCatalogEntry","modelId","find","entry","aiImageProviderUsdPerImage","aiImageBilledUsdPerImage","aiImageCount","usage","value","Number","images","isFinite","floor","round","AI_FALLBACK_RATES","AI_FALLBACK_CACHE_MIN_TOKENS","aiModelCacheMinTokens","aiCatalogEntry","ZERO_RATES","isSentinel","Object","values","includes","aiProviderRatesForModel","aiBilledRatesForModel","priceUsage","rate","raw","inputTokens","outputTokens","cacheReadTokens","cacheWriteTokens","estimateAiProviderCostUsd","imageSize","estimateAiBilledUsd","aiModelIdsForProvider","providerId","filter","AI_STEP_TIERS","aiDefaultModelFor","onProvider"],"mappings":"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"}
|