@broberg/ai-sdk 0.36.6 → 0.37.0
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/dist/chunk-CTPTMHNX.js +279 -0
- package/dist/chunk-CTPTMHNX.js.map +1 -0
- package/dist/index.d.ts +11 -4
- package/dist/index.js +22 -10
- package/dist/index.js.map +1 -1
- package/dist/pricing.d.ts +34 -2
- package/dist/pricing.js +15 -110
- package/dist/pricing.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-TENEIW7I.js +0 -130
- package/dist/chunk-TENEIW7I.js.map +0 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/transport/http.ts","../src/transport/subprocess.ts","../src/transport/stream.ts","../src/providers/tools.ts","../src/cost/region.ts","../src/cost/usage.ts","../src/providers/anthropic.ts","../src/providers/openai-compatible.ts","../src/providers/openai.ts","../src/providers/media.ts","../src/providers/gemini.ts","../src/providers/deepinfra.ts","../src/providers/openrouter.ts","../src/providers/requesty.ts","../src/providers/deepseek.ts","../src/providers/mistral.ts","../src/providers/elevenlabs.ts","../src/providers/azure.ts","../src/providers/vertex.ts","../src/providers/deepl.ts","../src/providers/fal.ts","../src/providers/bfl.ts","../src/providers/registry.ts","../src/cost/budget.ts","../src/capabilities/vision.ts","../src/capabilities/video.ts","../src/capabilities/translate.ts","../src/capabilities/embedding.ts","../src/capabilities/transcribe.ts","../src/capabilities/contracts/index.ts","../src/voices/registry.ts","../src/voices/types.ts","../src/voices/resolve.ts","../src/schema/inputs.ts","../src/version.ts","../src/cost/sinks/upmetrics.ts","../src/client.ts","../src/providers/stub.ts","../src/availability/refresh.ts","../src/cost/budget-store.ts","../src/cost/sinks/noop.ts","../src/cost/sinks/multi.ts","../src/cost/sinks/discord.ts","../src/cost/sinks/sqlite.ts","../src/cost/upmetrics-read.ts"],"sourcesContent":["// HTTP transport: a thin fetch wrapper. Provider-agnostic — the adapter supplies\n// the fully-built url/headers/body and parses the returned json itself.\nimport type { TransportRequest, HttpResponse } from \"./types.js\";\n\nexport async function httpTransport(req: TransportRequest): Promise<HttpResponse> {\n if (!req.http) {\n throw new Error(\"httpTransport: req.http is required for http transport\");\n }\n const { url, method = \"POST\", headers, body } = req.http;\n const res = await fetch(url, {\n method,\n headers,\n body:\n body === undefined\n ? undefined\n : typeof body === \"string\"\n ? body\n : JSON.stringify(body),\n });\n // Read the body ONCE as text, then try to parse it. Reading .json() directly\n // discarded the body whenever it would not parse — so the very case errorBody was\n // written for (an HTML 502 from a gateway) produced \"(no body)\" and the outage page\n // we wanted to show was already gone. Keeping the text costs nothing and is the\n // difference between a debuggable message and a status code.\n const text = await res.text().catch(() => \"\");\n let json: unknown;\n try {\n json = text ? JSON.parse(text) : undefined;\n } catch {\n json = undefined;\n }\n return { ok: res.ok, status: res.status, json, text };\n}\n\n/** Render a provider error body for an exception message, without ever throwing.\n *\n * F043. `httpTransport` sets `json` to undefined when the response body is not JSON\n * — an HTML 502 from a gateway, a proxy timeout page, an empty body. Four adapters\n * then wrote `JSON.stringify(res.json).slice(0, 300)`, and JSON.stringify(undefined)\n * returns undefined rather than a string, so the ERROR HANDLER crashed with\n * \"Cannot read properties of undefined (reading 'slice')\" — replacing a useful\n * \"502 <gateway page>\" with a TypeError that pointed nowhere near the real cause.\n * Reported by cms via components (#24152) as a one-off they could not reproduce;\n * it is not rare behaviour, it is a rare RESPONSE.\n *\n * Same family as the two other faults measured that day: a missing value degrading\n * into something that does not look like a missing value. Here it must look like one. */\nexport function errorBody(json: unknown, rawText?: string): string {\n const fallback = rawText && rawText.trim() ? rawText.slice(0, 300) : \"(no body)\";\n if (json === undefined || json === null) return fallback;\n if (typeof json === \"string\") return json.slice(0, 300);\n try {\n return (JSON.stringify(json) ?? fallback).slice(0, 300);\n } catch {\n return fallback; // circular / non-serialisable — still must not throw\n }\n}\n","// Subprocess transport: runs the local `claude -p` CLI (Anthropic Max plan).\n// No API key, no metered charge — costUsd is always 0, flagged subprocess:true so\n// dashboards can split free (Max) from paid (API). Token counts still come back\n// from the CLI's JSON so usage is tracked even when cost is zero.\nimport type { TransportRequest, SubprocessResponse } from \"./types.js\";\n\n/** The subset of `claude -p --output-format json` output we read. The CLI emits\n * more fields; we only need the result text + token usage. */\ninterface ClaudeCliJson {\n result?: string;\n usage?: {\n input_tokens?: number;\n output_tokens?: number;\n cache_creation_input_tokens?: number;\n cache_read_input_tokens?: number;\n };\n}\n\n/** Pure parser for the `claude -p --output-format json` stdout. Exported so it\n * can be unit-tested without spawning the binary. costUsd is pinned to 0. */\nexport function parseClaudeCliJson(raw: string): SubprocessResponse {\n let parsed: ClaudeCliJson;\n try {\n parsed = JSON.parse(raw) as ClaudeCliJson;\n } catch {\n throw new Error(\n `subprocessTransport: could not parse claude -p JSON output: ${raw.slice(0, 200)}`,\n );\n }\n const u = parsed.usage ?? {};\n return {\n text: parsed.result ?? \"\",\n inputTokens: u.input_tokens ?? 0,\n outputTokens: u.output_tokens ?? 0,\n cacheReadTokens: u.cache_read_input_tokens ?? 0,\n cacheCreationTokens: u.cache_creation_input_tokens ?? 0,\n costUsd: 0,\n subprocess: true,\n };\n}\n\nexport async function subprocessTransport(\n req: TransportRequest,\n): Promise<SubprocessResponse> {\n if (!req.subprocess) {\n throw new Error(\"subprocessTransport: req.subprocess is required for subprocess transport\");\n }\n const { prompt, systemPrompt } = req.subprocess;\n\n const cmd = [\"claude\", \"-p\", \"--output-format\", \"json\", \"--model\", req.spec.model];\n if (systemPrompt) cmd.push(\"--system-prompt\", systemPrompt);\n\n // Prompt goes in on stdin as a Blob (no argv length limit, no manual FileSink).\n const proc = (() => {\n try {\n return Bun.spawn(cmd, {\n stdin: new Blob([prompt]),\n stdout: \"pipe\",\n stderr: \"pipe\",\n });\n } catch (err) {\n throw new Error(\n `subprocessTransport: failed to spawn 'claude' — is the CLI installed and on PATH? (${String(err)})`,\n );\n }\n })();\n\n const [stdout, stderr, exitCode] = await Promise.all([\n new Response(proc.stdout).text(),\n new Response(proc.stderr).text(),\n proc.exited,\n ]);\n\n if (exitCode !== 0) {\n throw new Error(\n `subprocessTransport: claude -p exited ${exitCode}: ${stderr.slice(0, 300) || stdout.slice(0, 300)}`,\n );\n }\n\n return parseClaudeCliJson(stdout);\n}\n","// SSE streaming transport (F8.1). Like httpTransport but yields the parsed\n// `data:` payloads from the response body instead of awaiting .json() — pure\n// fetch + a ReadableStream reader, so it is Node 18+ and Bun safe. The adapter\n// supplies the `stream:true` body and parses each yielded JSON string itself.\nimport type { TransportRequest } from \"./types.js\";\n\n/** HTTP error from a streaming connect — carries `status` so the client's\n * pre-stream fallback can tell an eligible 429/5xx from a hard 4xx. */\nexport class StreamHttpError extends Error {\n readonly status: number;\n constructor(message: string, status: number) {\n super(message);\n this.name = \"StreamHttpError\";\n this.status = status;\n }\n}\n\nexport interface StreamTransportRequest extends TransportRequest {\n /** Injectable fetch for tests. */\n fetch?: typeof fetch;\n}\n\n/**\n * Open an SSE stream and yield each event's `data:` payload as a raw string\n * (the JSON after `data: `), skipping the `[DONE]` terminator and non-data\n * lines. Throws StreamHttpError before the first yield on a non-2xx connect.\n */\nexport async function* streamTransport(req: StreamTransportRequest): AsyncIterable<string> {\n if (!req.http) throw new Error(\"streamTransport: req.http is required for http transport\");\n const { url, method = \"POST\", headers, body } = req.http;\n const fetchImpl = req.fetch ?? fetch;\n const res = await fetchImpl(url, {\n method,\n headers,\n body:\n body === undefined\n ? undefined\n : typeof body === \"string\"\n ? body\n : JSON.stringify(body),\n });\n if (!res.ok || !res.body) {\n const text = await res.text().catch(() => \"\");\n throw new StreamHttpError(`stream ${res.status}: ${text.slice(0, 300)}`, res.status);\n }\n const reader = res.body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n // OpenAI/Anthropic emit one `data: {json}\\n\\n` per event — parse per line.\n let nl: number;\n while ((nl = buffer.indexOf(\"\\n\")) >= 0) {\n const line = buffer.slice(0, nl).replace(/\\r$/, \"\");\n buffer = buffer.slice(nl + 1);\n if (!line.startsWith(\"data:\")) continue; // skip comments / event: / id:\n const data = line.slice(5).trim();\n if (data === \"[DONE]\") return;\n if (data) yield data;\n }\n }\n } finally {\n reader.releaseLock();\n }\n}\n","// Cross-provider tool/function-calling normalization. The SDK speaks one Tool /\n// ToolCall shape; each provider has its own. toProviderTools builds the request\n// tools array; fromProviderToolCall parses one tool-call out of a response.\n// OpenAI, DeepInfra and OpenRouter share the OpenAI-compatible format.\nimport type { ToolCallLike, Tool, ToolCall } from \"../types.js\";\n\ntype ToolProvider = \"openai\" | \"deepinfra\" | \"openrouter\" | \"gemini\" | \"anthropic\";\n\nfunction family(provider: string): ToolProvider {\n if (provider === \"gemini\" || provider === \"google\") return \"gemini\";\n if (provider === \"anthropic\") return \"anthropic\";\n // openai, deepinfra, openrouter — all OpenAI-compatible\n return \"openai\";\n}\n\n/** Convert SDK tools to a provider's request format. */\nexport function toProviderTools(tools: Tool[], provider: string): unknown {\n switch (family(provider)) {\n case \"openai\":\n return tools.map((t) => ({\n type: \"function\",\n function: { name: t.name, description: t.description, parameters: t.parameters },\n }));\n case \"gemini\":\n return [\n {\n functionDeclarations: tools.map((t) => ({\n name: t.name,\n description: t.description,\n parameters: t.parameters,\n })),\n },\n ];\n case \"anthropic\":\n return tools.map((t) => ({\n name: t.name,\n description: t.description,\n input_schema: t.parameters,\n }));\n default:\n throw new Error(`toProviderTools: unsupported provider family for \"${provider}\"`);\n }\n}\n\n/** Parse a single provider-shaped tool call back into the SDK ToolCall shape. */\nexport function fromProviderToolCall(raw: unknown, provider: string): ToolCall {\n const r = raw as Record<string, unknown>;\n switch (family(provider)) {\n case \"openai\": {\n // { id, type:\"function\", function:{ name, arguments:\"<json>\" } }\n const fn = (r.function ?? {}) as { name?: string; arguments?: string };\n return {\n id: typeof r.id === \"string\" ? r.id : \"\",\n name: fn.name ?? \"\",\n arguments: parseArgs(fn.arguments),\n };\n }\n case \"gemini\": {\n // { functionCall:{ name, args } } or { name, args }\n const fc = (r.functionCall ?? r) as { name?: string; args?: unknown };\n return {\n id: \"\", // Gemini function calls have no id\n name: fc.name ?? \"\",\n arguments: (fc.args as Record<string, unknown>) ?? {},\n };\n }\n case \"anthropic\": {\n // { type:\"tool_use\", id, name, input }\n return {\n id: typeof r.id === \"string\" ? r.id : \"\",\n name: typeof r.name === \"string\" ? r.name : \"\",\n arguments: (r.input as Record<string, unknown>) ?? {},\n };\n }\n default:\n throw new Error(`fromProviderToolCall: unsupported provider family for \"${provider}\"`);\n }\n}\n\nfunction parseArgs(raw: unknown): Record<string, unknown> {\n if (raw === undefined || raw === null) return {};\n if (typeof raw === \"object\") return raw as Record<string, unknown>;\n if (typeof raw === \"string\") {\n try {\n return JSON.parse(raw) as Record<string, unknown>;\n } catch {\n return {};\n }\n }\n return {};\n}\n\n/** Read a tool call's arguments regardless of which spelling the caller used.\n * `arguments` is ours and wins; `args` is what @broberg/chat emits. See ToolCallLike\n * in types.ts for why both are accepted rather than one of us renaming. */\nexport function toolCallArgs(tc: ToolCallLike): Record<string, unknown> {\n return tc.arguments ?? tc.args ?? {};\n}\n","// F042 — where did the data actually go?\n//\n// The obvious implementation of this file is a table keyed on provider name, and it\n// would LIE for three of our adapters in the direction that matters. vertex, azure and\n// bfl are EU by default and by intent — that is why they exist — but each takes an\n// override (a GCP region, an Azure region, a base URL), so a consumer can point them\n// outside the EU while the provider name stays the same. A residency field that is\n// right by default and wrong precisely when someone changed something is worse than no\n// field at all, because it gets trusted.\n//\n// So the rule here is: the region is a property of the ENDPOINT WE CALLED. For the\n// adapters whose host is fixed in code, that derivation collapses to a constant (this\n// file). For the three that vary, the adapter passes the locator it actually used.\n\n/** Coarse data-residency of the endpoint a call went to.\n *\n * - `\"eu\"` — EU/EEA. **The only positive residency claim.** Nothing else is folded\n * in: an adequacy decision is not EU residency, so the UK, Switzerland\n * and Canada are deliberately NOT `\"eu\"` here.\n * - `\"us\"` — United States.\n * - `\"cn\"` — China.\n * - `\"unknown\"` — we genuinely cannot say: an aggregator that picks its own upstream,\n * or a region string we do not recognise.\n *\n * **`\"unknown\"` is NOT a synonym for safe.** `region !== \"us\"` is not an EU check —\n * it passes every OpenRouter call. Only `region === \"eu\"` may be treated as EU-resident.\n */\nexport type Region = \"eu\" | \"us\" | \"cn\" | \"unknown\";\n\n/** Region by HOST — the primary derivation, because it reads the thing that actually\n * decides: the URL we are about to call.\n *\n * The first version of this module keyed on provider NAME and carved out three\n * adapters as \"the configurable ones\". That carve-out was wrong: `mistralAdapter`\n * and `deeplAdapter` also take a `baseUrl`, so pointing Mistral — our designated\n * personal-data route — at a non-EU gateway still reported `region: \"eu\"`. A false\n * EU claim, in the module written to prevent false EU claims. Found in review of\n * F042 itself, which is the honest place to record it.\n *\n * An unlisted host is \"unknown\", never a guess: a custom gateway is exactly the case\n * where we cannot know, and the whole contract is that only \"eu\" is a claim. */\nconst HOST_REGION: Record<string, Region> = {\n \"api.mistral.ai\": \"eu\",\n \"api.deepl.com\": \"eu\",\n \"api-free.deepl.com\": \"eu\",\n \"api.eu.bfl.ai\": \"eu\",\n \"api.openai.com\": \"us\",\n \"api.anthropic.com\": \"us\",\n \"api.deepinfra.com\": \"us\",\n \"generativelanguage.googleapis.com\": \"us\",\n \"api.elevenlabs.io\": \"us\",\n \"fal.run\": \"us\",\n \"queue.fal.run\": \"us\",\n \"api.deepseek.com\": \"cn\",\n // Aggregators: the host is theirs, the upstream is not ours to know.\n \"openrouter.ai\": \"unknown\",\n \"router.requesty.ai\": \"unknown\",\n};\n\n/** Region of the endpoint a call will actually hit. Never throws — a residency\n * reading must not be able to break a call that already succeeded. */\nexport function regionOfHost(hostOrUrl: string | undefined): Region {\n if (!hostOrUrl) return \"unknown\";\n // A BARE HOSTNAME IS VALID INPUT. The first version required a full URL, so\n // regionOfHost(\"api.mistral.ai\") — the most natural thing to hand a function with\n // that name — answered \"unknown\", and a fail-closed guard built on it rejected\n // EVERYTHING including the one EU route. Found by components immediately after we\n // shipped the warning about the same trap in regionOfProvider: we fixed the\n // name-keyed function and left the host-keyed one with the identical shape.\n const trimmed = hostOrUrl.trim();\n if (!trimmed) return \"unknown\";\n let host = \"\";\n try {\n host = new URL(trimmed).host;\n } catch {\n /* not a URL — handled below */\n }\n // A SUCCESSFUL PARSE IS NOT A USABLE HOST. new URL(\"api.mistral.ai:443\") does NOT\n // throw: it reads \"api.mistral.ai:\" as a SCHEME and \"443\" as the path, and hands back\n // host === \"\". So the catch never ran and the answer was \"unknown\" — a call that\n // succeeded and told us nothing, which is the shape this whole module keeps removing.\n // Falling through on an empty host is the difference between \"parsed\" and \"answered\".\n if (!host) {\n // Read it as a host: take only the authority, so \"api.mistral.ai/v1\" and\n // \"api.mistral.ai:443\" both resolve, and drop any credentials before the @.\n host = trimmed.split(\"/\")[0]!.split(\"@\").pop()!.split(\":\")[0]!;\n }\n host = host.toLowerCase();\n // Exact match only — never a suffix test. \"api.mistral.ai.evil.com\" must not inherit\n // Mistral's EU claim, and an endsWith() check is how that would happen.\n return Object.hasOwn(HOST_REGION, host) ? (HOST_REGION[host] as Region) : \"unknown\";\n}\n\n/** Adapters whose endpoint is FIXED in code — there is no config that moves them, so\n * the provider name IS the region. Anything absent here must pass its region\n * explicitly; the fallback is `\"unknown\"`, never a guess in the reassuring direction. */\nconst FIXED_PROVIDER_REGION: Record<string, Region> = {\n // NB: mistral and deepl are deliberately ABSENT — both take a config.baseUrl, so\n // their region is a property of the URL, not of the name. They derive via\n // regionOfHost. Anything left here genuinely cannot be moved by config.\n openai: \"us\",\n anthropic: \"us\",\n // generativelanguage.googleapis.com is Google's GLOBAL endpoint, not a US-pinned one.\n // We report \"us\" rather than \"unknown\" because it is certainly not EU-resident, and\n // the honest error direction for a residency field is away from an EU claim. Vertex\n // (below, region-pinned) is the route to use when EU residency is required.\n gemini: \"us\",\n deepinfra: \"us\",\n fal: \"us\",\n elevenlabs: \"us\",\n // api.deepseek.com — People's Republic of China. No EU adequacy decision at all,\n // which is a materially different position from the US, hence its own value.\n deepseek: \"cn\",\n // Aggregators: they choose the upstream provider per request, so the region is not\n // ours to know. Reporting anything else here would be inventing a fact.\n openrouter: \"unknown\",\n requesty: \"unknown\",\n};\n\n/** GCP + Azure region names we recognise as EU/EEA. Norway is EEA and counts.\n * Switzerland and the UK are deliberately absent — adequate, but not EU/EEA. */\nconst EU_REGION_NAMES = new Set([\n // Azure\n \"westeurope\",\n \"northeurope\",\n \"swedencentral\",\n \"francecentral\",\n \"francesouth\",\n \"germanywestcentral\",\n \"germanynorth\",\n \"norwayeast\",\n \"norwaywest\",\n \"polandcentral\",\n \"italynorth\",\n \"spaincentral\",\n]);\n\nconst US_REGION_NAMES = new Set([\n // Azure\n \"eastus\",\n \"eastus2\",\n \"westus\",\n \"westus2\",\n \"westus3\",\n \"centralus\",\n \"northcentralus\",\n \"southcentralus\",\n \"westcentralus\",\n]);\n\n/** Classify a provider REGION STRING — a Vertex/GCP location like `europe-west1`, or\n * an Azure region like `westeurope`. Anything unrecognised is `\"unknown\"`: a region\n * name we have never seen is exactly the case where guessing is most tempting and\n * least defensible. Never throws — a residency reading must not be able to break a\n * call that already succeeded. */\nexport function classifyRegionName(name: string | undefined): Region {\n if (!name) return \"unknown\";\n const n = name.trim().toLowerCase();\n if (!n) return \"unknown\";\n // A Region value passed straight back in. \"eu\" is what this function RETURNS and\n // what a consumer compares against, so handing it in is the obvious mistake — and\n // answering \"unknown\" to \"eu\" is the kind of confident wrong answer this module\n // keeps having to remove. Identity is the honest reply.\n if (n === \"eu\" || n === \"us\" || n === \"cn\" || n === \"unknown\") return n as Region;\n // GCP-style: europe-west1, europe-north1, us-central1, …\n if (n.startsWith(\"europe-\")) return \"eu\";\n if (n.startsWith(\"us-\")) return \"us\";\n if (EU_REGION_NAMES.has(n)) return \"eu\";\n if (US_REGION_NAMES.has(n)) return \"us\";\n return \"unknown\";\n}\n\n/** Region for an adapter whose endpoint is fixed. Unknown provider → `\"unknown\"`.\n *\n * **DO NOT BUILD A RESIDENCY GUARD ON THIS.** Use {@link regionOfHost} on the base URL\n * the call will actually use. Found by a consumer building exactly that guard (super,\n * 2026-08-30): `regionOfProvider(\"mistral\")` is `\"unknown\"` — correct, because Mistral\n * takes a `baseUrl` and a name cannot answer for residency — but a guard written as\n * `regionOfProvider(p) === \"eu\"` therefore REJECTS Mistral, which is the only EU route\n * we have. It fails closed and is useless: it filters out the thing it exists to allow.\n *\n * The trap is invisible from the signature, which is why it is written here rather than\n * only in the docs. This function answers \"is this provider's endpoint fixed, and where\n * is it?\" — a narrower question than \"where will my call go?\". */\nexport function regionOfProvider(provider: string): Region {\n // Object.hasOwn, NOT a bare lookup + ??. A plain object inherits from\n // Object.prototype, so FIXED_PROVIDER_REGION[\"constructor\"] returns a FUNCTION and\n // the ?? fallback never fires — putting a function where a Region belongs. It fails\n // safe against `region === \"eu\"`, but it serialises to nothing, so a cost sink would\n // record a Usage with no region at all: a missing value that does not look like one,\n // in the very feature built to stop that. Not reachable today (every caller passes a\n // hardcoded adapter name) — fixed because \"not reachable yet\" is not a property we\n // control from here.\n return Object.hasOwn(FIXED_PROVIDER_REGION, provider)\n ? (FIXED_PROVIDER_REGION[provider] as Region)\n : \"unknown\";\n}\n","// Usage construction + cost computation. Real adapters (F4) build their Usage via\n// freshUsage() and fill costUsd from computeCost(). The pricing table lives in\n// ./pricing.ts (F3.6); until a model is priced, computeCost returns 0 so calls\n// still complete (cost just shows $0 rather than throwing).\nimport { getPrice } from \"./pricing.js\";\nimport { regionOfProvider, type Region } from \"./region.js\";\nimport type { Usage, Transport, Capability } from \"../types.js\";\n\n/**\n * Cost in USD for a call. cache-read/creation tokens are priced separately when\n * the pricing entry defines rates for them; otherwise they fall back to the\n * input rate (read) / are ignored (creation). Unknown model → 0.\n */\nexport function computeCost(\n provider: string,\n model: string,\n inputTokens: number,\n outputTokens: number,\n cacheReadTokens = 0,\n cacheCreationTokens = 0,\n): number {\n const price = getPrice(provider, model);\n if (!price) return 0;\n const perToken = (per1M: number) => per1M / 1_000_000;\n const inRate = perToken(price.inputPer1M);\n const outRate = perToken(price.outputPer1M);\n const cacheReadRate =\n price.cacheReadPer1M !== undefined ? perToken(price.cacheReadPer1M) : inRate;\n const cacheWriteRate =\n price.cacheWritePer1M !== undefined ? perToken(price.cacheWritePer1M) : inRate;\n return (\n inputTokens * inRate +\n outputTokens * outRate +\n cacheReadTokens * cacheReadRate +\n cacheCreationTokens * cacheWriteRate\n );\n}\n\n/** Build a Usage with cost computed from the pricing table. Adapters call this\n * after a successful provider call; latencyMs/ts/capability are stamped by the\n * client (call-context owner), so they default to 0/\"\"/the passed capability. */\nexport function freshUsage(args: {\n provider: string;\n model: string;\n transport: Transport;\n capability: Capability;\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens?: number;\n cacheCreationTokens?: number;\n /** Data residency of the endpoint this call ACTUALLY used (F042). Pass it from any\n * adapter whose region a consumer can change — vertex, azure, bfl. Omitting it\n * falls back to the fixed provider table, which does not list those three, so a\n * forgetful adapter degrades to \"unknown\" rather than to a false \"eu\". */\n region?: Region;\n subprocess?: boolean;\n}): Usage {\n const cacheReadTokens = args.cacheReadTokens ?? 0;\n const cacheCreationTokens = args.cacheCreationTokens ?? 0;\n // Subprocess (Max plan) is never a metered charge to us — cost is always 0.\n const costUsd = args.subprocess\n ? 0\n : computeCost(\n args.provider,\n args.model,\n args.inputTokens,\n args.outputTokens,\n cacheReadTokens,\n cacheCreationTokens,\n );\n const usage: Usage = {\n provider: args.provider,\n model: args.model,\n region: args.region ?? regionOfProvider(args.provider),\n transport: args.transport,\n inputTokens: args.inputTokens,\n outputTokens: args.outputTokens,\n cacheReadTokens,\n cacheCreationTokens,\n costUsd,\n latencyMs: 0,\n capability: args.capability,\n ts: \"\",\n };\n if (args.subprocess) usage.subprocess = true;\n return usage;\n}\n","// Anthropic adapter (F4.6) — the real one (F2.5 shipped only a stub). Two\n// transports: http (api.anthropic.com/v1/messages) and subprocess (claude -p,\n// Max plan, costUsd 0). Critical for the xrt81 vision pilot. Tools normalized\n// via F4.5. No @anthropic-ai/sdk package — plain fetch through httpTransport.\nimport { httpTransport, errorBody } from \"../transport/http.js\";\nimport { subprocessTransport } from \"../transport/subprocess.js\";\nimport { streamTransport } from \"../transport/stream.js\";\nimport { toolCallArgs, toProviderTools, fromProviderToolCall } from \"./tools.js\";\nimport { freshUsage } from \"../cost/usage.js\";\nimport type {\n ProviderAdapter,\n ChatRequest,\n ChatResult,\n ChatStreamEvent,\n Message,\n ContentPart,\n ToolCall,\n} from \"../types.js\";\n\ninterface AnthropicBlock {\n type: string;\n text?: string;\n id?: string;\n name?: string;\n input?: Record<string, unknown>;\n}\ninterface AnthropicResponse {\n content?: AnthropicBlock[];\n usage?: {\n input_tokens?: number;\n output_tokens?: number;\n cache_read_input_tokens?: number;\n cache_creation_input_tokens?: number;\n };\n error?: unknown;\n}\n\nfunction contentBlocks(content: string | ContentPart[]): unknown {\n if (typeof content === \"string\") return content;\n return content.map((p) => {\n if (p.type === \"text\") return { type: \"text\", text: p.text };\n // Anthropic has no native video input — route video via a video-capable\n // provider (Gemini, F019) instead.\n if (p.type === \"video\") {\n throw new Error(\"anthropic adapter: video input is not supported — use a video provider (e.g. gemini)\");\n }\n if (typeof p.image === \"string\" && /^https?:\\/\\//.test(p.image)) {\n return { type: \"image\", source: { type: \"url\", url: p.image } };\n }\n const data =\n typeof p.image === \"string\"\n ? p.image.replace(/^data:[^;]+;base64,/, \"\")\n : Buffer.from(p.image).toString(\"base64\");\n return {\n type: \"image\",\n source: { type: \"base64\", media_type: p.mimeType ?? \"image/png\", data },\n };\n });\n}\n\n/** Flatten messages to a single prompt for the subprocess (claude -p) path. */\nfunction flattenForSubprocess(messages: Message[]): { prompt: string; system?: string } {\n const sys: string[] = [];\n const turns: string[] = [];\n for (const m of messages) {\n const text =\n typeof m.content === \"string\"\n ? m.content\n : m.content.map((p) => (p.type === \"text\" ? p.text : \"[image]\")).join(\" \");\n if (m.role === \"system\") sys.push(text);\n else turns.push(`${m.role}: ${text}`);\n }\n return { prompt: turns.join(\"\\n\\n\"), system: sys.length ? sys.join(\"\\n\") : undefined };\n}\n\nexport function anthropicAdapter(\n config: { apiKey?: string; baseUrl?: string; anthropicVersion?: string; fetch?: typeof fetch } = {},\n): ProviderAdapter {\n const baseUrl = config.baseUrl ?? \"https://api.anthropic.com\";\n const version = config.anthropicVersion ?? \"2023-06-01\";\n\n /** Build the /v1/messages body (shared by the http + stream paths). */\n function buildBody(req: ChatRequest): Record<string, unknown> {\n const system: string[] = [];\n const messages: { role: string; content: unknown }[] = [];\n for (const m of req.messages as Message[]) {\n if (m.role === \"system\") {\n system.push(typeof m.content === \"string\" ? m.content : \"\");\n continue;\n }\n // tool-result turn → a user message carrying a tool_result block (F8.7).\n if (m.role === \"tool\") {\n messages.push({\n role: \"user\",\n content: [\n {\n type: \"tool_result\",\n tool_use_id: m.toolCallId ?? \"\",\n content: typeof m.content === \"string\" ? m.content : \"\",\n },\n ],\n });\n continue;\n }\n // assistant turn that called tools → text blocks + tool_use blocks (F8.7).\n if (m.role === \"assistant\" && m.toolCalls && m.toolCalls.length > 0) {\n const blocks: unknown[] = [];\n if (typeof m.content === \"string\") {\n if (m.content.length > 0) blocks.push({ type: \"text\", text: m.content });\n } else {\n blocks.push(...(contentBlocks(m.content) as unknown[]));\n }\n for (const tc of m.toolCalls) {\n blocks.push({ type: \"tool_use\", id: tc.id, name: tc.name, input: toolCallArgs(tc) });\n }\n messages.push({ role: \"assistant\", content: blocks });\n continue;\n }\n messages.push({ role: m.role === \"assistant\" ? \"assistant\" : \"user\", content: contentBlocks(m.content) });\n }\n const body: Record<string, unknown> = {\n model: req.spec.model,\n max_tokens: req.maxTokens ?? 1024, // Anthropic requires max_tokens\n messages,\n };\n if (system.length > 0) body.system = system.join(\"\\n\");\n if (req.tools) body.tools = toProviderTools(req.tools, \"anthropic\");\n if (req.temperature !== undefined) body.temperature = req.temperature;\n return body;\n }\n\n function apiKeyOrThrow(): string {\n const apiKey = config.apiKey ?? process.env.ANTHROPIC_API_KEY;\n if (!apiKey) throw new Error(\"anthropic adapter: API key not set (env ANTHROPIC_API_KEY)\");\n return apiKey;\n }\n\n async function chatHttp(req: ChatRequest): Promise<ChatResult> {\n const apiKey = apiKeyOrThrow();\n const body = buildBody(req);\n\n const res = await httpTransport({\n spec: req.spec,\n http: {\n url: `${baseUrl}/v1/messages`,\n headers: {\n \"content-type\": \"application/json\",\n \"x-api-key\": apiKey,\n \"anthropic-version\": version,\n },\n body,\n },\n });\n if (!res.ok) throw new Error(`anthropic ${res.status}: ${errorBody(res.json, res.text)}`);\n\n const data = res.json as AnthropicResponse;\n const blocks = data.content ?? [];\n const text = blocks\n .filter((b) => b.type === \"text\" && typeof b.text === \"string\")\n .map((b) => b.text)\n .join(\"\");\n const toolCalls: ToolCall[] = blocks\n .filter((b) => b.type === \"tool_use\")\n .map((b) => fromProviderToolCall(b, \"anthropic\"));\n\n const usage = freshUsage({\n provider: \"anthropic\",\n model: req.spec.model,\n transport: \"http\",\n capability: \"chat\",\n inputTokens: data.usage?.input_tokens ?? 0,\n outputTokens: data.usage?.output_tokens ?? 0,\n cacheReadTokens: data.usage?.cache_read_input_tokens ?? 0,\n cacheCreationTokens: data.usage?.cache_creation_input_tokens ?? 0,\n });\n const result: ChatResult = { text, usage };\n if (toolCalls.length > 0) result.toolCalls = toolCalls;\n return result;\n }\n\n async function chatSubprocess(req: ChatRequest): Promise<ChatResult> {\n const { prompt, system } = flattenForSubprocess(req.messages as Message[]);\n const r = await subprocessTransport({ spec: req.spec, subprocess: { prompt, systemPrompt: system } });\n const usage = freshUsage({\n provider: \"anthropic\",\n model: req.spec.model,\n transport: \"subprocess\",\n capability: \"chat\",\n inputTokens: r.inputTokens,\n outputTokens: r.outputTokens,\n cacheReadTokens: r.cacheReadTokens,\n cacheCreationTokens: r.cacheCreationTokens,\n subprocess: true,\n });\n return { text: r.text, usage };\n }\n\n async function chat(req: ChatRequest): Promise<ChatResult> {\n return req.spec.transport === \"subprocess\" ? chatSubprocess(req) : chatHttp(req);\n }\n\n // Streaming chat (F8.4) over the native /v1/messages SSE. Maps\n // content_block_delta(text_delta) → text events, accumulates tool_use blocks\n // (id/name from content_block_start, input from input_json_delta) → complete\n // tool_call events, and reads usage from message_start + message_delta. Only\n // the http transport streams — `claude -p` subprocess is one-shot.\n async function* chatStream(req: ChatRequest): AsyncIterable<ChatStreamEvent> {\n if (req.spec.transport === \"subprocess\") {\n throw new Error(\"anthropic adapter: streaming is not supported over the subprocess transport\");\n }\n const apiKey = apiKeyOrThrow();\n const body = { ...buildBody(req), stream: true };\n const stream = streamTransport({\n spec: req.spec,\n fetch: config.fetch,\n http: {\n url: `${baseUrl}/v1/messages`,\n headers: {\n \"content-type\": \"application/json\",\n \"x-api-key\": apiKey,\n \"anthropic-version\": version,\n },\n body,\n },\n });\n\n let inputTokens = 0;\n let outputTokens = 0;\n let cacheReadTokens = 0;\n let cacheCreationTokens = 0;\n let stopReason: string | null = null;\n // index → accumulated tool_use block (input_json_delta fragments concatenated).\n const toolBlocks = new Map<number, { id: string; name: string; json: string }>();\n\n for await (const data of stream) {\n let ev: AnthropicStreamEvent;\n try {\n ev = JSON.parse(data) as AnthropicStreamEvent;\n } catch {\n continue;\n }\n switch (ev.type) {\n case \"message_start\": {\n const u = ev.message?.usage;\n inputTokens = u?.input_tokens ?? 0;\n cacheReadTokens = u?.cache_read_input_tokens ?? 0;\n cacheCreationTokens = u?.cache_creation_input_tokens ?? 0;\n break;\n }\n case \"content_block_start\": {\n if (ev.content_block?.type === \"tool_use\" && ev.index !== undefined) {\n toolBlocks.set(ev.index, {\n id: ev.content_block.id ?? \"\",\n name: ev.content_block.name ?? \"\",\n json: \"\",\n });\n }\n break;\n }\n case \"content_block_delta\": {\n const d = ev.delta;\n if (d?.type === \"text_delta\" && d.text) {\n yield { type: \"text\", delta: d.text };\n } else if (d?.type === \"input_json_delta\" && d.partial_json && ev.index !== undefined) {\n const b = toolBlocks.get(ev.index);\n if (b) b.json += d.partial_json;\n }\n break;\n }\n case \"message_delta\": {\n if (ev.delta?.stop_reason) stopReason = ev.delta.stop_reason;\n if (ev.usage?.output_tokens !== undefined) outputTokens = ev.usage.output_tokens;\n break;\n }\n default:\n break; // content_block_stop / message_stop / ping\n }\n }\n\n for (const [, b] of [...toolBlocks.entries()].sort((a, c) => a[0] - c[0])) {\n let args: Record<string, unknown> = {};\n try {\n args = b.json ? (JSON.parse(b.json) as Record<string, unknown>) : {};\n } catch {\n args = {};\n }\n yield { type: \"tool_call\", id: b.id, name: b.name, args };\n }\n const usage = freshUsage({\n provider: \"anthropic\",\n model: req.spec.model,\n transport: \"http\",\n capability: \"chat\",\n inputTokens,\n outputTokens,\n cacheReadTokens,\n cacheCreationTokens,\n });\n yield { type: \"usage\", costUsd: usage.costUsd, model: usage.model, usage };\n yield { type: \"finish\", reason: mapAnthropicStop(stopReason) };\n }\n\n return { name: \"anthropic\", chat, chatStream, vision: chat };\n}\n\n/** Anthropic Messages SSE event (only the fields we read). */\ninterface AnthropicStreamEvent {\n type: string;\n index?: number;\n message?: {\n usage?: {\n input_tokens?: number;\n cache_read_input_tokens?: number;\n cache_creation_input_tokens?: number;\n };\n };\n content_block?: { type?: string; id?: string; name?: string };\n delta?: { type?: string; text?: string; partial_json?: string; stop_reason?: string };\n usage?: { output_tokens?: number };\n}\n\n/** Map Anthropic stop_reason → the SDK's ChatStreamEvent finish reason. */\nfunction mapAnthropicStop(reason: string | null): \"end_turn\" | \"tool_calls\" | \"length\" | \"stop\" {\n switch (reason) {\n case \"tool_use\":\n return \"tool_calls\";\n case \"max_tokens\":\n return \"length\";\n case \"stop_sequence\":\n return \"stop\";\n default:\n return \"end_turn\";\n }\n}\n","// Shared core for OpenAI-compatible chat APIs. OpenAI (F4.1), DeepInfra (F4.3)\n// and OpenRouter (F4.4) all speak this wire format — only base URL, key and a\n// couple of headers differ. The adapter uses httpTransport (F2.4) for the wire\n// I/O and the F4.5 tool contract for tool round-tripping.\nimport { httpTransport, errorBody } from \"../transport/http.js\";\nimport { streamTransport } from \"../transport/stream.js\";\nimport { toolCallArgs, toProviderTools, fromProviderToolCall } from \"./tools.js\";\nimport { freshUsage } from \"../cost/usage.js\";\nimport { regionOfHost } from \"../cost/region.js\";\nimport type {\n ProviderAdapter,\n ChatRequest,\n ChatResult,\n ChatStreamEvent,\n Message,\n ToolCall,\n} from \"../types.js\";\n\nexport interface OpenAICompatibleConfig {\n /** Provider name recorded on Usage (e.g. \"openai\", \"deepinfra\", \"openrouter\"). */\n name: string;\n /** Chat completions base, e.g. \"https://api.openai.com/v1\". */\n baseUrl: string;\n /** Resolved at call time if omitted (env var per provider). */\n apiKey?: string;\n /** Extra headers (e.g. OpenRouter's HTTP-Referer / X-Title). */\n extraHeaders?: Record<string, string>;\n /** Injectable fetch for the streaming path (tests). */\n fetch?: typeof fetch;\n /** OpenRouter ground-truth cost (F010): send `usage:{include:true}` and use the\n * response's `usage.cost` (USD) as costUsd, falling back to the pricing table.\n * Only OpenRouter returns this field — openai/deepinfra leave it false. */\n costFromResponseField?: boolean;\n /** F039.2 — this provider accepts `prompt_cache_key` and caches a shared prefix\n * on it. Mistral only, deliberately: an unknown field is ignored by some\n * OpenAI-compatible servers and rejected with a 400 by others, so sending it\n * everywhere would trade a saving for an outage. Providers that cache\n * AUTOMATICALLY (openai, deepseek, gemini) need no key — they only need their\n * cached counts read back, which happens for every provider below. */\n supportsPromptCacheKey?: boolean;\n}\n\n/** A stable cache key derived from the fixed part of the prompt (F039.2).\n *\n * Content-derived on purpose. The key is a shared-prefix identity, so a key\n * collision must never mean two callers with DIFFERENT content share a bucket —\n * deriving it from the content makes a collision imply the content was identical,\n * and identical content cannot leak anything the other party did not already send.\n * (An id-derived default — \"conversation 42\" — would collide across tenants with\n * different content. That is the trap components flagged.)\n *\n * Only the leading system message is hashed: it is the part that repeats verbatim\n * across every call in an app, which is exactly what caching pays for. */\nfunction autoCacheKey(messages: { role: string; content: unknown }[]): string | undefined {\n const system = messages.find((m) => m.role === \"system\");\n if (!system || typeof system.content !== \"string\" || system.content.length < 200) return undefined;\n let h = 0x811c9dc5;\n for (let i = 0; i < system.content.length; i++) {\n h ^= system.content.charCodeAt(i);\n h = Math.imul(h, 0x01000193) >>> 0;\n }\n return `ai-sdk-auto-${h.toString(16)}-${system.content.length}`;\n}\n\ninterface OAToolCall {\n id?: string;\n function?: { name?: string; arguments?: string };\n}\ninterface OAResponse {\n choices?: { message?: { content?: string | null; tool_calls?: OAToolCall[] } }[];\n usage?: {\n prompt_tokens?: number;\n completion_tokens?: number;\n cost?: number;\n /** Mistral (F039): how many prompt tokens were served from cache. Note that\n * prompt_tokens INCLUDES these, so they must be subtracted before billing —\n * computeCost adds cacheReadTokens ON TOP of inputTokens. */\n prompt_tokens_details?: { cached_tokens?: number };\n };\n error?: unknown;\n}\n\n/** SDK message → OpenAI message (string content, or multimodal parts for vision).\n * Threads the normalized tool form to the wire: a `tool`-role message's\n * `toolCallId` → `tool_call_id`, and an assistant message's `toolCalls` →\n * `tool_calls:[{id,type:'function',function:{name,arguments}}]` (F8.3) so a\n * multi-turn tool conversation round-trips. Exported for serialization tests. */\nexport function toOpenAIMessage(m: Message): Record<string, unknown> {\n if (typeof m.content === \"string\") {\n const base: Record<string, unknown> = { role: m.role, content: m.content };\n if (m.toolCallId) base.tool_call_id = m.toolCallId;\n if (m.toolCalls && m.toolCalls.length > 0) {\n base.tool_calls = m.toolCalls.map((tc) => ({\n id: tc.id,\n type: \"function\",\n function: { name: tc.name, arguments: JSON.stringify(toolCallArgs(tc)) },\n }));\n }\n return base;\n }\n const content = m.content.map((p) => {\n if (p.type === \"text\") return { type: \"text\", text: p.text };\n if (p.type === \"video\") {\n // F019.3 — OpenRouter video models. `video_url` mirrors `image_url`;\n // VERIFIED live 2026-06-04 against gemma-4 + nvidia-nemotron (both described\n // a real 2MB clip sent inline as a base64 data-URL).\n const url =\n typeof p.video === \"string\"\n ? p.video\n : `data:${p.mimeType ?? \"video/mp4\"};base64,${Buffer.from(p.video).toString(\"base64\")}`;\n return { type: \"video_url\", video_url: { url } };\n }\n const url =\n typeof p.image === \"string\"\n ? p.image\n : `data:${p.mimeType ?? \"image/png\"};base64,${Buffer.from(p.image).toString(\"base64\")}`;\n return { type: \"image_url\", image_url: { url } };\n });\n return { role: m.role, content };\n}\n\n/** THE ONE PLACE a chat body is built (F043).\n *\n * chat() and chatStream() used to construct this separately, and the prompt-cache\n * key was added to only one of them — so every streamed call paid full price for a\n * system prompt it had already sent, silently, behind a type that says the two take\n * the same request. components (#24153) and sanne (#24154) each measured it in the\n * published 0.34.0 tarball before we noticed.\n *\n * Keeping one builder is the actual fix. Copying the missing lines across would have\n * closed this instance and left the next added field free to drift the same way.\n * chatStream adds only `stream` + `stream_options` on top of what comes back here. */\nfunction buildChatBody(\n req: ChatRequest,\n config: Pick<OpenAICompatibleConfig, \"supportsPromptCacheKey\" | \"costFromResponseField\">,\n): Record<string, unknown> {\n const body: Record<string, unknown> = {\n model: req.spec.model,\n messages: req.messages.map(toOpenAIMessage),\n };\n if (req.tools) body.tools = toProviderTools(req.tools, \"openai\");\n if (req.maxTokens !== undefined) body.max_tokens = req.maxTokens;\n if (req.temperature !== undefined) body.temperature = req.temperature;\n if (req.responseFormat === \"json\") body.response_format = { type: \"json_object\" };\n // F039: Mistral caches a shared prefix at 10% of the input rate, but ONLY when the\n // request carries a cache key. Measured 2026-08-27: without it, an identical\n // 8,810-token prefix reported cached_tokens 0 at every size up to 57k; with it, the\n // second call reported 8,784. Dropping this field was our bug, not a vendor limit.\n // ON BY DEFAULT (F039.2). Opt-in was the wrong default: it only saves money for\n // callers who read a changelog, and this repo already learned that lesson once —\n // ~91% of Mistral spend was invisible because per-repo cost-sink wiring drifted.\n // `promptCache: false` turns it off; an explicit promptCacheKey always wins.\n if (config.supportsPromptCacheKey && req.promptCache !== false) {\n const k = req.promptCacheKey ?? autoCacheKey(req.messages);\n if (k !== undefined) body.prompt_cache_key = k;\n }\n if (config.costFromResponseField) body.usage = { include: true };\n return body;\n}\n\nexport function makeOpenAICompatibleAdapter(config: OpenAICompatibleConfig): ProviderAdapter {\n async function chat(req: ChatRequest): Promise<ChatResult> {\n const apiKey = config.apiKey ?? process.env[`${config.name.toUpperCase()}_API_KEY`];\n if (!apiKey) {\n throw new Error(`${config.name} adapter: API key not set (env ${config.name.toUpperCase()}_API_KEY)`);\n }\n const body = buildChatBody(req, config);\n\n const res = await httpTransport({\n spec: req.spec,\n http: {\n url: `${config.baseUrl}/chat/completions`,\n headers: {\n \"content-type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n ...config.extraHeaders,\n },\n body,\n },\n });\n if (!res.ok) {\n throw new Error(`${config.name} ${res.status}: ${errorBody(res.json, res.text)}`);\n }\n const data = res.json as OAResponse;\n const msg = data.choices?.[0]?.message;\n // Reasoning/multimodal models can return `content` as an array of blocks (or\n // null) instead of a plain string — coerce so callers always get a string\n // (was: `?? \"\"`, which left an array through → consumer `text.replace` crash).\n const text = contentToText(msg?.content);\n const toolCalls: ToolCall[] | undefined = msg?.tool_calls?.map((tc) =>\n fromProviderToolCall(tc, \"openai\"),\n );\n const cachedIn = data.usage?.prompt_tokens_details?.cached_tokens;\n const usage = freshUsage({\n provider: config.name,\n model: req.spec.model,\n // From the URL we actually called, not from config.name — mistral and deepseek\n // both take a baseUrl, and a custom gateway must not inherit their EU/CN claim.\n region: regionOfHost(config.baseUrl),\n transport: \"http\",\n capability: \"chat\",\n // prompt_tokens INCLUDES the cached ones; computeCost adds cacheReadTokens on\n // top of inputTokens, so billing the raw figure would charge the cached prefix\n // twice — at full rate AND at the cache rate.\n inputTokens: (data.usage?.prompt_tokens ?? 0) - (cachedIn ?? 0),\n outputTokens: data.usage?.completion_tokens ?? 0,\n // Absent field stays undefined: \"not reported\" is not the same as \"zero cached\".\n ...(cachedIn === undefined ? {} : { cacheReadTokens: cachedIn }),\n });\n if (config.costFromResponseField && typeof data.usage?.cost === \"number\") {\n usage.costUsd = data.usage.cost; // OpenRouter ground-truth beats the estimate\n }\n const result: ChatResult = { text, usage };\n if (toolCalls && toolCalls.length > 0) result.toolCalls = toolCalls;\n return result;\n }\n\n // Streaming chat (F8.2). Parses the OpenAI chat.completions SSE: content\n // deltas → text events, tool_calls deltas accumulated (index-keyed, arguments\n // string concatenated) → complete tool_call events at end, the include_usage\n // chunk → a usage event, finish_reason → the terminal finish (emitted last so\n // tool_calls + usage precede it).\n async function* chatStream(req: ChatRequest): AsyncIterable<ChatStreamEvent> {\n const apiKey = config.apiKey ?? process.env[`${config.name.toUpperCase()}_API_KEY`];\n if (!apiKey) {\n throw new Error(`${config.name} adapter: API key not set (env ${config.name.toUpperCase()}_API_KEY)`);\n }\n const body: Record<string, unknown> = {\n ...buildChatBody(req, config),\n stream: true,\n stream_options: { include_usage: true },\n };\n\n const stream = streamTransport({\n spec: req.spec,\n fetch: config.fetch,\n http: {\n url: `${config.baseUrl}/chat/completions`,\n headers: {\n \"content-type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n ...config.extraHeaders,\n },\n body,\n },\n });\n\n // index → accumulated tool call (id/name set once, arguments concatenated).\n const toolAcc = new Map<number, { id: string; name: string; args: string }>();\n let finishReason: string | null = null;\n\n for await (const data of stream) {\n let chunk: OAStreamChunk;\n try {\n chunk = JSON.parse(data) as OAStreamChunk;\n } catch {\n continue; // ignore unparseable keep-alive noise\n }\n const choice = chunk.choices?.[0];\n if (choice) {\n const delta = choice.delta ?? {};\n if (typeof delta.content === \"string\" && delta.content.length > 0) {\n yield { type: \"text\", delta: delta.content };\n }\n for (const tc of delta.tool_calls ?? []) {\n const idx = tc.index ?? 0;\n const cur = toolAcc.get(idx) ?? { id: \"\", name: \"\", args: \"\" };\n if (tc.id) cur.id = tc.id;\n if (tc.function?.name) cur.name = tc.function.name;\n if (tc.function?.arguments) cur.args += tc.function.arguments;\n toolAcc.set(idx, cur);\n }\n if (choice.finish_reason) finishReason = choice.finish_reason;\n }\n if (chunk.usage) {\n const usage = freshUsage({\n provider: config.name,\n model: req.spec.model,\n region: regionOfHost(config.baseUrl),\n transport: \"http\",\n capability: \"chat\",\n inputTokens: chunk.usage.prompt_tokens ?? 0,\n outputTokens: chunk.usage.completion_tokens ?? 0,\n });\n if (config.costFromResponseField && typeof chunk.usage.cost === \"number\") {\n usage.costUsd = chunk.usage.cost; // OpenRouter ground-truth\n }\n yield { type: \"usage\", costUsd: usage.costUsd, model: usage.model, usage };\n }\n }\n\n // Flush accumulated tool calls (complete), then the terminal finish.\n for (const [, t] of [...toolAcc.entries()].sort((a, b) => a[0] - b[0])) {\n let args: Record<string, unknown> = {};\n try {\n args = t.args ? (JSON.parse(t.args) as Record<string, unknown>) : {};\n } catch {\n args = {};\n }\n yield { type: \"tool_call\", id: t.id, name: t.name, args };\n }\n yield { type: \"finish\", reason: mapFinishReason(finishReason) };\n }\n\n return {\n name: config.name,\n chat,\n chatStream,\n // gpt-4o-class models are multimodal — vision shares the chat path.\n vision: chat,\n };\n}\n\n/** OpenAI streaming chunk shape (only the fields we read). */\ninterface OAStreamChunk {\n choices?: {\n delta?: {\n content?: string | null;\n tool_calls?: { index?: number; id?: string; function?: { name?: string; arguments?: string } }[];\n };\n finish_reason?: string | null;\n }[];\n usage?: {\n prompt_tokens?: number;\n completion_tokens?: number;\n cost?: number;\n /** Mistral (F039): how many prompt tokens were served from cache. Note that\n * prompt_tokens INCLUDES these, so they must be subtracted before billing —\n * computeCost adds cacheReadTokens ON TOP of inputTokens. */\n prompt_tokens_details?: { cached_tokens?: number };\n };\n}\n\n/** Coerce an OpenAI `message.content` to a string. Most providers return a string,\n * but reasoning/multimodal models can return an array of content blocks (or null). */\nfunction contentToText(content: unknown): string {\n if (typeof content === \"string\") return content;\n if (Array.isArray(content)) {\n return content\n .map((p) => {\n if (typeof p === \"string\") return p;\n const t = (p as { text?: unknown } | null)?.text;\n return typeof t === \"string\" ? t : \"\";\n })\n .join(\"\");\n }\n return \"\";\n}\n\n/** Map OpenAI finish_reason → the SDK's ChatStreamEvent finish reason. */\nfunction mapFinishReason(reason: string | null): \"end_turn\" | \"tool_calls\" | \"length\" | \"stop\" {\n switch (reason) {\n case \"tool_calls\":\n return \"tool_calls\";\n case \"length\":\n return \"length\";\n case \"stop\":\n return \"stop\";\n default:\n return \"end_turn\";\n }\n}\n","// OpenAI adapter (F4.1 chat/vision + F5.4 embedding). Chat/vision come from the\n// shared OpenAI-compatible core; embedding uses the /embeddings endpoint. No\n// openai npm package — plain fetch through httpTransport.\nimport { makeOpenAICompatibleAdapter } from \"./openai-compatible.js\";\nimport { httpTransport, errorBody } from \"../transport/http.js\";\nimport { freshUsage } from \"../cost/usage.js\";\nimport type {\n ProviderAdapter,\n EmbeddingRequest,\n EmbeddingResult,\n TranscribeRequest,\n TranscribeResult,\n} from \"../types.js\";\n\n/** Whisper-family per-minute USD prices (audio is not token-priced). */\nconst WHISPER_PRICE_PER_MIN: Record<string, number> = {\n \"whisper-1\": 0.006,\n};\n\nexport function openaiAdapter(\n config: { apiKey?: string; baseUrl?: string; fetch?: typeof fetch } = {},\n): ProviderAdapter {\n const baseUrl = config.baseUrl ?? \"https://api.openai.com/v1\";\n const base = makeOpenAICompatibleAdapter({ name: \"openai\", baseUrl, apiKey: config.apiKey });\n\n async function embedding(req: EmbeddingRequest): Promise<EmbeddingResult> {\n const apiKey = config.apiKey ?? process.env.OPENAI_API_KEY;\n if (!apiKey) throw new Error(\"openai adapter: API key not set (env OPENAI_API_KEY)\");\n const res = await httpTransport({\n spec: req.spec,\n http: {\n url: `${baseUrl}/embeddings`,\n headers: { \"content-type\": \"application/json\", Authorization: `Bearer ${apiKey}` },\n body: { model: req.spec.model, input: req.input },\n },\n });\n if (!res.ok) {\n throw new Error(`openai ${res.status}: ${errorBody(res.json, res.text)}`);\n }\n const data = res.json as {\n data?: { embedding: number[] }[];\n usage?: { prompt_tokens?: number };\n };\n const vectors = (data.data ?? []).map((d) => d.embedding);\n const usage = freshUsage({\n provider: \"openai\",\n model: req.spec.model,\n transport: \"http\",\n capability: \"embedding\",\n inputTokens: data.usage?.prompt_tokens ?? 0,\n outputTokens: 0,\n });\n return { vectors, usage };\n }\n\n async function transcribe(req: TranscribeRequest): Promise<TranscribeResult> {\n const apiKey = config.apiKey ?? process.env.OPENAI_API_KEY;\n if (!apiKey) throw new Error(\"openai adapter: API key not set (env OPENAI_API_KEY)\");\n // Whisper is multipart/form-data — bypass httpTransport (JSON-only). Don't set\n // content-type; fetch adds the multipart boundary.\n const form = new FormData();\n form.append(\"file\", new Blob([req.audio]), \"audio\");\n form.append(\"model\", req.spec.model);\n if (req.language) form.append(\"language\", req.language);\n // Timestamps (F036): Whisper needs verbose_json, plus a granularity per\n // requested level. verbose_json returns `segments` inherently; `words` only\n // when \"word\" granularity is asked for.\n if (req.timestamps && req.timestamps.length > 0) {\n form.append(\"response_format\", \"verbose_json\");\n for (const g of req.timestamps) form.append(\"timestamp_granularities[]\", g);\n }\n const fetchImpl = config.fetch ?? fetch;\n const res = await fetchImpl(`${baseUrl}/audio/transcriptions`, {\n method: \"POST\",\n headers: { Authorization: `Bearer ${apiKey}` },\n body: form,\n });\n if (!res.ok) {\n throw new Error(`openai ${res.status}: ${(await res.text().catch(() => \"\")).slice(0, 200)}`);\n }\n const data = (await res.json()) as {\n text?: string;\n words?: { word: string; start: number; end: number }[];\n segments?: { text: string; start: number; end: number }[];\n };\n const usage = freshUsage({\n provider: \"openai\",\n model: req.spec.model,\n transport: \"http\",\n capability: \"transcribe\",\n inputTokens: 0,\n outputTokens: 0, // Whisper is per-minute, not token-priced.\n });\n // Per-minute cost when the caller supplies the audio duration (API returns none).\n if (req.durationSec !== undefined) {\n const perMinute = WHISPER_PRICE_PER_MIN[req.spec.model] ?? 0;\n usage.costUsd = (req.durationSec / 60) * perMinute;\n }\n const result: TranscribeResult = { text: data.text ?? \"\", usage };\n // \"word\" granularity → words[]; any timestamps → segments[] (verbose_json emits them).\n if (req.timestamps?.includes(\"word\") && data.words) {\n result.words = data.words.map((w) => ({ word: w.word, start: w.start, end: w.end }));\n }\n if (req.timestamps && req.timestamps.length > 0 && data.segments) {\n result.segments = data.segments.map((s) => ({ text: s.text, start: s.start, end: s.end }));\n }\n return result;\n }\n\n return { ...base, embedding, transcribe };\n}\n","// Shared image-input helpers (F031). Extracted from gemini.ts once a second\n// provider (vertex.ts) needed the exact same URL/bytes/data-URI → inline\n// base64+mime resolution for Veo's `image:{bytesBase64Encoded, mimeType}` field.\n\n/** Resolve an image input to { data(base64), mimeType } — a URL is fetched to bytes. */\nexport async function toInlineImage(\n image: string | Uint8Array,\n fetchImpl: typeof fetch,\n): Promise<{ data: string; mimeType: string }> {\n if (typeof image !== \"string\") {\n return { data: Buffer.from(image).toString(\"base64\"), mimeType: sniffMime(image) };\n }\n if (/^https?:\\/\\//i.test(image)) {\n const res = await fetchImpl(image);\n if (!res.ok) throw new Error(`toInlineImage: failed to fetch image (${res.status})`);\n const bytes = new Uint8Array(await res.arrayBuffer());\n const mimeType = res.headers.get(\"content-type\") ?? sniffMime(bytes);\n return { data: Buffer.from(bytes).toString(\"base64\"), mimeType };\n }\n // A data: URI or bare base64.\n const comma = image.startsWith(\"data:\") ? image.indexOf(\",\") : -1;\n const b64 = comma >= 0 ? image.slice(comma + 1) : image;\n const mimeType = image.startsWith(\"data:\") ? image.slice(5, image.indexOf(\";\")) : \"image/png\";\n return { data: b64, mimeType };\n}\n\nexport function sniffMime(b: Uint8Array): string {\n if (b[0] === 0x89 && b[1] === 0x50) return \"image/png\";\n if (b[0] === 0x47 && b[1] === 0x49) return \"image/gif\";\n if (b[0] === 0x52 && b[1] === 0x49 && b[8] === 0x57) return \"image/webp\";\n return \"image/jpeg\";\n}\n","// Google Gemini adapter (F4.2). generateContent REST API; API key in the query\n// param (?key=), not a header. System turns map to systemInstruction; assistant\n// maps to role \"model\". Token counts come from usageMetadata. Tools normalized\n// via F4.5. No @google/generative-ai package — plain fetch through httpTransport.\nimport { httpTransport, errorBody } from \"../transport/http.js\";\nimport { streamTransport } from \"../transport/stream.js\";\nimport { toProviderTools, fromProviderToolCall } from \"./tools.js\";\nimport { freshUsage } from \"../cost/usage.js\";\nimport { toInlineImage } from \"./media.js\";\nimport type {\n ProviderAdapter,\n ChatRequest,\n ChatResult,\n ChatStreamEvent,\n ImageRequest,\n ImageResult,\n AnimateRequest,\n AnimateResult,\n Message,\n ContentPart,\n ToolCall,\n} from \"../types.js\";\n\n/** Per-image USD price for Gemini image-gen models (generateContent image output\n * is billed per image). Official ai.google.dev/gemini-api/docs/pricing, standard\n * paid tier, at the 1K/1024px output size (Google's per-image price rises with\n * resolution — 2K/4K cost more; we record the common 1K default). Overridable\n * per call via geminiAdapter config.pricePerImage. */\nconst GEMINI_IMAGE_PRICE_PER_IMAGE: Record<string, number> = {\n \"gemini-2.5-flash-image\": 0.039, // \"nano-banana\" — 1024px = 1290 tok\n \"gemini-3.1-flash-image\": 0.067, // 1K=$0.067, 2K=$0.101, 4K=$0.151\n \"gemini-3.1-flash-image-preview\": 0.067,\n \"gemini-3-pro-image\": 0.134, // premium — 1K/2K=$0.134, 4K=$0.24\n \"gemini-3-pro-image-preview\": 0.134, // was $0.039 — wrong (that's the flash price); pro is $0.134\n};\n\nexport interface GeminiPart {\n text?: string;\n functionCall?: { name: string; args: Record<string, unknown> };\n inlineData?: { mimeType: string; data: string };\n}\ninterface GeminiResponse {\n candidates?: { content?: { parts?: GeminiPart[] } }[];\n usageMetadata?: { promptTokenCount?: number; candidatesTokenCount?: number; cachedContentTokenCount?: number };\n error?: unknown;\n}\n\n/** Split Gemini's promptTokenCount into billable and cached halves (F040).\n *\n * MEASURED 2026-08-27, not assumed: an 11,408-token repeated prefix reported\n * `promptTokenCount: 11408` alongside `cachedContentTokenCount: 11242` — so the\n * prompt count INCLUDES the cached tokens and they must be subtracted, because\n * computeCost adds cacheReadTokens ON TOP of inputTokens. Getting this direction\n * wrong double-bills the cached prefix.\n *\n * Gemini's implicit caching needs no opt-in and no key, but it does need a few\n * calls to warm: one run first hit on call 3, another on call 5. So a single\n * cold call reporting nothing cached is not evidence that caching is off. */\nfunction splitCached(meta: { promptTokenCount?: number; cachedContentTokenCount?: number } | undefined): {\n inputTokens: number;\n cacheReadTokens?: number;\n} {\n const prompt = meta?.promptTokenCount ?? 0;\n const cached = meta?.cachedContentTokenCount;\n if (cached === undefined) return { inputTokens: prompt };\n return { inputTokens: Math.max(0, prompt - cached), cacheReadTokens: cached };\n}\n\n/** Exported so the Vertex adapter (F038) reuses this exact mapping — Vertex and the\n * Gemini API share the generateContent content format, and two copies of it would\n * drift. */\nexport { splitCached };\n\nexport function partsFrom(content: string | ContentPart[]): GeminiPart[] {\n if (typeof content === \"string\") return [{ text: content }];\n return content.map((p): GeminiPart => {\n if (p.type === \"text\") return { text: p.text };\n // Video (F019) and image both go inline as base64 — Gemini accepts video mime\n // types natively. (Clips over ~20MB need the Files API — not handled here.)\n if (p.type === \"video\") {\n const data =\n typeof p.video === \"string\"\n ? p.video.replace(/^data:[^;]+;base64,/, \"\")\n : Buffer.from(p.video).toString(\"base64\");\n return { inlineData: { mimeType: p.mimeType ?? \"video/mp4\", data } };\n }\n const data =\n typeof p.image === \"string\"\n ? p.image.replace(/^data:[^;]+;base64,/, \"\")\n : Buffer.from(p.image).toString(\"base64\");\n return { inlineData: { mimeType: p.mimeType ?? \"image/png\", data } };\n });\n}\n\n/** Per-SECOND USD for Veo video models (F024). Official ai.google.dev/gemini-api/\n * docs/pricing (2026-06, \"video with audio\", 720p/1080p default; 4K costs more).\n * Override per call via config.pricePerSecond. Unknown model → 0 (never fabricated). */\nconst VEO_PRICE_PER_SEC: Record<string, number> = {\n \"veo-3.1-generate-preview\": 0.4, // standard; 4K = 0.60\n \"veo-3.1-fast-generate-preview\": 0.1, // 720p; 1080p = 0.12, 4K = 0.30\n \"veo-3.1-lite-generate-preview\": 0.05, // 720p; 1080p = 0.08\n \"veo-3.0-generate-001\": 0.4,\n \"veo-3.0-fast-generate-001\": 0.1,\n};\n\nexport function geminiAdapter(\n config: {\n apiKey?: string;\n baseUrl?: string;\n fetch?: typeof fetch;\n pricePerImage?: number;\n /** Override the per-SECOND Veo video price (else estimate per model, 0 if unknown). */\n pricePerSecond?: number;\n /** Poll interval for Veo long-running operations (default 5s). */\n pollIntervalMs?: number;\n /** Deadline for a Veo job (default 300000 = 5 min). */\n videoTimeoutMs?: number;\n } = {},\n): ProviderAdapter {\n const baseUrl = config.baseUrl ?? \"https://generativelanguage.googleapis.com/v1beta\";\n\n function resolveKey(): string {\n const apiKey = config.apiKey ?? process.env.GOOGLE_API_KEY ?? process.env.GEMINI_API_KEY;\n if (!apiKey) throw new Error(\"gemini adapter: API key not set (env GOOGLE_API_KEY)\");\n return apiKey;\n }\n\n /** Build the generateContent body (shared by the http + stream paths). */\n function buildBody(req: ChatRequest): Record<string, unknown> {\n const systemParts: GeminiPart[] = [];\n const contents: { role: string; parts: GeminiPart[] }[] = [];\n for (const m of req.messages as Message[]) {\n if (m.role === \"system\") {\n systemParts.push(...partsFrom(m.content));\n } else {\n contents.push({\n role: m.role === \"assistant\" ? \"model\" : \"user\",\n parts: partsFrom(m.content),\n });\n }\n }\n const body: Record<string, unknown> = { contents };\n if (systemParts.length > 0) body.systemInstruction = { parts: systemParts };\n if (req.tools) body.tools = toProviderTools(req.tools, \"gemini\");\n const genConfig: Record<string, unknown> = {};\n if (req.maxTokens !== undefined) genConfig.maxOutputTokens = req.maxTokens;\n if (req.temperature !== undefined) genConfig.temperature = req.temperature;\n if (Object.keys(genConfig).length > 0) body.generationConfig = genConfig;\n return body;\n }\n\n async function chat(req: ChatRequest): Promise<ChatResult> {\n const apiKey = resolveKey();\n const body = buildBody(req);\n\n const res = await httpTransport({\n spec: req.spec,\n http: {\n url: `${baseUrl}/models/${req.spec.model}:generateContent?key=${encodeURIComponent(apiKey)}`,\n headers: { \"content-type\": \"application/json\" },\n body,\n },\n });\n if (!res.ok) {\n throw new Error(`gemini ${res.status}: ${errorBody(res.json, res.text)}`);\n }\n const data = res.json as GeminiResponse;\n const parts = data.candidates?.[0]?.content?.parts ?? [];\n const text = parts\n .filter((p) => typeof p.text === \"string\")\n .map((p) => p.text)\n .join(\"\");\n const toolCalls: ToolCall[] = parts\n .filter((p) => p.functionCall)\n .map((p) => fromProviderToolCall({ functionCall: p.functionCall }, \"gemini\"));\n\n const usage = freshUsage({\n provider: \"gemini\",\n model: req.spec.model,\n transport: \"http\",\n capability: \"chat\",\n ...splitCached(data.usageMetadata),\n outputTokens: data.usageMetadata?.candidatesTokenCount ?? 0,\n });\n const result: ChatResult = { text, usage };\n if (toolCalls.length > 0) result.toolCalls = toolCalls;\n return result;\n }\n\n // Streaming chat (F8.6) over streamGenerateContent?alt=sse. Each SSE chunk is\n // a partial GenerateContentResponse: parts[].text → text events, parts[].\n // functionCall → complete tool_call events (gemini sends each call whole), and\n // the final usageMetadata → a usage event. finishReason maps the terminal.\n async function* chatStream(req: ChatRequest): AsyncIterable<ChatStreamEvent> {\n const apiKey = resolveKey();\n const body = buildBody(req);\n const stream = streamTransport({\n spec: req.spec,\n fetch: config.fetch,\n http: {\n url: `${baseUrl}/models/${req.spec.model}:streamGenerateContent?alt=sse&key=${encodeURIComponent(apiKey)}`,\n headers: { \"content-type\": \"application/json\" },\n body,\n },\n });\n\n const toolCalls: ToolCall[] = [];\n let inputTokens = 0;\n let outputTokens = 0;\n let cacheReadTokens: number | undefined;\n let finishReason: string | null = null;\n\n for await (const data of stream) {\n let chunk: GeminiResponse & { candidates?: { finishReason?: string }[] };\n try {\n chunk = JSON.parse(data) as typeof chunk;\n } catch {\n continue;\n }\n const candidate = chunk.candidates?.[0];\n for (const p of candidate?.content?.parts ?? []) {\n if (typeof p.text === \"string\" && p.text.length > 0) {\n yield { type: \"text\", delta: p.text };\n } else if (p.functionCall) {\n toolCalls.push(fromProviderToolCall({ functionCall: p.functionCall }, \"gemini\"));\n }\n }\n if (candidate?.finishReason) finishReason = candidate.finishReason;\n if (chunk.usageMetadata) {\n const split = splitCached(chunk.usageMetadata);\n inputTokens = chunk.usageMetadata.promptTokenCount === undefined ? inputTokens : split.inputTokens;\n if (split.cacheReadTokens !== undefined) cacheReadTokens = split.cacheReadTokens;\n outputTokens = chunk.usageMetadata.candidatesTokenCount ?? outputTokens;\n }\n }\n\n for (const tc of toolCalls) {\n yield { type: \"tool_call\", id: tc.id, name: tc.name, args: tc.arguments };\n }\n const usage = freshUsage({\n provider: \"gemini\",\n model: req.spec.model,\n transport: \"http\",\n capability: \"chat\",\n inputTokens,\n outputTokens,\n ...(cacheReadTokens === undefined ? {} : { cacheReadTokens }),\n });\n yield { type: \"usage\", costUsd: usage.costUsd, model: usage.model, usage };\n yield {\n type: \"finish\",\n reason: toolCalls.length > 0 ? \"tool_calls\" : mapGeminiFinish(finishReason),\n };\n }\n\n // Image generation (F013) via generateContent with IMAGE response modality.\n // Gemini returns the image inline as base64 (not a hosted URL like fal), so we\n // hand it back as a data: URL. Built to match cms's nano-banana request.\n async function image(req: ImageRequest): Promise<ImageResult> {\n const apiKey = resolveKey();\n // Direct fetch (injectable for tests) — generateContent is JSON in/out but\n // we read inline image bytes, so we don't route through httpTransport here.\n const fetchImpl = config.fetch ?? fetch;\n const res = await fetchImpl(`${baseUrl}/models/${req.spec.model}:generateContent?key=${encodeURIComponent(apiKey)}`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({\n contents: [{ role: \"user\", parts: [{ text: req.prompt }] }],\n // The multimodal image model can return text + image; ask for both.\n generationConfig: { responseModalities: [\"TEXT\", \"IMAGE\"] },\n }),\n });\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`gemini image ${res.status}: ${body.slice(0, 300)}`);\n }\n const data = (await res.json()) as GeminiResponse & {\n candidates?: { content?: { parts?: GeminiImagePart[] } }[];\n promptFeedback?: { blockReason?: string };\n };\n if (data.promptFeedback?.blockReason) {\n throw new Error(`gemini image blocked: ${data.promptFeedback.blockReason}`);\n }\n let url: string | undefined;\n for (const p of data.candidates?.[0]?.content?.parts ?? []) {\n // Some responses use camelCase inlineData, others snake_case inline_data.\n const inline = p.inlineData ?? p.inline_data;\n const mime = inline?.mimeType ?? inline?.mime_type;\n const b64 = inline?.data;\n if (mime && b64) {\n url = `data:${mime};base64,${b64}`;\n break;\n }\n }\n if (!url) throw new Error(\"gemini image: response contained no inline image data\");\n const usage = freshUsage({\n provider: \"gemini\",\n model: req.spec.model,\n transport: \"http\",\n capability: \"image\",\n ...splitCached(data.usageMetadata),\n outputTokens: data.usageMetadata?.candidatesTokenCount ?? 0,\n });\n usage.costUsd = config.pricePerImage ?? GEMINI_IMAGE_PRICE_PER_IMAGE[req.spec.model] ?? 0;\n return { url, usage };\n }\n\n // Image-to-video (F024) via Veo on the Gemini API — :predictLongRunning. Submit\n // returns an operation; poll until done; the result is an auth-gated file URI, so\n // we download the bytes with the key and hand them back (the URI alone needs auth).\n async function animate(req: AnimateRequest): Promise<AnimateResult> {\n const apiKey = resolveKey();\n const fetchImpl = config.fetch ?? fetch;\n const pollIntervalMs = config.pollIntervalMs ?? 5000;\n const deadline = Date.now() + (config.videoTimeoutMs ?? 300000);\n\n // Input image → inline base64 + mime (URL is fetched to bytes first).\n const { data, mimeType } = await toInlineImage(req.image, fetchImpl);\n const parameters: Record<string, unknown> = {};\n // durationSeconds must be a NUMBER (the API rejects a string, despite some docs).\n if (req.durationSec !== undefined) parameters.durationSeconds = req.durationSec;\n if (req.resolution !== undefined) parameters.resolution = req.resolution;\n // Veo's predict image field is bytesBase64Encoded + mimeType (NOT generateContent's\n // inlineData — the API rejects that: \"inlineData isn't supported by this model\").\n const body = {\n instances: [{ prompt: req.prompt ?? \"\", image: { bytesBase64Encoded: data, mimeType } }],\n ...(Object.keys(parameters).length ? { parameters } : {}),\n };\n\n const submit = await fetchImpl(\n `${baseUrl}/models/${req.spec.model}:predictLongRunning?key=${encodeURIComponent(apiKey)}`,\n { method: \"POST\", headers: { \"content-type\": \"application/json\" }, body: JSON.stringify(body) },\n );\n if (!submit.ok) {\n throw new Error(`gemini animate ${submit.status}: ${(await submit.text().catch(() => \"\")).slice(0, 300)}`);\n }\n const op = (await submit.json()) as { name?: string };\n if (!op.name) throw new Error(\"gemini animate: no operation name in submit response\");\n\n // Poll the operation until done.\n let videoUri: string | undefined;\n for (;;) {\n const poll = await fetchImpl(`${baseUrl}/${op.name}?key=${encodeURIComponent(apiKey)}`, {\n headers: { \"content-type\": \"application/json\" },\n });\n if (!poll.ok) throw new Error(`gemini animate poll ${poll.status}`);\n const opData = (await poll.json()) as VeoOperation;\n if (opData.error) throw new Error(`gemini animate: ${opData.error.message ?? \"operation error\"}`);\n if (opData.done) {\n videoUri = opData.response?.generateVideoResponse?.generatedSamples?.[0]?.video?.uri;\n if (!videoUri) throw new Error(`gemini animate: done but no video uri: ${errorBody(opData.response)}`);\n break;\n }\n if (Date.now() >= deadline) throw new Error(\"gemini animate: timed out\");\n await new Promise((r) => setTimeout(r, pollIntervalMs));\n }\n\n // Download the bytes (the URI is auth-gated + short-lived).\n const dl = await fetchImpl(videoUri.includes(\"key=\") ? videoUri : `${videoUri}${videoUri.includes(\"?\") ? \"&\" : \"?\"}key=${encodeURIComponent(apiKey)}`);\n if (!dl.ok) throw new Error(`gemini animate download ${dl.status}`);\n const bytes = new Uint8Array(await dl.arrayBuffer());\n\n const usage = freshUsage({\n provider: \"gemini\",\n model: req.spec.model,\n transport: \"http\",\n capability: \"animate\",\n inputTokens: 0,\n outputTokens: 0,\n });\n const perSec = config.pricePerSecond ?? VEO_PRICE_PER_SEC[req.spec.model] ?? 0;\n usage.costUsd = perSec * (req.durationSec ?? 8);\n return { url: videoUri, bytes, mimeType: \"video/mp4\", usage };\n }\n\n return { name: \"gemini\", chat, chatStream, image, animate, vision: chat };\n}\n\n/** A Veo predictLongRunning operation result shape. */\ninterface VeoOperation {\n done?: boolean;\n error?: { message?: string };\n response?: {\n generateVideoResponse?: {\n generatedSamples?: { video?: { uri?: string } }[];\n };\n };\n}\n\n/** Image part shape on a generateContent response (camel + snake aliases). */\ninterface GeminiInline {\n mimeType?: string;\n mime_type?: string;\n data?: string;\n}\ninterface GeminiImagePart {\n text?: string;\n inlineData?: GeminiInline;\n inline_data?: GeminiInline;\n}\n\n/** Map Gemini finishReason → the SDK's ChatStreamEvent finish reason. */\nfunction mapGeminiFinish(reason: string | null): \"end_turn\" | \"tool_calls\" | \"length\" | \"stop\" {\n switch (reason) {\n case \"MAX_TOKENS\":\n return \"length\";\n case \"STOP\":\n return \"end_turn\";\n default:\n return reason ? \"stop\" : \"end_turn\";\n }\n}\n","// DeepInfra adapter (F4.3). DeepInfra exposes an OpenAI-compatible endpoint, so\n// this is the shared core pointed at DeepInfra's base URL + key. No extra deps.\nimport { makeOpenAICompatibleAdapter } from \"./openai-compatible.js\";\nimport type { ProviderAdapter } from \"../types.js\";\n\nexport function deepinfraAdapter(\n config: { apiKey?: string; baseUrl?: string } = {},\n): ProviderAdapter {\n return makeOpenAICompatibleAdapter({\n name: \"deepinfra\",\n baseUrl: config.baseUrl ?? \"https://api.deepinfra.com/v1/openai\",\n apiKey: config.apiKey,\n });\n}\n","// OpenRouter adapter (F4.4). Meta-router with an OpenAI-compatible API — reuses\n// the shared core + OpenRouter's attribution headers. Any upstream model is\n// reachable by its slug, e.g. \"minimax/minimax-m2.7\", \"google/gemini-2.5-flash\".\nimport { makeOpenAICompatibleAdapter } from \"./openai-compatible.js\";\nimport { freshUsage } from \"../cost/usage.js\";\nimport type { ProviderAdapter, ImageRequest, ImageResult } from \"../types.js\";\n\n// F033.1 — OpenRouter's unified Image API (POST /images, distinct from\n// /chat/completions) returns base64 image data under data[].b64_json, plus a\n// ground-truth usage.cost (USD) like chat does. Vector/SVG output is the same\n// shape with data[].media_type = \"image/svg+xml\". A model/policy error can come\n// back as HTTP 200 with an empty data[] and a structured `error` — surfaced so\n// the caller sees the real cause, not a generic \"no image data\".\ninterface OpenRouterImageResponse {\n data?: { b64_json?: string; media_type?: string }[];\n usage?: { cost?: number };\n error?: { message?: string } | string;\n}\n\n// Per-image USD ESTIMATES — fallback for when OpenRouter's response omits\n// usage.cost. Verified 2026-07-03 against openrouter.ai/recraft/recraft-v4.1*\n// (override via config.pricePerImage).\nconst OPENROUTER_IMAGE_PRICE_ESTIMATE: Record<string, number> = {\n \"recraft/recraft-v4.1\": 0.035,\n \"recraft/recraft-v4.1-vector\": 0.08,\n};\n\nexport interface OpenRouterAdapterConfig {\n apiKey?: string;\n baseUrl?: string;\n referer?: string;\n title?: string;\n fetch?: typeof fetch;\n /** Override the per-image USD price (else OPENROUTER_IMAGE_PRICE_ESTIMATE, else 0). */\n pricePerImage?: number;\n}\n\nexport function openrouterAdapter(config: OpenRouterAdapterConfig = {}): ProviderAdapter {\n const baseUrl = config.baseUrl ?? \"https://openrouter.ai/api/v1\";\n const headers = {\n \"HTTP-Referer\": config.referer ?? \"https://broberg.ai\",\n \"X-Title\": config.title ?? \"@broberg/ai-sdk\",\n };\n const base = makeOpenAICompatibleAdapter({\n name: \"openrouter\",\n baseUrl,\n apiKey: config.apiKey,\n extraHeaders: headers,\n // Forward the injectable fetch so an override applies uniformly to\n // chat/chatStream/vision as well as the image() path below.\n fetch: config.fetch,\n // OpenRouter returns ground-truth usage.cost (USD) when usage:{include:true}\n // is set — use it over the local pricing-table estimate (F010).\n costFromResponseField: true,\n });\n\n async function image(req: ImageRequest): Promise<ImageResult> {\n const apiKey = config.apiKey ?? process.env.OPENROUTER_API_KEY;\n if (!apiKey) throw new Error(\"openrouter adapter: OPENROUTER_API_KEY not set\");\n const doFetch = config.fetch ?? fetch;\n\n const body: Record<string, unknown> = { model: req.spec.model, prompt: req.prompt };\n if (req.width !== undefined && req.height !== undefined) {\n body.size = `${req.width}x${req.height}`;\n }\n // OpenRouter's Image API takes top-level `seed` (reproducibility) and\n // `output_format` (png/jpeg/webp) — forward the ImageRequest fields the\n // rest of the SDK exposes (matches bfl.ts) instead of silently dropping them.\n if (req.seed !== undefined) body.seed = req.seed;\n if (req.outputFormat !== undefined) body.output_format = req.outputFormat;\n\n const res = await doFetch(`${baseUrl}/images`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n ...headers,\n },\n body: JSON.stringify(body),\n });\n if (!res.ok) {\n throw new Error(`openrouter images ${res.status}: ${(await res.text().catch(() => \"\")).slice(0, 300)}`);\n }\n const data = (await res.json()) as OpenRouterImageResponse;\n const first = data.data?.[0];\n if (!first?.b64_json) {\n // A flagged/failed generation can arrive as 200 + empty data + an error\n // payload — surface it so a moderation block reads differently than a glitch.\n const errMsg = typeof data.error === \"string\" ? data.error : data.error?.message;\n throw new Error(`openrouter images: ${errMsg ?? \"no image data in response\"}`);\n }\n\n const usage = freshUsage({\n provider: \"openrouter\",\n model: req.spec.model,\n transport: \"http\",\n capability: \"image\",\n inputTokens: 0,\n outputTokens: 0,\n });\n usage.costUsd =\n data.usage?.cost ?? config.pricePerImage ?? OPENROUTER_IMAGE_PRICE_ESTIMATE[req.spec.model] ?? 0;\n return { url: `data:${first.media_type ?? \"image/png\"};base64,${first.b64_json}`, usage };\n }\n\n return { ...base, image };\n}\n","// Requesty adapter (F028). An OpenAI-compatible AI gateway (400+ models, 30+\n// providers) — a drop-in alternative to the `openrouter` upstream. Reuses the\n// shared OpenAI-compatible core; only the base URL + key differ. Requesty returns\n// ground-truth `usage.cost`, so cost is exact (not a table estimate). Key from\n// REQUESTY_API_KEY. EU data-residency endpoint via `eu:true`.\n//\n// GDPR note: the EU endpoint keeps only Requesty's GATEWAY in the EU (Frankfurt).\n// End-to-end EU residency still requires an EU-region MODEL slug (Bedrock\n// `@eu-central-1`, Vertex `@eu`, Azure `@swedencentral`, Mistral EU-default) — a\n// global slug routes inference outside the EU despite the EU endpoint.\nimport { makeOpenAICompatibleAdapter } from \"./openai-compatible.js\";\nimport type { ProviderAdapter } from \"../types.js\";\n\nconst US_BASE = \"https://router.requesty.ai/v1\";\nconst EU_BASE = \"https://router.eu.requesty.ai/v1\";\n\nexport function requestyAdapter(\n config: { apiKey?: string; baseUrl?: string; eu?: boolean; referer?: string; title?: string } = {},\n): ProviderAdapter {\n return makeOpenAICompatibleAdapter({\n name: \"requesty\",\n baseUrl: config.baseUrl ?? (config.eu ? EU_BASE : US_BASE),\n apiKey: config.apiKey,\n extraHeaders: {\n \"HTTP-Referer\": config.referer ?? \"https://broberg.ai\",\n \"X-Title\": config.title ?? \"@broberg/ai-sdk\",\n },\n // Requesty returns ground-truth usage.cost (USD) by default — use it over the\n // local pricing-table estimate (same as OpenRouter, F010).\n costFromResponseField: true,\n });\n}\n","// DeepSeek adapter (F030) — the opt-in NON-PII secondary route for the Anthropic\n// phase-out. DeepSeek's direct API is OpenAI-compatible, so this reuses the shared\n// core; only base URL + key differ. Reached via `override:{ provider:\"deepseek\",\n// model:\"…\" }` — never a default tier. Key from DEEPSEEK_API_KEY.\n//\n// GDPR: DeepSeek is CN-hosted → NOT GDPR-safe. Use ONLY for non-PII workloads\n// (e.g. public web/article scanning). Personal data stays on Mistral EU.\n//\n// Models (direct api.deepseek.com): `deepseek-chat` (non-thinking) and\n// `deepseek-reasoner` (thinking) — both DEPRECATE 2026-07-24 and map to\n// `deepseek-v4-flash`. Prefer `deepseek-v4-flash` going forward (same model, not\n// sunset). The direct API does NOT return a cost field → cost comes from the\n// pricing table (verify rates against a real key; see src/cost/pricing.ts).\nimport { makeOpenAICompatibleAdapter } from \"./openai-compatible.js\";\nimport type { ProviderAdapter } from \"../types.js\";\n\nexport function deepseekAdapter(\n config: { apiKey?: string; baseUrl?: string } = {},\n): ProviderAdapter {\n return makeOpenAICompatibleAdapter({\n name: \"deepseek\", // → key DEEPSEEK_API_KEY\n baseUrl: config.baseUrl ?? \"https://api.deepseek.com/v1\",\n apiKey: config.apiKey,\n // Direct API returns no usage.cost → price from the table (not response).\n costFromResponseField: false,\n });\n}\n","// Mistral adapter. Mistral's La Plateforme exposes an OpenAI-compatible chat\n// endpoint (the shared core), plus two specialty endpoints we add here:\n// /ocr (F016.2, per-page) and /moderations (F016.4, per-token). Key resolved\n// from MISTRAL_API_KEY when not passed.\nimport { makeOpenAICompatibleAdapter } from \"./openai-compatible.js\";\nimport { freshUsage } from \"../cost/usage.js\";\nimport { regionOfHost } from \"../cost/region.js\";\nimport type {\n ProviderAdapter,\n OcrRequest,\n OcrResult,\n OcrPage,\n ModerationRequest,\n ModerationResult,\n ModerationItem,\n EmbeddingRequest,\n EmbeddingResult,\n TranscribeRequest,\n TranscribeResult,\n BatchRequestItem,\n BatchJob,\n BatchResultItem,\n TierSpec,\n} from \"../types.js\";\n\n/** Per-page USD for Mistral OCR ($2 / 1000 pages). Overridable via config. */\nconst MISTRAL_OCR_PRICE_PER_PAGE = 0.002;\n\n/** Per-minute USD for Voxtral transcription models (F016.3). */\nconst VOXTRAL_PRICE_PER_MIN: Record<string, number> = {\n \"voxtral-mini-latest\": 0.002,\n \"voxtral-mini-2507\": 0.002,\n \"voxtral-mini-2602\": 0.002,\n};\n\nexport function mistralAdapter(\n config: { apiKey?: string; baseUrl?: string; fetch?: typeof fetch; pricePerPage?: number } = {},\n): ProviderAdapter {\n const baseUrl = config.baseUrl ?? \"https://api.mistral.ai/v1\";\n const base = makeOpenAICompatibleAdapter({ name: \"mistral\", baseUrl, apiKey: config.apiKey, supportsPromptCacheKey: true });\n\n function key(): string {\n const k = config.apiKey ?? process.env.MISTRAL_API_KEY;\n if (!k) throw new Error(\"mistral adapter: API key not set (env MISTRAL_API_KEY)\");\n return k;\n }\n const fetchImpl = config.fetch ?? fetch;\n\n // OCR (F016.2) — POST /ocr. document is a URL/data-URL; image/* routes as an\n // image, anything else as a document (PDF etc.). Billed per page processed.\n async function ocr(req: OcrRequest): Promise<OcrResult> {\n const isImage = (req.mimeType ?? \"\").startsWith(\"image/\");\n const url =\n typeof req.document === \"string\"\n ? req.document\n : `data:${req.mimeType ?? \"application/pdf\"};base64,${Buffer.from(req.document).toString(\"base64\")}`;\n const document = isImage\n ? { type: \"image_url\", image_url: url }\n : { type: \"document_url\", document_url: url };\n\n const res = await fetchImpl(`${baseUrl}/ocr`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", authorization: `Bearer ${key()}` },\n body: JSON.stringify({ model: req.spec.model, document }),\n });\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`mistral ocr ${res.status}: ${body.slice(0, 300)}`);\n }\n const data = (await res.json()) as {\n pages?: { index?: number; markdown?: string }[];\n usage_info?: { pages_processed?: number };\n };\n const pages: OcrPage[] = (data.pages ?? []).map((p, i) => ({\n index: p.index ?? i,\n markdown: p.markdown ?? \"\",\n }));\n const pagesProcessed = data.usage_info?.pages_processed ?? pages.length;\n const usage = freshUsage({\n provider: \"mistral\",\n // From the URL we actually called. mistral is deliberately ABSENT from the\n // provider-name table (config.baseUrl can move it), so omitting this here made\n // these four report \"unknown\" instead of \"eu\" — a regression shipped in 0.36.0\n // that broke the very enforcement we told consumers to write.\n region: regionOfHost(baseUrl),\n model: req.spec.model,\n transport: \"http\",\n capability: \"ocr\",\n inputTokens: 0,\n outputTokens: 0,\n });\n usage.costUsd = pagesProcessed * (config.pricePerPage ?? MISTRAL_OCR_PRICE_PER_PAGE);\n return { pages, usage };\n }\n\n // Moderation (F016.4) — POST /moderations. Returns per-input category booleans\n // + scores; `flagged` = any category true. Billed per input token (estimated\n // from input length when the API omits a usage count).\n async function moderate(req: ModerationRequest): Promise<ModerationResult> {\n const res = await fetchImpl(`${baseUrl}/moderations`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", authorization: `Bearer ${key()}` },\n body: JSON.stringify({ model: req.spec.model, input: req.input }),\n });\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`mistral moderation ${res.status}: ${body.slice(0, 300)}`);\n }\n const data = (await res.json()) as {\n results?: { categories?: Record<string, boolean>; category_scores?: Record<string, number> }[];\n usage?: { prompt_tokens?: number };\n };\n const results: ModerationItem[] = (data.results ?? []).map((r) => {\n const categories = r.categories ?? {};\n return {\n flagged: Object.values(categories).some(Boolean),\n categories,\n categoryScores: r.category_scores ?? {},\n };\n });\n // The moderation endpoint usually omits token counts → estimate from input.\n const estIn = req.input.reduce((n, s) => n + Math.ceil(s.length / 4), 0);\n const usage = freshUsage({\n provider: \"mistral\",\n // From the URL we actually called. mistral is deliberately ABSENT from the\n // provider-name table (config.baseUrl can move it), so omitting this here made\n // these four report \"unknown\" instead of \"eu\" — a regression shipped in 0.36.0\n // that broke the very enforcement we told consumers to write.\n region: regionOfHost(baseUrl),\n model: req.spec.model,\n transport: \"http\",\n capability: \"moderation\",\n inputTokens: data.usage?.prompt_tokens ?? estIn,\n outputTokens: 0,\n });\n return { results, usage };\n }\n\n // Embeddings (F016.5) — POST /embeddings (OpenAI-compatible). Per-token input.\n async function embedding(req: EmbeddingRequest): Promise<EmbeddingResult> {\n const res = await fetchImpl(`${baseUrl}/embeddings`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", authorization: `Bearer ${key()}` },\n body: JSON.stringify({ model: req.spec.model, input: req.input }),\n });\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`mistral embeddings ${res.status}: ${body.slice(0, 300)}`);\n }\n const data = (await res.json()) as {\n data?: { embedding: number[] }[];\n usage?: { prompt_tokens?: number; total_tokens?: number };\n };\n const vectors = (data.data ?? []).map((d) => d.embedding);\n const usage = freshUsage({\n provider: \"mistral\",\n // From the URL we actually called. mistral is deliberately ABSENT from the\n // provider-name table (config.baseUrl can move it), so omitting this here made\n // these four report \"unknown\" instead of \"eu\" — a regression shipped in 0.36.0\n // that broke the very enforcement we told consumers to write.\n region: regionOfHost(baseUrl),\n model: req.spec.model,\n transport: \"http\",\n capability: \"embedding\",\n inputTokens: data.usage?.prompt_tokens ?? data.usage?.total_tokens ?? 0,\n outputTokens: 0,\n });\n return { vectors, usage };\n }\n\n // Transcribe (F016.3) — Voxtral via OpenAI-compatible /audio/transcriptions\n // (multipart). Per-minute cost when durationSec is supplied.\n async function transcribe(req: TranscribeRequest): Promise<TranscribeResult> {\n const form = new FormData();\n form.append(\"file\", new Blob([req.audio]), \"audio\");\n form.append(\"model\", req.spec.model);\n if (req.language) form.append(\"language\", req.language);\n const res = await fetchImpl(`${baseUrl}/audio/transcriptions`, {\n method: \"POST\",\n headers: { authorization: `Bearer ${key()}` },\n body: form,\n });\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`mistral transcribe ${res.status}: ${body.slice(0, 300)}`);\n }\n const data = (await res.json()) as { text?: string };\n const usage = freshUsage({\n provider: \"mistral\",\n // From the URL we actually called. mistral is deliberately ABSENT from the\n // provider-name table (config.baseUrl can move it), so omitting this here made\n // these four report \"unknown\" instead of \"eu\" — a regression shipped in 0.36.0\n // that broke the very enforcement we told consumers to write.\n region: regionOfHost(baseUrl),\n model: req.spec.model,\n transport: \"http\",\n capability: \"transcribe\",\n inputTokens: 0,\n outputTokens: 0,\n });\n if (req.durationSec !== undefined) {\n usage.costUsd = (req.durationSec / 60) * (VOXTRAL_PRICE_PER_MIN[req.spec.model] ?? 0);\n }\n return { text: data.text ?? \"\", usage };\n }\n\n // Batch (F016.1) — async chat at 50% cost. Upload a JSONL of requests → create\n // a job → poll status → download results. Each line: {custom_id, body:{model,messages}}.\n async function batchSubmit(req: { items: BatchRequestItem[]; spec: TierSpec }): Promise<BatchJob> {\n const jsonl = req.items\n .map((it) =>\n JSON.stringify({\n custom_id: it.customId,\n body: { model: req.spec.model, messages: [{ role: \"user\", content: it.prompt }] },\n }),\n )\n .join(\"\\n\");\n // Upload the input file (multipart, purpose=batch).\n const form = new FormData();\n form.append(\"purpose\", \"batch\");\n form.append(\"file\", new Blob([jsonl], { type: \"application/jsonl\" }), \"batch.jsonl\");\n const up = await fetchImpl(`${baseUrl}/files`, {\n method: \"POST\",\n headers: { authorization: `Bearer ${key()}` },\n body: form,\n });\n if (!up.ok) throw new Error(`mistral batch upload ${up.status}: ${(await up.text().catch(() => \"\")).slice(0, 200)}`);\n const fileId = ((await up.json()) as { id?: string }).id;\n // Create the batch job.\n const job = await fetchImpl(`${baseUrl}/batch/jobs`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", authorization: `Bearer ${key()}` },\n body: JSON.stringify({ input_files: [fileId], model: req.spec.model, endpoint: \"/v1/chat/completions\" }),\n });\n if (!job.ok) throw new Error(`mistral batch job ${job.status}: ${(await job.text().catch(() => \"\")).slice(0, 200)}`);\n const data = (await job.json()) as { id?: string; status?: string; total_requests?: number };\n return { jobId: data.id ?? \"\", status: data.status ?? \"queued\", total: data.total_requests };\n }\n\n async function batchStatus(req: { jobId: string; spec: TierSpec }): Promise<BatchJob> {\n const res = await fetchImpl(`${baseUrl}/batch/jobs/${req.jobId}`, { headers: { authorization: `Bearer ${key()}` } });\n if (!res.ok) throw new Error(`mistral batch status ${res.status}`);\n const d = (await res.json()) as { id?: string; status?: string; total_requests?: number; succeeded_requests?: number };\n return { jobId: d.id ?? req.jobId, status: d.status ?? \"unknown\", total: d.total_requests, completed: d.succeeded_requests };\n }\n\n async function batchResults(req: { jobId: string; spec: TierSpec }): Promise<BatchResultItem[]> {\n const job = await fetchImpl(`${baseUrl}/batch/jobs/${req.jobId}`, { headers: { authorization: `Bearer ${key()}` } });\n if (!job.ok) throw new Error(`mistral batch results ${job.status}`);\n const outputFile = ((await job.json()) as { output_file?: string }).output_file;\n if (!outputFile) throw new Error(\"mistral batch: job has no output_file yet (not finished)\");\n const content = await fetchImpl(`${baseUrl}/files/${outputFile}/content`, { headers: { authorization: `Bearer ${key()}` } });\n if (!content.ok) throw new Error(`mistral batch download ${content.status}`);\n const lines = (await content.text()).trim().split(\"\\n\").filter(Boolean);\n return lines.map((line) => {\n const row = JSON.parse(line) as { custom_id?: string; response?: { body?: { choices?: { message?: { content?: string } }[] } } };\n return { customId: row.custom_id ?? \"\", text: row.response?.body?.choices?.[0]?.message?.content ?? \"\" };\n });\n }\n\n return { ...base, ocr, moderate, embedding, transcribe, batchSubmit, batchStatus, batchResults };\n}\n","// ElevenLabs adapter (F020). Text-to-Dialogue (eleven_v3) turns a manuscript of\n// {text, voice_id} turns into ONE cohesive multi-voice audio episode — the\n// \"instant podcast\" primitive. Also single-voice TTS + voice listing. Audio out\n// is MP3 bytes; billed per character. Key from ELEVENLABS_API_KEY.\nimport { freshUsage } from \"../cost/usage.js\";\nimport type { ProviderAdapter, DialogueRequest, TtsRequest, PodcastResult } from \"../types.js\";\n\n/** USD per 1000 characters (ElevenLabs bills per char; API overage ≈ $0.10–0.18/1k). */\nconst ELEVENLABS_PRICE_PER_1K_CHARS = 0.15;\n\n/** Curated Danish voices (F020.3) — friendly name → ElevenLabs voiceId. Apps can\n * pass these names to `ai.podcast`/`ai.tts` instead of raw IDs. */\nexport const ELEVENLABS_DANISH_VOICES: Record<string, string> = {\n soren: \"xj6X4BCUsv9oxohm1E8o\",\n jesper: \"Bl1YwS3uJac5zEOSNESn\",\n mads: \"BIWC0507fYMfhPcAEIRP\",\n noam: \"V34B5u5UbLdNJVEkcgXp\",\n camilla: \"4RklGmuxoAskAbGXplXN\",\n};\n\n/** Resolve a curated voice name to its voiceId; pass a raw voiceId through unchanged. */\nexport function resolveVoice(nameOrId: string): string {\n return ELEVENLABS_DANISH_VOICES[nameOrId] ?? nameOrId;\n}\n\nexport interface ElevenLabsVoice {\n voiceId: string;\n name: string;\n language?: string;\n}\n\nexport function elevenlabsAdapter(\n config: { apiKey?: string; baseUrl?: string; fetch?: typeof fetch; pricePer1kChars?: number } = {},\n): ProviderAdapter & {\n listVoices(): Promise<ElevenLabsVoice[]>;\n} {\n const baseUrl = config.baseUrl ?? \"https://api.elevenlabs.io/v1\";\n const fetchImpl = config.fetch ?? fetch;\n\n function key(): string {\n const k = config.apiKey ?? process.env.ELEVENLABS_API_KEY;\n if (!k) throw new Error(\"elevenlabs adapter: API key not set (env ELEVENLABS_API_KEY)\");\n return k;\n }\n\n function priceFor(chars: number, model: string): ReturnType<typeof freshUsage> {\n const usage = freshUsage({\n provider: \"elevenlabs\",\n model,\n transport: \"http\",\n capability: \"podcast\",\n inputTokens: 0,\n outputTokens: 0,\n });\n usage.costUsd = (chars / 1000) * (config.pricePer1kChars ?? ELEVENLABS_PRICE_PER_1K_CHARS);\n return usage;\n }\n\n // Multi-voice dialogue → one episode. POST /text-to-dialogue.\n async function dialogue(req: DialogueRequest): Promise<PodcastResult> {\n const res = await fetchImpl(`${baseUrl}/text-to-dialogue`, {\n method: \"POST\",\n headers: { \"xi-api-key\": key(), \"content-type\": \"application/json\", accept: \"audio/mpeg\" },\n body: JSON.stringify({\n model_id: req.spec.model,\n inputs: req.inputs.map((t) => ({ text: t.text, voice_id: t.voiceId })),\n ...(req.format ? { output_format: req.format } : {}),\n }),\n });\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`elevenlabs dialogue ${res.status}: ${body.slice(0, 300)}`);\n }\n const audio = new Uint8Array(await res.arrayBuffer());\n const chars = req.inputs.reduce((n, t) => n + t.text.length, 0);\n return { audio, mimeType: \"audio/mpeg\", usage: priceFor(chars, req.spec.model) };\n }\n\n // Single-voice TTS. POST /text-to-speech/{voice_id}.\n async function tts(req: TtsRequest): Promise<PodcastResult> {\n const model = req.spec.model;\n const res = await fetchImpl(`${baseUrl}/text-to-speech/${req.voiceId}`, {\n method: \"POST\",\n headers: { \"xi-api-key\": key(), \"content-type\": \"application/json\", accept: \"audio/mpeg\" },\n body: JSON.stringify({ text: req.text, model_id: model }),\n });\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`elevenlabs tts ${res.status}: ${body.slice(0, 300)}`);\n }\n const audio = new Uint8Array(await res.arrayBuffer());\n return { audio, mimeType: \"audio/mpeg\", usage: priceFor(req.text.length, model) };\n }\n\n async function listVoices(): Promise<ElevenLabsVoice[]> {\n const res = await fetchImpl(`${baseUrl}/voices`, { headers: { \"xi-api-key\": key() } });\n if (!res.ok) throw new Error(`elevenlabs voices ${res.status}`);\n const data = (await res.json()) as { voices?: { voice_id: string; name: string; labels?: { language?: string } }[] };\n return (data.voices ?? []).map((v) => ({ voiceId: v.voice_id, name: v.name, language: v.labels?.language }));\n }\n\n return { name: \"elevenlabs\", dialogue, tts, listVoices };\n}\n","// Azure Speech (Cognitive Services) TTS adapter (F026). Natural EU-resident\n// neural Danish read-aloud behind the existing `ai.tts` capability. Azure Speech\n// is NOT reachable via OpenRouter (that proxies LLM chat/completions only) — this\n// is a direct SSML REST call, region-pinned to an EU host. Audio out is MP3 bytes;\n// billed per character. Key + region from AZURE_SPEECH_KEY / AZURE_SPEECH_REGION.\nimport { freshUsage } from \"../cost/usage.js\";\nimport { classifyRegionName, type Region } from \"../cost/region.js\";\nimport type { ProviderAdapter, TtsRequest, PodcastResult, TranscribeRequest, TranscribeResult } from \"../types.js\";\n\n/** USD per 1000 characters. ≈ Azure neural standard ($16 / 1M chars) — verify on\n * azure.microsoft.com/pricing; override via config.pricePer1kChars. */\nconst AZURE_TTS_PRICE_PER_1K_CHARS = 0.016;\n\n/** USD per audio-minute for speech-to-text. ≈ Azure standard STT ($1 / audio-hour\n * = $0.0167/min) — verify the fast-transcription rate on azure.microsoft.com/pricing;\n * override via config.sttPricePerMin. */\nconst AZURE_STT_PRICE_PER_MIN = 0.0167;\n\n/** Fast-transcription REST api-version. 2025-10-15 is required for the `phraseList`\n * biasing field (2024-11-15 rejects it as \"Invalid JSON\"); both serve plain\n * transcription. Override via config.sttApiVersion. (Live-verified F029.) */\nconst DEFAULT_STT_API_VERSION = \"2025-10-15\";\n\n/** Default region — EU/GDPR-clean. Override via config.region / AZURE_SPEECH_REGION. */\nconst DEFAULT_REGION = \"westeurope\";\n\n/** Default MP3 output (Azure's X-Microsoft-OutputFormat). */\nconst DEFAULT_FORMAT = \"audio-24khz-48kbitrate-mono-mp3\";\n\n/** Short language code → Azure STT locale. A full locale (\"da-DK\") passes through;\n * omitted language defaults to da-DK (the EU-Danish use-case this was built for). */\nconst AZURE_LOCALE_MAP: Record<string, string> = {\n da: \"da-DK\", en: \"en-US\", de: \"de-DE\", sv: \"sv-SE\", nb: \"nb-NO\", no: \"nb-NO\",\n fi: \"fi-FI\", nl: \"nl-NL\", fr: \"fr-FR\", es: \"es-ES\", it: \"it-IT\", pt: \"pt-PT\",\n};\nfunction toAzureLocale(lang?: string): string {\n if (!lang) return \"da-DK\";\n if (lang.includes(\"-\")) return lang;\n return AZURE_LOCALE_MAP[lang.toLowerCase()] ?? lang;\n}\n\n/** A curated Danish-speaking Azure voice, exposed so a consuming app can render a\n * picker. `native` = a true da-DK voice (most natural); otherwise a multilingual\n * voice that also speaks Danish (Azure has only 2 native da-DK voices). */\nexport interface AzureVoiceInfo {\n /** Friendly name a caller passes as `voice` (e.g. \"christel\"). */\n name: string;\n /** Full Azure voice name (e.g. \"da-DK-ChristelNeural\"). */\n voiceId: string;\n gender: \"female\" | \"male\";\n /** Display label for a UI picker. */\n display: string;\n /** True for the 2 native da-DK voices; false for multilingual voices speaking Danish. */\n native: boolean;\n /** Per-voice default speaking rate, applied when a call passes no explicit `rate`\n * (e.g. Christel reads a touch fast, so her natural default is 0.85). Omitted = 1 (normal). */\n defaultRate?: number;\n}\n\n/** Curated da-DK roster (F026) — 2 native + 4 multilingual, 3 of each gender.\n * Verified against Azure's voices/list (only Christel + Jeppe are native da-DK). */\nexport const AZURE_DANISH_VOICE_LIST: AzureVoiceInfo[] = [\n { name: \"christel\", voiceId: \"da-DK-ChristelNeural\", gender: \"female\", display: \"Christel\", native: true, defaultRate: 0.85 },\n { name: \"seraphina\", voiceId: \"de-DE-SeraphinaMultilingualNeural\", gender: \"female\", display: \"Seraphina\", native: false },\n { name: \"ava\", voiceId: \"en-US-AvaMultilingualNeural\", gender: \"female\", display: \"Ava\", native: false },\n { name: \"jeppe\", voiceId: \"da-DK-JeppeNeural\", gender: \"male\", display: \"Jeppe\", native: true },\n { name: \"florian\", voiceId: \"de-DE-FlorianMultilingualNeural\", gender: \"male\", display: \"Florian\", native: false },\n { name: \"andrew\", voiceId: \"en-US-AndrewMultilingualNeural\", gender: \"male\", display: \"Andrew\", native: false },\n];\n\n/** Friendly name → full Azure voice name. Distinct from ELEVENLABS_DANISH_VOICES so\n * the client's resolveVoice passes these through unchanged to this adapter. */\nexport const AZURE_DANISH_VOICES: Record<string, string> = Object.fromEntries(\n AZURE_DANISH_VOICE_LIST.map((v) => [v.name, v.voiceId]),\n);\n\n/** The curated Danish voice roster, for a consuming app to present in a picker. */\nexport function listAzureDanishVoices(): AzureVoiceInfo[] {\n return AZURE_DANISH_VOICE_LIST;\n}\n\n/** Resolve a curated friendly name to its full Azure voice; pass a full voice name\n * (e.g. \"da-DK-ChristelNeural\") through unchanged. */\nexport function resolveAzureVoice(nameOrVoice: string): string {\n return AZURE_DANISH_VOICES[nameOrVoice] ?? nameOrVoice;\n}\n\n/** XML-escape so a `&`/`<` in the text can't break the SSML envelope. */\nfunction xmlEscape(s: string): string {\n return s\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n\n/** Derive the BCP-47 locale from a voice name: \"da-DK-ChristelNeural\" → \"da-DK\".\n * Exported so the F037 voice registry derives locales from this one implementation\n * instead of keeping a second copy of the rule. */\nexport function localeOf(voice: string): string {\n const parts = voice.split(\"-\");\n return parts.length >= 2 ? `${parts[0]}-${parts[1]}` : \"en-US\";\n}\n\nexport function azureAdapter(\n config: {\n apiKey?: string;\n region?: string;\n fetch?: typeof fetch;\n pricePer1kChars?: number;\n /** USD per audio-minute for transcribe (overrides AZURE_STT_PRICE_PER_MIN). */\n sttPricePerMin?: number;\n /** STT base URL override (e.g. a resource custom domain). */\n sttBaseUrl?: string;\n /** Resource name → custom-domain STT host `{resource}.cognitiveservices.azure.com`\n * (or env AZURE_SPEECH_RESOURCE). Without it, STT uses the regional host. */\n resource?: string;\n /** Fast-transcription api-version (overrides the GA default). */\n sttApiVersion?: string;\n /** phraseList biasing weight (0–2) applied when a call passes `phrases`. Default 1.5. */\n sttBiasingWeight?: number;\n } = {},\n): ProviderAdapter {\n const fetchImpl = config.fetch ?? fetch;\n\n function key(): string {\n const k = config.apiKey ?? process.env.AZURE_SPEECH_KEY;\n if (!k) throw new Error(\"azure adapter: API key not set (env AZURE_SPEECH_KEY)\");\n return k;\n }\n function region(): string {\n return config.region ?? process.env.AZURE_SPEECH_REGION ?? DEFAULT_REGION;\n }\n /** STT host. Default = regional cognitive host; a resource name (config/env) →\n * the custom-domain host (some resources require it). Live-verified per resource. */\n /** Residency of the STT host we will ACTUALLY call. sttBaseUrl() may come from a\n * custom URL or a resource name, neither of which derives from region() — so\n * reading region() here reported \"eu\" for a call to a US resource whenever\n * AZURE_SPEECH_REGION was left at its default. Exactly the failure F042 exists to\n * prevent, found in review of F042. A resource host carries no region in its name,\n * so it is honestly \"unknown\" unless an explicit region says otherwise. */\n function sttRegion(): Region {\n if (config.sttBaseUrl || config.resource || process.env.AZURE_SPEECH_RESOURCE) {\n // An explicitly-set region still wins — the caller told us where the resource is.\n return config.region ?? process.env.AZURE_SPEECH_REGION\n ? classifyRegionName(region())\n : \"unknown\";\n }\n return classifyRegionName(region());\n }\n\n function sttBaseUrl(): string {\n if (config.sttBaseUrl) return config.sttBaseUrl.replace(/\\/$/, \"\");\n const resource = config.resource ?? process.env.AZURE_SPEECH_RESOURCE;\n if (resource) return `https://${resource}.cognitiveservices.azure.com`;\n return `https://${region()}.api.cognitive.microsoft.com`;\n }\n\n function priceFor(chars: number, model: string): ReturnType<typeof freshUsage> {\n const usage = freshUsage({\n provider: \"azure\",\n model,\n // Same region() that picked the host. westeurope by default, but\n // config.region / AZURE_SPEECH_REGION can point this at eastus.\n region: classifyRegionName(region()),\n transport: \"http\",\n capability: \"tts\",\n inputTokens: 0,\n outputTokens: 0,\n });\n usage.costUsd = (chars / 1000) * (config.pricePer1kChars ?? AZURE_TTS_PRICE_PER_1K_CHARS);\n return usage;\n }\n\n // Single-voice TTS. POST .../cognitiveservices/v1 with an SSML body.\n async function tts(req: TtsRequest): Promise<PodcastResult> {\n const voice = resolveAzureVoice(req.voiceId);\n const lang = req.lang ?? localeOf(voice);\n const format = req.format ?? DEFAULT_FORMAT;\n // Speaking rate via SSML <prosody>: a multiplier of the default (1 = normal,\n // 0.9 = 10% slower, 1.1 = 10% faster). An explicit req.rate wins; otherwise the\n // voice's own defaultRate (e.g. Christel = 0.85) applies; else no wrapper.\n const escaped = xmlEscape(req.text);\n const effRate = req.rate ?? AZURE_DANISH_VOICE_LIST.find((v) => v.voiceId === voice)?.defaultRate;\n const inner =\n effRate != null && effRate !== 1 ? `<prosody rate='${effRate}'>${escaped}</prosody>` : escaped;\n const ssml =\n `<speak version='1.0' xml:lang='${lang}'>` +\n `<voice name='${voice}'>${inner}</voice></speak>`;\n const res = await fetchImpl(\n `https://${region()}.tts.speech.microsoft.com/cognitiveservices/v1`,\n {\n method: \"POST\",\n headers: {\n \"Ocp-Apim-Subscription-Key\": key(),\n \"Content-Type\": \"application/ssml+xml\",\n \"X-Microsoft-OutputFormat\": format,\n },\n body: ssml,\n },\n );\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`azure tts ${res.status}: ${body.slice(0, 300)}`);\n }\n const audio = new Uint8Array(await res.arrayBuffer());\n return { audio, mimeType: \"audio/mpeg\", usage: priceFor(req.text.length, req.spec.model) };\n }\n\n // Speech-to-text (F029) via Azure fast transcription. Synchronous multipart POST\n // → { combinedPhrases:[{text}], durationMilliseconds }. da-DK forced (Voxtral can't).\n // Cost is per audio-minute from the response's real duration. EU-resident.\n async function transcribe(req: TranscribeRequest): Promise<TranscribeResult> {\n const locale = toAzureLocale(req.language);\n const definition: Record<string, unknown> = { locales: [locale] };\n // Bias toward known brand/jargon terms (F029.3) — lifts accuracy on names the\n // model wouldn't otherwise know (e.g. \"cardmem\", \"Pins\"). Other STTs ignore phrases.\n if (req.phrases && req.phrases.length > 0) {\n definition.phraseList = { phrases: req.phrases, biasingWeight: config.sttBiasingWeight ?? 1.5 };\n }\n const form = new FormData();\n form.append(\"audio\", new Blob([req.audio]), \"audio\");\n form.append(\"definition\", JSON.stringify(definition));\n const url = `${sttBaseUrl()}/speechtotext/transcriptions:transcribe?api-version=${config.sttApiVersion ?? DEFAULT_STT_API_VERSION}`;\n const res = await fetchImpl(url, {\n method: \"POST\",\n headers: { \"Ocp-Apim-Subscription-Key\": key() },\n body: form,\n });\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`azure transcribe ${res.status}: ${body.slice(0, 300)}`);\n }\n const data = (await res.json()) as {\n combinedPhrases?: { text?: string }[];\n durationMilliseconds?: number;\n // Fast-transcription phrases carry ms offsets + per-word timing (F036.1).\n phrases?: {\n text?: string;\n offsetMilliseconds?: number;\n durationMilliseconds?: number;\n words?: { text?: string; offsetMilliseconds?: number; durationMilliseconds?: number }[];\n }[];\n };\n const text = data.combinedPhrases?.[0]?.text ?? \"\";\n // Prefer the API's real duration; fall back to a caller-supplied durationSec.\n const minutes =\n data.durationMilliseconds != null\n ? data.durationMilliseconds / 60000\n : (req.durationSec ?? 0) / 60;\n const usage = freshUsage({\n provider: \"azure\",\n model: req.spec.model,\n region: sttRegion(),\n transport: \"http\",\n capability: \"transcribe\",\n inputTokens: 0,\n outputTokens: 0,\n });\n usage.costUsd = minutes * (config.sttPricePerMin ?? AZURE_STT_PRICE_PER_MIN);\n const result: TranscribeResult = { text, usage };\n // Timestamps (F036.1) — Azure fast-transcription already returns phrases+words\n // with ms offsets; surface them on the same TranscribeResult shape as Whisper.\n // \"word\" granularity → words[]; any timestamps request → segments[].\n if (req.timestamps && req.timestamps.length > 0 && data.phrases) {\n const toSec = (ms?: number) => (ms ?? 0) / 1000;\n if (req.timestamps.includes(\"word\")) {\n const words = data.phrases.flatMap((p) => p.words ?? []);\n if (words.length > 0) {\n result.words = words.map((w) => ({\n word: w.text ?? \"\",\n start: toSec(w.offsetMilliseconds),\n end: toSec((w.offsetMilliseconds ?? 0) + (w.durationMilliseconds ?? 0)),\n }));\n }\n }\n result.segments = data.phrases.map((p) => ({\n text: p.text ?? \"\",\n start: toSec(p.offsetMilliseconds),\n end: toSec((p.offsetMilliseconds ?? 0) + (p.durationMilliseconds ?? 0)),\n }));\n }\n return result;\n }\n\n return { name: \"azure\", tts, transcribe };\n}\n","// Google Cloud Vertex AI adapter (F031) — EU-resident `ai.animate` (Veo). Reuses\n// the exact Veo request/poll/download shape proven live in gemini.ts (F024), but\n// swaps: (a) endpoint → a region-pinned Vertex host (default europe-west1, the\n// whole reason this adapter exists), (b) auth → a GCP service-account OAuth2\n// Bearer token, self-minted via node:crypto (zero extra deps), not an API key.\n//\n// UNVERIFIED SHAPE NOTE: the inline-bytes response parsing below (`response.\n// videos[].bytesBase64Encoded`) is our best-effort read of Vertex's public Veo\n// docs — it has not yet been proven against a real Vertex response (F031.3's\n// live smoke does that). A `gcsUri`-shaped response throws a clear error rather\n// than silently mis-parsing.\nimport { createSign } from \"node:crypto\";\nimport { readFileSync } from \"node:fs\";\nimport { toInlineImage } from \"./media.js\";\nimport { partsFrom, type GeminiPart, splitCached } from \"./gemini.js\";\nimport { freshUsage, computeCost } from \"../cost/usage.js\";\nimport { classifyRegionName } from \"../cost/region.js\";\nimport { errorBody } from \"../transport/http.js\";\nimport type {\n ProviderAdapter,\n AnimateRequest,\n AnimateResult,\n ChatRequest,\n ChatResult,\n Message,\n} from \"../types.js\";\n\nconst TOKEN_ENDPOINT = \"https://oauth2.googleapis.com/token\";\nconst DEFAULT_REGION = \"europe-west1\";\nconst CLOUD_PLATFORM_SCOPE = \"https://www.googleapis.com/auth/cloud-platform\";\n\n/** Per-SECOND USD for Veo on Vertex — same model family/pricing as the consumer\n * Gemini API (F024's VEO_PRICE_PER_SEC). Override per call via config.pricePerSecond. */\nconst VERTEX_VEO_PRICE_PER_SEC: Record<string, number> = {\n \"veo-3.1-generate-preview\": 0.4,\n \"veo-3.1-fast-generate-preview\": 0.1,\n \"veo-3.1-lite-generate-preview\": 0.05,\n \"veo-3.0-generate-001\": 0.4,\n \"veo-3.0-fast-generate-001\": 0.1,\n};\n\ninterface ServiceAccountCredentials {\n client_email: string;\n private_key: string;\n /** Present in a real service-account key; used as the project fallback (F038). */\n project_id?: string;\n}\n\ninterface VertexOperation {\n done?: boolean;\n error?: { message?: string };\n response?: {\n videos?: { bytesBase64Encoded?: string; gcsUri?: string; mimeType?: string }[];\n };\n}\n\nfunction base64url(input: Buffer | string): string {\n const buf = typeof input === \"string\" ? Buffer.from(input) : input;\n return buf.toString(\"base64\").replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n}\n\nfunction resolveCredentials(config: { credentials?: string }): ServiceAccountCredentials {\n const inline = config.credentials ?? process.env.GOOGLE_VERTEX_CREDENTIALS;\n if (inline) {\n try {\n return JSON.parse(inline) as ServiceAccountCredentials;\n } catch {\n throw new Error(\"vertex adapter: GOOGLE_VERTEX_CREDENTIALS is not valid JSON\");\n }\n }\n const path = process.env.GOOGLE_APPLICATION_CREDENTIALS;\n if (path) {\n let raw: string;\n try {\n raw = readFileSync(path, \"utf8\");\n } catch (err) {\n throw new Error(`vertex adapter: failed to read GOOGLE_APPLICATION_CREDENTIALS file: ${(err as Error).message}`);\n }\n return JSON.parse(raw) as ServiceAccountCredentials;\n }\n throw new Error(\n \"vertex adapter: service-account credentials not set (env GOOGLE_VERTEX_CREDENTIALS inline JSON, or GOOGLE_APPLICATION_CREDENTIALS file path)\",\n );\n}\n\n/** Self-sign a JWT and exchange it for a Bearer access token — no google-auth-library dep. */\nasync function mintAccessToken(\n creds: ServiceAccountCredentials,\n fetchImpl: typeof fetch,\n): Promise<{ token: string; expiresAt: number }> {\n const now = Math.floor(Date.now() / 1000);\n const header = { alg: \"RS256\", typ: \"JWT\" };\n const claims = {\n iss: creds.client_email,\n scope: CLOUD_PLATFORM_SCOPE,\n aud: TOKEN_ENDPOINT,\n iat: now,\n exp: now + 3600,\n };\n const unsigned = `${base64url(JSON.stringify(header))}.${base64url(JSON.stringify(claims))}`;\n const signature = createSign(\"RSA-SHA256\").update(unsigned).sign(creds.private_key);\n const jwt = `${unsigned}.${base64url(signature)}`;\n\n const res = await fetchImpl(TOKEN_ENDPOINT, {\n method: \"POST\",\n headers: { \"content-type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({\n grant_type: \"urn:ietf:params:oauth:grant-type:jwt-bearer\",\n assertion: jwt,\n }).toString(),\n });\n if (!res.ok) {\n throw new Error(`vertex adapter: token exchange failed ${res.status}: ${(await res.text().catch(() => \"\")).slice(0, 300)}`);\n }\n const data = (await res.json()) as { access_token?: string; expires_in?: number };\n if (!data.access_token) throw new Error(\"vertex adapter: token exchange returned no access_token\");\n return { token: data.access_token, expiresAt: Date.now() + (data.expires_in ?? 3600) * 1000 };\n}\n\nexport function vertexAdapter(\n config: {\n /** Inline service-account JSON; else env GOOGLE_VERTEX_CREDENTIALS or GOOGLE_APPLICATION_CREDENTIALS (file path). */\n credentials?: string;\n /** GCP project id; else env GOOGLE_VERTEX_PROJECT. Required — never guessed. */\n project?: string;\n /** Vertex region; default \"europe-west1\" (EU by default — this adapter's reason to exist). */\n region?: string;\n fetch?: typeof fetch;\n pricePerSecond?: number;\n pollIntervalMs?: number;\n videoTimeoutMs?: number;\n } = {},\n): ProviderAdapter {\n const fetchImpl = config.fetch ?? fetch;\n let cached: { token: string; expiresAt: number } | null = null;\n\n function region(): string {\n return config.region ?? process.env.GOOGLE_VERTEX_REGION ?? DEFAULT_REGION;\n }\n function project(): string {\n // The service-account JSON already carries project_id, so falling back to it\n // spares every consumer a second env var whose value is sitting in the first\n // one — and spares them a \"project not set\" error that looks like a bug.\n const p =\n config.project ?? process.env.GOOGLE_VERTEX_PROJECT ?? resolveCredentials(config).project_id;\n if (!p) throw new Error(\"vertex adapter: project not set (config.project, env GOOGLE_VERTEX_PROJECT, or project_id in the credentials)\");\n return p;\n }\n async function accessToken(): Promise<string> {\n if (cached && cached.expiresAt - 60_000 > Date.now()) return cached.token;\n const creds = resolveCredentials(config);\n cached = await mintAccessToken(creds, fetchImpl);\n return cached.token;\n }\n\n async function animate(req: AnimateRequest): Promise<AnimateResult> {\n const token = await accessToken();\n const proj = project();\n const reg = region();\n const pollIntervalMs = config.pollIntervalMs ?? 5000;\n const deadline = Date.now() + (config.videoTimeoutMs ?? 300000);\n const baseUrl = `https://${reg}-aiplatform.googleapis.com/v1`;\n\n const { data, mimeType } = await toInlineImage(req.image, fetchImpl);\n const parameters: Record<string, unknown> = {};\n if (req.durationSec !== undefined) parameters.durationSeconds = req.durationSec;\n if (req.resolution !== undefined) parameters.resolution = req.resolution;\n const body = {\n instances: [{ prompt: req.prompt ?? \"\", image: { bytesBase64Encoded: data, mimeType } }],\n ...(Object.keys(parameters).length ? { parameters } : {}),\n };\n\n const submit = await fetchImpl(\n `${baseUrl}/projects/${proj}/locations/${reg}/publishers/google/models/${req.spec.model}:predictLongRunning`,\n {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", authorization: `Bearer ${token}` },\n body: JSON.stringify(body),\n },\n );\n if (!submit.ok) {\n throw new Error(`vertex animate ${submit.status}: ${(await submit.text().catch(() => \"\")).slice(0, 300)}`);\n }\n const op = (await submit.json()) as { name?: string };\n if (!op.name) throw new Error(\"vertex animate: no operation name in submit response\");\n\n let videoB64: string | undefined;\n let videoMime = \"video/mp4\";\n for (;;) {\n const poll = await fetchImpl(`${baseUrl}/${op.name}`, { headers: { authorization: `Bearer ${token}` } });\n if (!poll.ok) throw new Error(`vertex animate poll ${poll.status}`);\n const opData = (await poll.json()) as VertexOperation;\n if (opData.error) throw new Error(`vertex animate: ${opData.error.message ?? \"operation error\"}`);\n if (opData.done) {\n const video = opData.response?.videos?.[0];\n if (!video) {\n throw new Error(`vertex animate: done but no video in response: ${errorBody(opData.response)}`);\n }\n if (!video.bytesBase64Encoded) {\n if (video.gcsUri) {\n throw new Error(\n `vertex animate: response returned a gcsUri (\"${video.gcsUri}\") — GCS download not yet supported (F031.x); this build only handles inline bytes`,\n );\n }\n throw new Error(`vertex animate: done but no bytesBase64Encoded in response: ${errorBody(opData.response)}`);\n }\n videoB64 = video.bytesBase64Encoded;\n videoMime = video.mimeType ?? \"video/mp4\";\n break;\n }\n if (Date.now() >= deadline) throw new Error(\"vertex animate: timed out\");\n await new Promise((r) => setTimeout(r, pollIntervalMs));\n }\n\n const usage = freshUsage({\n provider: \"vertex\",\n model: req.spec.model,\n // Read from the SAME region() that built the URL above — this adapter is EU by\n // default, but config.region / GOOGLE_VERTEX_REGION can move it, and a residency\n // field that ignores the override is worse than none.\n region: classifyRegionName(region()),\n transport: \"http\",\n capability: \"animate\",\n inputTokens: 0,\n outputTokens: 0,\n });\n const perSec = config.pricePerSecond ?? VERTEX_VEO_PRICE_PER_SEC[req.spec.model] ?? 0;\n usage.costUsd = perSec * (req.durationSec ?? 8);\n return { url: `vertex://${op.name}`, bytes: Buffer.from(videoB64, \"base64\"), mimeType: videoMime, usage };\n }\n\n // EU-resident image + VIDEO analysis (F038). Vertex speaks the same\n // generateContent shape as the Gemini API, so the message→parts mapping is\n // imported rather than copied. The URL is region-pinned exactly like animate:\n // personal data (faces, EXIF geo) must not leave the EU, and there is NO\n // fallback to another region — an EU error propagates to the caller.\n async function vision(req: ChatRequest): Promise<ChatResult> {\n const token = await accessToken();\n const proj = project();\n const reg = region();\n\n const systemParts: GeminiPart[] = [];\n const contents: { role: string; parts: GeminiPart[] }[] = [];\n for (const m of req.messages as Message[]) {\n if (m.role === \"system\") systemParts.push(...partsFrom(m.content));\n else contents.push({ role: m.role === \"assistant\" ? \"model\" : \"user\", parts: partsFrom(m.content) });\n }\n const body: Record<string, unknown> = { contents };\n if (systemParts.length > 0) body.systemInstruction = { parts: systemParts };\n const genConfig: Record<string, unknown> = {};\n if (req.maxTokens !== undefined) genConfig.maxOutputTokens = req.maxTokens;\n if (req.temperature !== undefined) genConfig.temperature = req.temperature;\n if (Object.keys(genConfig).length > 0) body.generationConfig = genConfig;\n\n const url =\n `https://${reg}-aiplatform.googleapis.com/v1/projects/${proj}` +\n `/locations/${reg}/publishers/google/models/${req.spec.model}:generateContent`;\n const res = await fetchImpl(url, {\n method: \"POST\",\n headers: { authorization: `Bearer ${token}`, \"content-type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n if (!res.ok) {\n throw new Error(`vertex vision ${res.status}: ${(await res.text().catch(() => \"\")).slice(0, 300)}`);\n }\n const data = (await res.json()) as {\n candidates?: { content?: { parts?: GeminiPart[] } }[];\n usageMetadata?: { promptTokenCount?: number; candidatesTokenCount?: number; cachedContentTokenCount?: number };\n };\n const text = (data.candidates?.[0]?.content?.parts ?? [])\n .map((p) => p.text ?? \"\")\n .join(\"\")\n .trim();\n\n // F040: Vertex serves the same Gemini models and the same usageMetadata shape,\n // so it reuses gemini.ts's splitter rather than keeping a second copy of the\n // subtraction rule. promptTokenCount INCLUDES cachedContentTokenCount.\n const { inputTokens, cacheReadTokens } = splitCached(data.usageMetadata);\n const outputTokens = data.usageMetadata?.candidatesTokenCount ?? 0;\n const usage = freshUsage({\n provider: \"vertex\",\n model: req.spec.model,\n // Read from the SAME region() that built the URL above — this adapter is EU by\n // default, but config.region / GOOGLE_VERTEX_REGION can move it, and a residency\n // field that ignores the override is worse than none.\n region: classifyRegionName(region()),\n transport: \"http\",\n capability: \"vision\",\n inputTokens,\n outputTokens,\n ...(cacheReadTokens === undefined ? {} : { cacheReadTokens }),\n });\n usage.costUsd = computeCost(\"vertex\", req.spec.model, inputTokens, outputTokens, cacheReadTokens ?? 0);\n return { text, usage };\n }\n\n return { name: \"vertex\", animate, vision };\n}\n","// DeepL translation adapter (F032) — a dedicated MT engine, not a chat model.\n// Implements ProviderAdapter.translate directly (no chat prompt-contract).\n// EU-hosted (Falun, Sweden per deepl.com). Opt-in via override:{provider:\"deepl\"};\n// the LLM-prompt-based ai.translate stays the default for every other provider.\n//\n// CONTRACT NOTE: DeepL requires real language codes (\"DA\", \"EN-US\", \"DE\", …) in\n// `to`/`from` — NOT the free-form names the chat-based route accepts (\"Danish\").\n// This adapter does not translate names to codes; pass DeepL's own codes.\nimport { freshUsage } from \"../cost/usage.js\";\nimport { regionOfHost } from \"../cost/region.js\";\nimport type { ProviderAdapter, TranslateRequest, TranslateResult } from \"../types.js\";\n\n/** USD per 1000 characters. UNVERIFIED ESTIMATE — DeepL's own pricing pages\n * resisted automated fetch (JS-rendered / bot-protected) as of 2026-06-20;\n * third-party sources converge loosely around €20/1M chars for the Pro API,\n * but conflicting subscription-tier reports exist. Verify against\n * deepl.com/pro-api directly before relying on this for a budget decision.\n * Override via config.pricePer1kChars. Free-tier (\":fx\" key, within quota) is\n * genuinely $0 — this rate only matters for Pro usage past the free allowance. */\nconst DEEPL_PRICE_PER_1K_CHARS_ESTIMATE = 0.0217;\n\nexport function deeplAdapter(\n config: { apiKey?: string; baseUrl?: string; fetch?: typeof fetch; pricePer1kChars?: number } = {},\n): ProviderAdapter {\n const fetchImpl = config.fetch ?? fetch;\n\n function key(): string {\n const k = config.apiKey ?? process.env.DEEPL_API_KEY;\n if (!k) throw new Error(\"deepl adapter: API key not set (env DEEPL_API_KEY)\");\n return k;\n }\n\n // DeepL Free API keys always end in \":fx\" — a documented DeepL convention —\n // and must hit the free-tier host, not the Pro one.\n function baseUrl(apiKey: string): string {\n return config.baseUrl ?? (apiKey.endsWith(\":fx\") ? \"https://api-free.deepl.com\" : \"https://api.deepl.com\");\n }\n\n async function translate(req: TranslateRequest): Promise<TranslateResult> {\n const apiKey = key();\n const body: Record<string, unknown> = { text: [req.text], target_lang: req.to.toUpperCase() };\n if (req.from) body.source_lang = req.from.toUpperCase();\n\n const res = await fetchImpl(`${baseUrl(apiKey)}/v2/translate`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", authorization: `DeepL-Auth-Key ${apiKey}` },\n body: JSON.stringify(body),\n });\n if (!res.ok) {\n const errBody = await res.text().catch(() => \"\");\n throw new Error(`deepl translate ${res.status}: ${errBody.slice(0, 300)}`);\n }\n const data = (await res.json()) as { translations?: { text?: string; detected_source_language?: string }[] };\n const text = data.translations?.[0]?.text;\n if (text === undefined) throw new Error(\"deepl translate: response contained no translation\");\n\n const usage = freshUsage({\n provider: \"deepl\",\n region: regionOfHost(baseUrl(apiKey)),\n model: req.spec.model,\n transport: \"http\",\n capability: \"translate\",\n inputTokens: 0,\n outputTokens: 0,\n });\n usage.costUsd = (req.text.length / 1000) * (config.pricePer1kChars ?? DEEPL_PRICE_PER_1K_CHARS_ESTIMATE);\n return { text, usage };\n }\n\n return { name: \"deepl\", translate };\n}\n","// fal.ai adapter (F5.3 + F021). Image modes, both observed in the F1 inventory:\n// - sync : POST https://fal.run/{model}, image URL straight back (sanneandersen)\n// - queue : POST https://queue.fal.run/{model} → poll status → fetch result\n// F021 adds LoRA style-training (trainStyle) + LoRA inference (image loras).\n// Auth header `Authorization: Key <FAL_KEY>`. No @fal-ai/client — plain fetch.\nimport { deflateRawSync, crc32 } from \"node:zlib\";\nimport { freshUsage } from \"../cost/usage.js\";\nimport type {\n ProviderAdapter,\n ImageRequest,\n ImageResult,\n AnimateRequest,\n AnimateResult,\n TrainStyleRequest,\n TrainStyleResult,\n} from \"../types.js\";\n\ninterface FalImagesResponse {\n images?: { url?: string }[];\n has_nsfw_concepts?: boolean[];\n error?: unknown;\n}\ninterface FalTrainResponse {\n diffusers_lora_file?: { url?: string };\n config_file?: { url?: string };\n}\ninterface FalQueueSubmit {\n request_id?: string;\n status_url?: string;\n response_url?: string;\n}\ninterface FalQueueStatus {\n status?: \"IN_QUEUE\" | \"IN_PROGRESS\" | \"COMPLETED\" | \"FAILED\";\n}\n\nexport interface FalAdapterConfig {\n apiKey?: string;\n /** \"sync\" (default — fal.run, fast models) or \"queue\" (queue.fal.run, polled). */\n mode?: \"sync\" | \"queue\";\n syncBaseUrl?: string;\n queueBaseUrl?: string;\n pollIntervalMs?: number;\n timeoutMs?: number;\n /** Deadline for training jobs — they take minutes (default 600000 = 10 min). */\n trainTimeoutMs?: number;\n /** Deadline for video jobs — they take minutes (default 600000 = 10 min). */\n videoTimeoutMs?: number;\n fetch?: typeof fetch;\n /** Override the per-image USD price (else a built-in estimate per model, 0 if unknown). */\n pricePerImage?: number;\n /** Override the flat per-training USD price (else ~$2 estimate). */\n pricePerTraining?: number;\n /** Override the per-SECOND video USD price (else a built-in estimate per model, 0 if unknown). */\n pricePerSecond?: number;\n}\n\n// Per-image USD ESTIMATES (fal prices by megapixel/model and changes often —\n// verify before relying on these; override via config.pricePerImage). fal does\n// not return a price, so this is the SDK's best-effort cost for `usage.costUsd`.\nconst FAL_IMAGE_PRICE_ESTIMATE: Record<string, number> = {\n \"fal-ai/flux/schnell\": 0.003,\n \"fal-ai/flux/dev\": 0.025,\n \"fal-ai/flux-lora\": 0.025,\n \"fal-ai/flux-pro\": 0.05,\n \"fal-ai/flux-pro/v1.1\": 0.04,\n};\n// Flat training estimate (fal-ai/flux-lora-fast-training, ~$2; override via config).\nconst FAL_TRAIN_PRICE_ESTIMATE = 2.0;\n\n// Per-SECOND USD estimates for video models (F024). fal does not return a price,\n// and rates vary by model/resolution — entries are fal's OFFICIAL published\n// per-second rate (fal.ai/models/<id> pricing), not guessed; override via\n// config.pricePerSecond. Unknown model → 0 (cost surfaced via a live smoke,\n// not a fabricated number).\nconst FAL_VIDEO_PRICE_PER_SEC: Record<string, number> = {\n // Kling 2.5 Turbo Pro i2v — the blessed FAL_KEY-only image→video route (F014\n // contentpush spike). $0.35 for the first 5 s + $0.07/additional s = a flat\n // $0.07/s (1080p); per-second-billed, commercial-use, not deprecated.\n \"fal-ai/kling-video/v2.5-turbo/pro/image-to-video\": 0.07,\n};\n// Default clip length to bill when the caller doesn't pass durationSec (Veo ≈ 8s).\nconst FAL_VIDEO_DEFAULT_SEC = 8;\n\nconst sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));\n\nexport function falAdapter(config: FalAdapterConfig = {}): ProviderAdapter {\n const doFetch = config.fetch ?? fetch;\n const syncBase = config.syncBaseUrl ?? \"https://fal.run\";\n const queueBase = config.queueBaseUrl ?? \"https://queue.fal.run\";\n const pollIntervalMs = config.pollIntervalMs ?? 2000;\n const timeoutMs = config.timeoutMs ?? 60000;\n\n // sa flagged the gotcha: their env is FAL_API_KEY, the older convention is FAL_KEY.\n // Accept either so no repo has to alias one to the other.\n const resolveKey = () => config.apiKey ?? process.env.FAL_KEY ?? process.env.FAL_API_KEY;\n const authHeaders = (apiKey: string) => ({\n \"content-type\": \"application/json\",\n Authorization: `Key ${apiKey}`,\n });\n\n async function image(req: ImageRequest): Promise<ImageResult> {\n const apiKey = resolveKey();\n if (!apiKey) throw new Error(\"fal adapter: FAL_KEY not set\");\n const headers = authHeaders(apiKey);\n\n const body: Record<string, unknown> = { prompt: req.prompt };\n if (req.width !== undefined && req.height !== undefined) {\n body.image_size = { width: req.width, height: req.height };\n }\n if (req.loras && req.loras.length > 0) {\n body.loras = req.loras.map((l) => ({ path: l.path, scale: l.scale ?? 1 }));\n }\n\n const mode = config.mode ?? \"sync\";\n const run = (b: Record<string, unknown>) =>\n mode === \"sync\" ? runSync(req.spec.model, headers, b) : runQueue(req.spec.model, headers, b);\n\n let calls = 1;\n let { url, flagged } = await run(body);\n // F021.4 — fal's NSFW safety-checker occasionally false-positives on clean\n // LoRA output and returns a fully BLACK image (has_nsfw_concepts[0]=true).\n // When retryOnBlack is set, re-roll ONCE with a fresh seed.\n if (flagged && req.retryOnBlack) {\n calls++;\n ({ url, flagged } = await run({ ...body, seed: Math.floor(Math.random() * 1e9) }));\n }\n\n // fal returns no price; estimate per-image so usage.costUsd isn't silently 0.\n // A re-roll is a second billed generation → multiply by the call count.\n const usage = freshUsage({\n provider: \"fal\",\n model: req.spec.model,\n transport: \"http\",\n capability: \"image\",\n inputTokens: 0,\n outputTokens: 0,\n });\n usage.costUsd = (config.pricePerImage ?? FAL_IMAGE_PRICE_ESTIMATE[req.spec.model] ?? 0) * calls;\n return { url, usage };\n }\n\n async function animate(req: AnimateRequest): Promise<AnimateResult> {\n const apiKey = resolveKey();\n if (!apiKey) throw new Error(\"fal adapter: FAL_KEY not set\");\n const headers = authHeaders(apiKey);\n\n // Input image: a URL passes through; raw bytes are uploaded to fal storage\n // (fal needs a fetchable URL, not a data: URI — same gotcha as trainStyle).\n const imageUrl =\n typeof req.image === \"string\" && /^https?:\\/\\//i.test(req.image)\n ? req.image\n : await uploadToFalStorage(toBytes(req.image), sniffImageType(req.image), \"input\", apiKey);\n\n const body: Record<string, unknown> = { image_url: imageUrl };\n if (req.prompt !== undefined) body.prompt = req.prompt;\n if (req.durationSec !== undefined) body.duration = req.durationSec;\n if (req.resolution !== undefined) body.resolution = req.resolution;\n\n // Video is long-running → always the queue, with the longer deadline.\n const result = await queueResult(req.spec.model, headers, body, config.videoTimeoutMs ?? 600000);\n const url = extractVideoUrl(result);\n if (!url) {\n throw new Error(\n `fal animate: no video url in result — keys [${Object.keys(\n (result as Record<string, unknown>) ?? {},\n ).join(\", \")}]: ${JSON.stringify(result).slice(0, 500)}`,\n );\n }\n\n const usage = freshUsage({\n provider: \"fal\",\n model: req.spec.model,\n transport: \"http\",\n capability: \"animate\",\n inputTokens: 0,\n outputTokens: 0,\n });\n // fal returns no price → per-second estimate × duration (override config.pricePerSecond).\n const perSec = config.pricePerSecond ?? FAL_VIDEO_PRICE_PER_SEC[req.spec.model] ?? 0;\n usage.costUsd = perSec * (req.durationSec ?? FAL_VIDEO_DEFAULT_SEC);\n return { url, usage };\n }\n\n async function trainStyle(req: TrainStyleRequest): Promise<TrainStyleResult> {\n const apiKey = resolveKey();\n if (!apiKey) throw new Error(\"fal adapter: FAL_KEY not set\");\n const headers = authHeaders(apiKey);\n\n const body: Record<string, unknown> = {\n images_data_url: await resolveImagesUrl(req.images, apiKey),\n is_style: req.isStyle ?? true,\n };\n if (req.triggerWord !== undefined) body.trigger_word = req.triggerWord;\n if (req.steps !== undefined) body.steps = req.steps;\n if (req.createMasks !== undefined) body.create_masks = req.createMasks;\n\n // Training runs on the queue and takes minutes — use the longer deadline.\n const result = (await queueResult(\n req.spec.model,\n headers,\n body,\n config.trainTimeoutMs ?? 600000,\n )) as FalTrainResponse;\n // fal's LoRA trainers vary in output shape (field renames, wrappers, multiple\n // trainer endpoints). Extract defensively across known/likely locations, then\n // fall back to scanning for any *.safetensors url. If still nothing, surface the\n // RAW response so a shape mismatch is diagnosable without a key on this side.\n const { loraUrl, configUrl } = extractTrainedFiles(result);\n if (!loraUrl) {\n throw new Error(\n `fal trainStyle: no LoRA file url in result — fal returned keys [${Object.keys(\n (result as Record<string, unknown>) ?? {},\n ).join(\", \")}]: ${JSON.stringify(result).slice(0, 800)}`,\n );\n }\n\n const usage = freshUsage({\n provider: \"fal\",\n model: req.spec.model,\n transport: \"http\",\n capability: \"trainStyle\",\n inputTokens: 0,\n outputTokens: 0,\n });\n usage.costUsd = config.pricePerTraining ?? FAL_TRAIN_PRICE_ESTIMATE;\n return { loraUrl, configUrl: configUrl ?? \"\", usage };\n }\n\n /** A hosted archive URL passes straight through; an array of image URLs is fetched,\n * zipped in-memory, and uploaded to fal storage. fal REJECTS data: URIs here\n * (\"Invalid URL: URL too long\") — images_data_url must be a real http URL it can\n * fetch, so we upload the zip and pass the returned file_url. */\n async function resolveImagesUrl(images: string | string[], apiKey: string): Promise<string> {\n if (typeof images === \"string\") return images;\n const files = await Promise.all(\n images.map(async (url, i) => {\n const res = await doFetch(url);\n if (!res.ok) throw new Error(`fal trainStyle: failed to fetch image ${url} (${res.status})`);\n return { name: fileNameFromUrl(url, i), data: new Uint8Array(await res.arrayBuffer()) };\n }),\n );\n return uploadToFalStorage(buildZip(files), \"application/zip\", \"styleset.zip\", apiKey);\n }\n\n /** Upload bytes to fal storage: initiate (auth'd) → PUT to the returned signed url\n * → return the public file_url. fal CDN serves it back, fetchable by the trainer. */\n async function uploadToFalStorage(\n bytes: Uint8Array,\n contentType: string,\n fileName: string,\n apiKey: string,\n ): Promise<string> {\n const initiate = await doFetch(\"https://rest.alpha.fal.ai/storage/upload/initiate\", {\n method: \"POST\",\n headers: { Authorization: `Key ${apiKey}`, \"content-type\": \"application/json\" },\n body: JSON.stringify({ content_type: contentType, file_name: fileName }),\n });\n if (!initiate.ok) {\n throw new Error(\n `fal storage initiate ${initiate.status}: ${(await initiate.text().catch(() => \"\")).slice(0, 200)}`,\n );\n }\n const { upload_url, file_url } = (await initiate.json()) as { upload_url: string; file_url: string };\n const put = await doFetch(upload_url, {\n method: \"PUT\",\n headers: { \"content-type\": contentType },\n body: bytes,\n });\n if (!put.ok) throw new Error(`fal storage upload PUT ${put.status}`);\n return file_url;\n }\n\n /** Returns the image url + whether fal's safety-checker flagged it (→ black image). */\n async function runSync(\n model: string,\n headers: Record<string, string>,\n body: unknown,\n ): Promise<{ url: string; flagged: boolean }> {\n const res = await doFetch(`${syncBase}/${model}`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n });\n if (!res.ok) {\n throw new Error(`fal ${res.status}: ${(await res.text().catch(() => \"\")).slice(0, 200)}`);\n }\n const data = (await res.json()) as FalImagesResponse;\n const out = data.images?.[0]?.url;\n if (!out) throw new Error(`fal: no image url in response`);\n return { url: out, flagged: data.has_nsfw_concepts?.[0] === true };\n }\n\n async function runQueue(\n model: string,\n headers: Record<string, string>,\n body: unknown,\n ): Promise<{ url: string; flagged: boolean }> {\n const result = (await queueResult(model, headers, body, timeoutMs)) as FalImagesResponse;\n const out = result.images?.[0]?.url;\n if (!out) throw new Error(\"fal queue: no image url in result\");\n return { url: out, flagged: result.has_nsfw_concepts?.[0] === true };\n }\n\n /** Generic fal queue runner: submit → poll status → fetch+return the raw result JSON. */\n async function queueResult(\n model: string,\n headers: Record<string, string>,\n body: unknown,\n deadlineMs: number,\n ): Promise<unknown> {\n const submitRes = await doFetch(`${queueBase}/${model}`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n });\n if (!submitRes.ok) {\n throw new Error(\n `fal queue submit ${submitRes.status}: ${(await submitRes.text().catch(() => \"\")).slice(0, 200)}`,\n );\n }\n const submit = (await submitRes.json()) as FalQueueSubmit;\n const statusUrl = submit.status_url;\n const responseUrl = submit.response_url;\n if (!statusUrl || !responseUrl) throw new Error(\"fal queue: missing status/response url\");\n\n const deadline = Date.now() + deadlineMs;\n for (;;) {\n const statusRes = await doFetch(statusUrl, { headers });\n const status = (await statusRes.json()) as FalQueueStatus;\n if (status.status === \"COMPLETED\") break;\n if (status.status === \"FAILED\") throw new Error(\"fal queue: job FAILED\");\n if (Date.now() >= deadline) throw new Error(`fal queue: timed out after ${deadlineMs}ms`);\n await sleep(pollIntervalMs);\n }\n\n const resultRes = await doFetch(responseUrl, { headers });\n if (!resultRes.ok) {\n throw new Error(\n `fal queue result ${resultRes.status}: ${(await resultRes.text().catch(() => \"\")).slice(0, 300)}`,\n );\n }\n return resultRes.json();\n }\n\n return { name: \"fal\", image, animate, trainStyle };\n}\n\n/** Coerce an image input to bytes (a non-http string is treated as base64/data-URI). */\nfunction toBytes(img: string | Uint8Array): Uint8Array {\n if (typeof img !== \"string\") return img;\n const b64 = img.startsWith(\"data:\") ? img.slice(img.indexOf(\",\") + 1) : img;\n return new Uint8Array(Buffer.from(b64, \"base64\"));\n}\n\n/** Sniff a content-type from the bytes' magic (PNG/WebP/GIF), default JPEG. */\nfunction sniffImageType(img: string | Uint8Array): string {\n const b = toBytes(img);\n if (b[0] === 0x89 && b[1] === 0x50) return \"image/png\";\n if (b[0] === 0x47 && b[1] === 0x49) return \"image/gif\";\n if (b[0] === 0x52 && b[1] === 0x49 && b[8] === 0x57) return \"image/webp\";\n return \"image/jpeg\";\n}\n\n/** Find the result video URL across fal's video-output shapes (video.url, a wrapper,\n * or any *.mp4/.webm url anywhere in the response). */\nexport function extractVideoUrl(result: unknown): string | undefined {\n const r = result as Record<string, unknown> | null | undefined;\n const root = (r?.data ?? r?.response ?? r?.output ?? r) as Record<string, unknown> | null | undefined;\n return (\n urlOf(root?.video) ??\n urlOf((root?.videos as unknown[] | undefined)?.[0]) ??\n deepFindUrl(root, (u) => /\\.(mp4|webm|mov)(\\?|$)/i.test(u))\n );\n}\n\n// ── fal trained-file extraction (defensive against output-shape variance) ────\n\nfunction urlOf(v: unknown): string | undefined {\n if (typeof v === \"string\") return v;\n if (v && typeof v === \"object\" && typeof (v as { url?: unknown }).url === \"string\") {\n return (v as { url: string }).url;\n }\n return undefined;\n}\n\n/** BFS the response for the first {url}/string url matching `match`. */\nfunction deepFindUrl(obj: unknown, match: (url: string) => boolean): string | undefined {\n const stack: unknown[] = [obj];\n while (stack.length) {\n const cur = stack.pop();\n if (typeof cur === \"string\") {\n if (match(cur)) return cur;\n continue;\n }\n if (cur && typeof cur === \"object\") {\n const u = (cur as { url?: unknown }).url;\n if (typeof u === \"string\" && match(u)) return u;\n for (const v of Object.values(cur as Record<string, unknown>)) stack.push(v);\n }\n }\n return undefined;\n}\n\n/** Find the LoRA + config urls across known field names, an optional data/response/\n * output wrapper, and — as a last resort — any *.safetensors / config *.json url\n * anywhere in the response. fal's LoRA trainers vary in output shape. */\nexport function extractTrainedFiles(result: unknown): { loraUrl?: string; configUrl?: string } {\n const r = result as Record<string, unknown> | null | undefined;\n const root = (r?.data ?? r?.response ?? r?.output ?? r) as\n | Record<string, unknown>\n | null\n | undefined;\n const loraUrl =\n urlOf(root?.diffusers_lora_file) ??\n urlOf(root?.lora_file) ??\n urlOf(root?.safetensors) ??\n urlOf(root?.lora) ??\n deepFindUrl(root, (u) => /\\.safetensors(\\?|$)/i.test(u));\n const configUrl =\n urlOf(root?.config_file) ??\n urlOf(root?.config) ??\n deepFindUrl(root, (u) => /config[^/]*\\.json(\\?|$)/i.test(u));\n return { loraUrl, configUrl };\n}\n\n// ── In-memory ZIP (store via DEFLATE, node:zlib — zero new deps) ──────────────\n\nfunction fileNameFromUrl(url: string, i: number): string {\n const base = url.split(\"?\")[0]!.split(\"/\").pop() || \"\";\n return /\\.[a-z0-9]+$/i.test(base) ? base : `image_${i}.png`;\n}\n\n/** Build a spec-compliant ZIP (DEFLATE method) from named byte entries. */\nfunction buildZip(files: { name: string; data: Uint8Array }[]): Uint8Array {\n const parts: Buffer[] = [];\n const central: Buffer[] = [];\n let offset = 0;\n for (const f of files) {\n const nameBuf = Buffer.from(f.name, \"utf8\");\n const data = Buffer.from(f.data);\n const comp = deflateRawSync(data);\n const crc = crc32(data) >>> 0;\n\n const lfh = Buffer.alloc(30);\n lfh.writeUInt32LE(0x04034b50, 0); // local file header signature\n lfh.writeUInt16LE(20, 4); // version needed\n lfh.writeUInt16LE(0, 6); // flags\n lfh.writeUInt16LE(8, 8); // method = deflate\n lfh.writeUInt16LE(0, 10); // mod time\n lfh.writeUInt16LE(0x21, 12); // mod date (1980-01-01)\n lfh.writeUInt32LE(crc, 14);\n lfh.writeUInt32LE(comp.length, 18); // compressed size\n lfh.writeUInt32LE(data.length, 22); // uncompressed size\n lfh.writeUInt16LE(nameBuf.length, 26);\n lfh.writeUInt16LE(0, 28); // extra len\n parts.push(lfh, nameBuf, comp);\n\n const cdh = Buffer.alloc(46);\n cdh.writeUInt32LE(0x02014b50, 0); // central directory header signature\n cdh.writeUInt16LE(20, 4); // version made by\n cdh.writeUInt16LE(20, 6); // version needed\n cdh.writeUInt16LE(0, 8); // flags\n cdh.writeUInt16LE(8, 10); // method\n cdh.writeUInt16LE(0, 12); // mod time\n cdh.writeUInt16LE(0x21, 14); // mod date\n cdh.writeUInt32LE(crc, 16);\n cdh.writeUInt32LE(comp.length, 20);\n cdh.writeUInt32LE(data.length, 24);\n cdh.writeUInt16LE(nameBuf.length, 28);\n cdh.writeUInt16LE(0, 30); // extra len\n cdh.writeUInt16LE(0, 32); // comment len\n cdh.writeUInt16LE(0, 34); // disk number start\n cdh.writeUInt16LE(0, 36); // internal attrs\n cdh.writeUInt32LE(0, 38); // external attrs\n cdh.writeUInt32LE(offset, 42); // local header offset\n central.push(cdh, nameBuf);\n\n offset += lfh.length + nameBuf.length + comp.length;\n }\n const cd = Buffer.concat(central);\n const eocd = Buffer.alloc(22);\n eocd.writeUInt32LE(0x06054b50, 0); // end of central directory signature\n eocd.writeUInt16LE(0, 4); // disk number\n eocd.writeUInt16LE(0, 6); // cd start disk\n eocd.writeUInt16LE(files.length, 8); // entries this disk\n eocd.writeUInt16LE(files.length, 10); // total entries\n eocd.writeUInt32LE(cd.length, 12); // cd size\n eocd.writeUInt32LE(offset, 16); // cd offset\n eocd.writeUInt16LE(0, 20); // comment len\n return Buffer.concat([...parts, cd, eocd]);\n}\n","// Black Forest Labs (FLUX) adapter — F023 / F023.5. EU-RESIDENT image generation.\n//\n// GDPR CRUX (non-negotiable): this adapter hard-pins https://api.eu.bfl.ai — the\n// dedicated EU endpoint — NEVER the global api.bfl.ai (which auto-failovers to the\n// US and could route a face out of the EEA). A face = biometric personal data, so\n// EU residency is what makes this compliant; \"German company\" alone is not enough.\n// The default base is asserted in bfl.test.ts.\n//\n// Two EU-resident likeness modes (route by what ai.image is given):\n// • referenceImages (F023.5) → FLUX 2 multi-reference: 1–8 photos in the generate\n// call, NO training step. Default model flux-2-max ($0.25/img); pass\n// override:{ model:\"flux-2-pro\" } for ~half price ($0.12/img). Bytes are\n// base64-inlined into the EU call (no cross-region fetch); URLs pass through.\n// • finetune (F023) → flux-pro-1.1-ultra-finetuned, a subject trained ONCE in the\n// BFL dashboard (finetune-CREATE was retired from the public API — live-verified\n// 2026-06-16: POST /v1/finetune 404s on every region; legacy eu1/us1 hosts dead).\n// See the dashboard SOP in docs/features/F023-bfl-eu-portrait-lora.md.\n//\n// Auth header `x-key`. Request→poll: POST returns {id, polling_url, cost}; we poll the\n// EU get_result by id (deliberately NOT the returned polling_url) so a response carrying\n// a face never transits a non-EU host. BFL returns the real `cost` in credits\n// (1 credit = $0.01, official) → usage.costUsd is exact, not estimated.\nimport { freshUsage } from \"../cost/usage.js\";\nimport type { Region } from \"../cost/region.js\";\nimport type { ProviderAdapter, ImageRequest, ImageResult } from \"../types.js\";\n\nconst EU_BASE = \"https://api.eu.bfl.ai\";\n/** BFL bills in credits; 1 credit = $0.01 USD (official, bfl.ai/pricing). */\nconst BFL_CREDIT_USD = 0.01;\n\ninterface BflSubmitResponse {\n id?: string;\n polling_url?: string;\n /** BFL's billed cost for this request, in credits. */\n cost?: number;\n}\ninterface BflResultResponse {\n id?: string;\n /** \"Ready\" | \"Pending\" | \"Error\" | \"Request Moderated\" | \"Content Moderated\" | \"Task not found\" */\n status?: string;\n result?: { sample?: string } | null;\n progress?: number | null;\n}\n\nexport interface BflAdapterConfig {\n apiKey?: string;\n /** EU-resident base. Do NOT point this at api.bfl.ai (global, US-failover) — see header. */\n baseUrl?: string;\n pollIntervalMs?: number;\n timeoutMs?: number;\n fetch?: typeof fetch;\n /** Override the per-image USD price (else the built-in finetuned-inference estimate). */\n pricePerImage?: number;\n}\n\n// flux-pro-1.1-ultra-finetuned per-image USD. BFL bills per generated image; verify\n// against bfl.ai/pricing before relying on this (override via config.pricePerImage).\nconst BFL_IMAGE_PRICE = 0.06;\n\nconst sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));\n\nfunction gcd(a: number, b: number): number {\n return b === 0 ? a : gcd(b, a % b);\n}\n\n/** Remaining BFL account credits + their USD value (1 credit = $0.01). */\nexport interface BflCredits {\n credits: number;\n usd: number;\n}\n\n/** F023.6 — check the BFL account's remaining credit balance (`GET /v1/credits`).\n * Account-level (region-independent); EU-pinned by default for consistency. Use it\n * for budget-gating before a generate call: `if ((await bflCredits()).usd < 1) …`. */\nexport async function bflCredits(\n opts: { apiKey?: string; baseUrl?: string; fetch?: typeof fetch } = {},\n): Promise<BflCredits> {\n const apiKey = opts.apiKey ?? process.env.BFL_API_KEY;\n if (!apiKey) throw new Error(\"bflCredits: BFL_API_KEY not set\");\n const doFetch = opts.fetch ?? fetch;\n const res = await doFetch(`${opts.baseUrl ?? EU_BASE}/v1/credits`, { headers: { \"x-key\": apiKey } });\n if (!res.ok) {\n throw new Error(`bflCredits ${res.status}: ${(await res.text().catch(() => \"\")).slice(0, 200)}`);\n }\n const data = (await res.json()) as { credits?: number };\n const credits = typeof data.credits === \"number\" ? data.credits : 0;\n return { credits, usd: credits * BFL_CREDIT_USD };\n}\n\n/** Residency of a BFL base URL (F042). Only the dedicated EU host is an EU claim;\n * the global api.bfl.ai auto-failovers to the US, so where a call landed is not\n * something we can observe from here — \"unknown\" is the truthful answer, and it is\n * deliberately not \"us\" (a failover MAY have stayed in the EU; we just cannot say). */\nfunction bflRegion(base: string): Region {\n try {\n return new URL(base).host.toLowerCase() === \"api.eu.bfl.ai\" ? \"eu\" : \"unknown\";\n } catch {\n return \"unknown\";\n }\n}\n\nexport function bflAdapter(config: BflAdapterConfig = {}): ProviderAdapter {\n const doFetch = config.fetch ?? fetch;\n const base = config.baseUrl ?? EU_BASE;\n const pollIntervalMs = config.pollIntervalMs ?? 1500;\n const timeoutMs = config.timeoutMs ?? 120000;\n\n const resolveKey = () => config.apiKey ?? process.env.BFL_API_KEY;\n\n async function image(req: ImageRequest): Promise<ImageResult> {\n const apiKey = resolveKey();\n if (!apiKey) throw new Error(\"bfl adapter: BFL_API_KEY not set\");\n const headers = { \"content-type\": \"application/json\", \"x-key\": apiKey };\n\n const body: Record<string, unknown> = { prompt: req.prompt };\n if (req.referenceImages?.length) {\n // F023.5 — FLUX 2 multi-reference: input_image, input_image_2 … input_image_8.\n req.referenceImages.forEach((img, i) => {\n body[i === 0 ? \"input_image\" : `input_image_${i + 1}`] = toBflImage(img);\n });\n if (req.width) body.width = req.width;\n if (req.height) body.height = req.height;\n if (req.seed !== undefined) body.seed = req.seed;\n body.output_format = req.outputFormat ?? \"jpeg\";\n body.safety_tolerance = req.safetyTolerance ?? 2;\n } else if (req.finetune) {\n // F023 — finetuned subject (trained once in the BFL dashboard).\n body.finetune_id = req.finetune;\n if (req.finetuneStrength !== undefined) body.finetune_strength = req.finetuneStrength;\n // flux-pro-1.1-ultra takes aspect_ratio, not width/height — derive it when both given.\n if (req.width && req.height) {\n const g = gcd(req.width, req.height) || 1;\n body.aspect_ratio = `${req.width / g}:${req.height / g}`;\n }\n } else {\n throw new Error(\n \"bfl adapter: requires referenceImages (FLUX 2 multi-reference) or a finetune id. \" +\n \"ai.image({ referenceImages: [...] }) needs no training; ai.image({ finetune }) uses a subject \" +\n \"trained once in the BFL dashboard (dashboard.bfl.ai — finetune-create is not in the public API).\",\n );\n }\n\n const submitRes = await doFetch(`${base}/v1/${req.spec.model}`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n });\n if (!submitRes.ok) {\n throw new Error(`bfl ${submitRes.status}: ${(await submitRes.text().catch(() => \"\")).slice(0, 200)}`);\n }\n const submit = (await submitRes.json()) as BflSubmitResponse;\n if (!submit.id) throw new Error(\"bfl: no task id in submit response\");\n\n const sample = await poll(submit.id, apiKey);\n\n const usage = freshUsage({\n provider: \"bfl\",\n model: req.spec.model,\n region: bflRegion(base),\n transport: \"http\",\n capability: \"image\",\n inputTokens: 0,\n outputTokens: 0,\n });\n // BFL returns the real billed cost (credits) — use it; fall back to the estimate.\n usage.costUsd =\n typeof submit.cost === \"number\"\n ? submit.cost * BFL_CREDIT_USD\n : (config.pricePerImage ?? BFL_IMAGE_PRICE);\n return { url: sample, usage };\n }\n\n /** A URL passes through; raw bytes / a data: URI become a plain base64 string\n * (BFL's input_image wants base64, not a data: URI — verified live). */\n function toBflImage(img: string | Uint8Array): string {\n if (typeof img !== \"string\") return Buffer.from(img).toString(\"base64\");\n if (/^https?:\\/\\//i.test(img)) return img;\n const comma = img.startsWith(\"data:\") ? img.indexOf(\",\") : -1;\n return comma >= 0 ? img.slice(comma + 1) : img;\n }\n\n /** Poll the EU get_result by id until Ready (or a terminal/moderated status). */\n async function poll(id: string, apiKey: string): Promise<string> {\n const headers = { \"x-key\": apiKey };\n const deadline = Date.now() + timeoutMs;\n for (;;) {\n const res = await doFetch(`${base}/v1/get_result?id=${encodeURIComponent(id)}`, { headers });\n if (!res.ok) throw new Error(`bfl get_result ${res.status}`);\n const data = (await res.json()) as BflResultResponse;\n const status = data.status ?? \"\";\n if (status === \"Ready\") {\n const sample = data.result?.sample;\n if (!sample) throw new Error(\"bfl: status Ready but no result.sample url\");\n return sample;\n }\n if (status === \"Error\" || status === \"Failed\" || status === \"Task not found\") {\n throw new Error(`bfl: generation ${status}`);\n }\n if (status.includes(\"Moderated\")) {\n throw new Error(`bfl: ${status} — prompt or output flagged by BFL safety`);\n }\n if (Date.now() >= deadline) throw new Error(`bfl: timed out after ${timeoutMs}ms`);\n await sleep(pollIntervalMs);\n }\n }\n\n return { name: \"bfl\", image };\n}\n","// Default provider registry — the live adapters wired when AiConfig.providers is\n// absent. A bare createAI() makes real calls (keys from env). fal stays a stub\n// until F5.3 ships the real fal.ai image adapter.\nimport { anthropicAdapter } from \"./anthropic.js\";\nimport { openaiAdapter } from \"./openai.js\";\nimport { geminiAdapter } from \"./gemini.js\";\nimport { deepinfraAdapter } from \"./deepinfra.js\";\nimport { openrouterAdapter } from \"./openrouter.js\";\nimport { requestyAdapter } from \"./requesty.js\";\nimport { deepseekAdapter } from \"./deepseek.js\";\nimport { mistralAdapter } from \"./mistral.js\";\nimport { elevenlabsAdapter } from \"./elevenlabs.js\";\nimport { azureAdapter } from \"./azure.js\";\nimport { vertexAdapter } from \"./vertex.js\";\nimport { deeplAdapter } from \"./deepl.js\";\nimport { falAdapter } from \"./fal.js\";\nimport { bflAdapter } from \"./bfl.js\";\nimport type { ProviderAdapter } from \"../types.js\";\n\nexport const defaultProviders: Record<string, ProviderAdapter> = {\n anthropic: anthropicAdapter(),\n openai: openaiAdapter(),\n gemini: geminiAdapter(),\n deepinfra: deepinfraAdapter(),\n openrouter: openrouterAdapter(),\n requesty: requestyAdapter(),\n deepseek: deepseekAdapter(),\n mistral: mistralAdapter(),\n elevenlabs: elevenlabsAdapter(),\n azure: azureAdapter(),\n vertex: vertexAdapter(),\n deepl: deeplAdapter(),\n fal: falAdapter(),\n bfl: bflAdapter(),\n};\n","// Pre-flight budget guard. check() runs BEFORE the transport fires, so a call\n// that would breach a ceiling never reaches the provider. record() folds the\n// actual cost into the running total after a successful call.\nimport type { BudgetConfig, BudgetStore } from \"../types.js\";\n\n/** Default rolling-total store: in-memory, per BudgetGuard instance. */\nclass InMemoryBudgetStore implements BudgetStore {\n private spentUsd = 0;\n getSpent(): number {\n return this.spentUsd;\n }\n addSpent(usd: number): void {\n this.spentUsd += usd;\n }\n}\n\nexport class BudgetExceededError extends Error {\n readonly kind: \"per-call\" | \"rolling\";\n readonly limit: number;\n readonly spent: number;\n readonly requested: number;\n\n constructor(\n kind: \"per-call\" | \"rolling\",\n limit: number,\n spent: number,\n requested: number,\n ) {\n super(\n `Budget exceeded (${kind}): this call's estimated $${requested.toFixed(6)} ` +\n (kind === \"rolling\"\n ? `+ $${spent.toFixed(6)} already spent exceeds the $${limit.toFixed(6)} rolling ceiling`\n : `exceeds the $${limit.toFixed(6)} per-call ceiling`),\n );\n this.name = \"BudgetExceededError\";\n this.kind = kind;\n this.limit = limit;\n this.spent = spent;\n this.requested = requested;\n }\n}\n\nexport class BudgetGuard {\n private readonly store: BudgetStore;\n\n constructor(private readonly config: BudgetConfig) {\n this.store = config.store ?? new InMemoryBudgetStore();\n }\n\n /** Throws BudgetExceededError if `requested` would breach the per-call ceiling\n * or push the rolling total past its ceiling. Call before firing the request.\n * Async because a persistent store may be I/O-backed. */\n async check(requested: number): Promise<void> {\n const { perCallUsd, rollingUsd } = this.config;\n if (perCallUsd !== undefined && requested > perCallUsd) {\n throw new BudgetExceededError(\"per-call\", perCallUsd, await this.store.getSpent(), requested);\n }\n if (rollingUsd !== undefined) {\n const spent = await this.store.getSpent();\n if (spent + requested > rollingUsd) {\n throw new BudgetExceededError(\"rolling\", rollingUsd, spent, requested);\n }\n }\n }\n\n /** Add an actual cost to the running total (after a successful call). */\n async record(actual: number): Promise<void> {\n await this.store.addSpent(actual);\n }\n\n async totalSpent(): Promise<number> {\n return this.store.getSpent();\n }\n}\n","// Vision capability helper. The client owns orchestration (tier/budget/sink);\n// this module owns the vision-specific message shaping so it's unit-testable and\n// the capabilities/ layout stays meaningful. Default tier: \"vision\".\nimport type { VisionInput } from \"../schema/inputs.js\";\nimport type { Message, Tier } from \"../types.js\";\n\nexport const VISION_DEFAULT_TIER: Tier = \"vision\";\n\n/** Build the multimodal message(s) (optional system + user text + image) for a\n * vision call. A `system` instruction drives instruction-following far better\n * than packing rules into `prompt` for instruction-heavy tasks (e.g. a JSON critic). */\nexport function buildVisionMessages(input: VisionInput): Message[] {\n const messages: Message[] = [];\n if (input.system) messages.push({ role: \"system\", content: input.system });\n messages.push({\n role: \"user\",\n content: [\n { type: \"text\", text: input.prompt },\n { type: \"image\", image: input.image, mimeType: input.mimeType },\n ],\n });\n return messages;\n}\n","// Video Vision capability (F019). Like vision, but the multimodal part is a\n// video the model watches natively (Gemini, OpenRouter video models). The client\n// owns orchestration; this module owns the message shaping. Default tier: \"video\".\nimport type { VideoInput } from \"../schema/inputs.js\";\nimport type { Message, Tier } from \"../types.js\";\n\nexport const VIDEO_DEFAULT_TIER: Tier = \"video\";\n\n/** Build the message(s) (optional system + video + prompt) for a video-analysis call. */\nexport function buildVideoMessages(input: VideoInput): Message[] {\n const messages: Message[] = [];\n if (input.system) messages.push({ role: \"system\", content: input.system });\n messages.push({\n role: \"user\",\n content: [\n { type: \"video\", video: input.video, mimeType: input.mimeType },\n { type: \"text\", text: input.prompt },\n ],\n });\n return messages;\n}\n","// Translate capability helper. A thin prompt-contract on top of chat — the\n// client orchestrates (tier/budget/sink); this builds the messages. Default\n// tier: \"fast\". Returns the translation only, no preamble.\nimport type { TranslateInput } from \"../schema/inputs.js\";\nimport type { Message, Tier } from \"../types.js\";\n\nexport const TRANSLATE_DEFAULT_TIER: Tier = \"fast\";\n\nconst TRANSLATE_SYSTEM =\n \"You are a translation engine. Translate the user's text only. \" +\n \"Return the translation and nothing else — no preamble, no quotes.\";\n\nexport function buildTranslateMessages(input: TranslateInput): Message[] {\n const fromClause = input.from ? ` from ${input.from}` : \"\";\n return [\n { role: \"system\", content: TRANSLATE_SYSTEM },\n { role: \"user\", content: `Translate${fromClause} to ${input.to}:\\n\\n${input.text}` },\n ];\n}\n","// Embedding capability marker. The client orchestrates; this names the default\n// tier (OpenAI text-embedding-3-small via the embedding tier).\nimport type { Tier } from \"../types.js\";\n\nexport const EMBEDDING_DEFAULT_TIER: Tier = \"embedding\";\n","// Transcribe capability. No tier in the tier map (provider-specific, like image)\n// — defaults to OpenAI Whisper, overridable per call. Synergy: cctalk Danish\n// dictation. costUsd is 0 for v1 (Whisper is priced per minute, not per token).\nimport type { TierSpec } from \"../types.js\";\n\nexport const DEFAULT_TRANSCRIBE_SPEC: TierSpec = {\n provider: \"openai\",\n model: \"whisper-1\",\n transport: \"http\",\n};\n\n/** Fetch a URL to raw bytes; pass through bytes unchanged. */\nexport async function resolveAudio(\n audio: string | Uint8Array,\n fetchImpl: typeof fetch = fetch,\n): Promise<Uint8Array> {\n if (typeof audio !== \"string\") return audio;\n if (!/^https?:\\/\\//.test(audio)) {\n throw new Error(\"transcribe: string audio must be an http(s) URL (or pass raw bytes)\");\n }\n const res = await fetchImpl(audio);\n if (!res.ok) throw new Error(`transcribe: failed to fetch audio (${res.status})`);\n return new Uint8Array(await res.arrayBuffer());\n}\n","// Prompt-contract capabilities (F5.5). Each is a fixed system prompt over\n// chat/vision; extract adds Zod output validation with one retry. Exposed as\n// ai.contracts.* — built from the client so budget/cost tracking apply.\nimport type { AiClient, VisionInput } from \"../../schema/inputs.js\";\nimport type {\n Contracts,\n MockupInput,\n MockupResult,\n DesignInput,\n DesignResult,\n ExtractInput,\n ExtractResult,\n ClassifyInput,\n ClassifyResult,\n RerankInput,\n RerankResult,\n} from \"./types.js\";\n\n/** Pull the first JSON value out of a model reply (tolerates ```json fences + prose). */\nexport function parseJsonLoose(text: string): unknown {\n const fenced = text.replace(/```(?:json)?/gi, \"\").trim();\n const start = fenced.search(/[[{]/);\n if (start === -1) throw new Error(\"no JSON found in model output\");\n const slice = fenced.slice(start);\n // Walk back from the end to the matching closing bracket.\n const lastObj = slice.lastIndexOf(\"}\");\n const lastArr = slice.lastIndexOf(\"]\");\n const end = Math.max(lastObj, lastArr);\n return JSON.parse(slice.slice(0, end + 1));\n}\n\ntype ChatVision = Pick<AiClient, \"chat\" | \"vision\">;\n\nexport function makeContracts(client: ChatVision): Contracts {\n return {\n async mockup(input: MockupInput): Promise<MockupResult> {\n const constraints = input.constraints ? `\\n\\nConstraints:\\n${input.constraints}` : \"\";\n const res = await client.chat({\n system:\n \"You are a UI mockup generator. Output a single self-contained HTML document \" +\n \"using Tailwind CSS utility classes. Return ONLY the HTML — no markdown, no prose.\",\n prompt: `Build a UI mockup for:\\n${input.description}${constraints}`,\n tier: input.tier ?? \"smart\",\n purpose: input.purpose ?? \"contract:mockup\",\n });\n return { html: res.text, usage: res.usage };\n },\n\n async design(input: DesignInput): Promise<DesignResult> {\n const res = await client.vision({\n image: input.screenshot as VisionInput[\"image\"],\n prompt:\n \"You are a design-iteration engine. Given this screenshot, apply the instructions \" +\n `and return a single self-contained HTML document (Tailwind), ONLY the HTML.\\n\\n` +\n `Instructions:\\n${input.instructions}`,\n tier: input.tier ?? \"powerful\",\n purpose: input.purpose ?? \"contract:design\",\n });\n return { html: res.text, usage: res.usage };\n },\n\n async extract<T>(input: ExtractInput<T>): Promise<ExtractResult<T>> {\n const base =\n \"You are a structured-data extractor. Extract the requested data from the text and \" +\n \"return ONLY valid JSON — no markdown, no prose.\" +\n (input.instructions ? `\\n\\n${input.instructions}` : \"\");\n const run = async (reinforce: boolean) => {\n const res = await client.chat({\n system: reinforce ? `${base}\\n\\nYour previous output was not valid JSON. Return ONLY parseable JSON.` : base,\n prompt: input.text,\n tier: input.tier ?? \"smart\",\n purpose: input.purpose ?? \"contract:extract\",\n });\n return res;\n };\n let res = await run(false);\n try {\n return { data: input.schema.parse(parseJsonLoose(res.text)), usage: res.usage };\n } catch {\n // one retry with reinforcement\n res = await run(true);\n return { data: input.schema.parse(parseJsonLoose(res.text)), usage: res.usage };\n }\n },\n\n async classify(input: ClassifyInput): Promise<ClassifyResult> {\n const res = await client.chat({\n system:\n \"You are a zero-shot classifier. Choose exactly one label from the provided list. \" +\n 'Return ONLY JSON: {\"label\": \"<one of the labels>\", \"confidence\": <0..1>}.',\n prompt: `Labels: ${JSON.stringify(input.labels)}\\n\\nText:\\n${input.text}`,\n tier: input.tier ?? \"cheap\",\n purpose: input.purpose ?? \"contract:classify\",\n });\n const parsed = parseJsonLoose(res.text) as { label?: string; confidence?: number };\n const label = input.labels.includes(parsed.label ?? \"\") ? parsed.label! : (input.labels[0] ?? \"\");\n const confidence = typeof parsed.confidence === \"number\" ? parsed.confidence : 0;\n return { label, confidence, usage: res.usage };\n },\n\n async rerank(input: RerankInput): Promise<RerankResult> {\n const res = await client.chat({\n system:\n \"You are a relevance reranker. Score each item 0..1 for relevance to the query and \" +\n 'return ONLY JSON: [{\"item\": \"<verbatim item>\", \"score\": <0..1>}], ordered by score desc.',\n prompt: `Query: ${input.query}\\n\\nItems:\\n${JSON.stringify(input.items)}`,\n tier: input.tier ?? \"fast\",\n purpose: input.purpose ?? \"contract:rerank\",\n });\n const raw = parseJsonLoose(res.text) as { item?: string; score?: number }[];\n const ranked = (Array.isArray(raw) ? raw : [])\n .map((r) => ({ item: String(r.item ?? \"\"), score: typeof r.score === \"number\" ? r.score : 0 }))\n .sort((a, b) => b.score - a.score);\n return { ranked, usage: res.usage };\n },\n };\n}\n","// F037 — the voice registry. DERIVED from the curated rosters, never a second copy\n// of them: ELEVENLABS_DANISH_VOICES and AZURE_DANISH_VOICE_LIST stay the single\n// source for which voices we bless, and this module only adds the status layer on\n// top. A copied roster is a roster that drifts.\nimport { ELEVENLABS_DANISH_VOICES } from \"../providers/elevenlabs.js\";\nimport { AZURE_DANISH_VOICE_LIST, localeOf } from \"../providers/azure.js\";\nimport type { VoiceInfo, VoiceProvider } from \"./types.js\";\n\n/** When each provider's roster was last confirmed against the provider itself.\n * These are MEASUREMENTS with dates, not a claim of current truth — that is the\n * whole point of surfacing checkedAt. */\nconst CHECKED_AT: Record<VoiceProvider, string> = {\n // All 5 curated ids confirmed by SYNTHESIS — POST /v1/text-to-speech/{id} returned\n // 200 with distinct audio per voice (5 distinct sha256), and a fabricated id\n // returned 404, so a 200 means something.\n //\n // NB: GET /v1/voices/{id} is NOT a liveness test and must not be used as one. It\n // answers \"is this voice saved in our account\", and returns voice_not_found for a\n // public/shared voice that synthesizes perfectly well. Using it cost us a false\n // retirement (see the note on `mads` below) — the only honest liveness check for\n // ElevenLabs is a real synthesis call, which is exactly why v1 does no live check.\n elevenlabs: \"2026-08-11\",\n // F026 (6ca38c4) verified the 6 curated names against Azure's voices/list. Not\n // re-probed since: this machine has no Azure Speech key, and inventing a fresher\n // date than the last real check is exactly the lie checkedAt exists to prevent.\n azure: \"2026-06-23\",\n};\n\n/** Voices we know are GONE — keyed by curated name. A row here is the third state\n * the old two-state resolveVoice could not express. Keep the entry: deleting it\n * would send the friendly name to the provider as a raw voice id.\n *\n * Currently EMPTY. Every curated voice was synthesis-verified on 2026-08-11. This\n * map existing while empty is the point — it is the mechanism that lets us act on\n * a retirement the day one happens, instead of discovering we cannot express it. */\nconst RETIRED_DEFAULT: Record<string, string> = {};\n\nlet RETIRED: Record<string, string> = RETIRED_DEFAULT;\n\n/** Genders as published by the provider's voices endpoint. Absent = we have no\n * source; never inferred from a first name. `mads` is absent because it is not\n * saved to our account, and that endpoint only describes account voices — the\n * voice itself works fine. */\nconst ELEVENLABS_GENDER: Record<string, \"female\" | \"male\"> = {\n soren: \"male\",\n jesper: \"male\",\n noam: \"male\",\n camilla: \"female\",\n};\n\n/** Caveats worth showing in a picker that are NOT unavailability. */\nconst NOTES: Record<string, string> = {\n mads: \"usable, but not saved to the ElevenLabs account, so the voices endpoint publishes no metadata for it (verified by synthesis 2026-08-11)\",\n};\n\nfunction build(): VoiceInfo[] {\n const rows: VoiceInfo[] = [];\n\n for (const [name, id] of Object.entries(ELEVENLABS_DANISH_VOICES)) {\n const retired = RETIRED[name];\n rows.push({\n id,\n name,\n provider: \"elevenlabs\",\n // The curated ElevenLabs roster IS the Danish one (see the constant's name\n // + F020); the multilingual model speaks it as da-DK.\n locale: \"da-DK\",\n gender: ELEVENLABS_GENDER[name],\n available: retired === undefined,\n status: retired === undefined ? \"available\" : \"retired\",\n note: retired ?? NOTES[name],\n checkedAt: CHECKED_AT.elevenlabs,\n });\n }\n\n for (const v of AZURE_DANISH_VOICE_LIST) {\n const retired = RETIRED[v.name];\n rows.push({\n id: v.voiceId,\n name: v.name,\n provider: \"azure\",\n locale: localeOf(v.voiceId),\n gender: v.gender,\n available: retired === undefined,\n status: retired === undefined ? \"available\" : \"retired\",\n note: retired ?? NOTES[v.name],\n checkedAt: CHECKED_AT.azure,\n });\n }\n\n return rows;\n}\n\nlet ROWS: VoiceInfo[] = build();\n\n/** All curated voices, current status applied. Optionally scoped to one provider. */\nexport function allVoices(provider?: VoiceProvider): VoiceInfo[] {\n return provider ? ROWS.filter((v) => v.provider === provider) : [...ROWS];\n}\n\n/** Look up by curated friendly name OR by full provider voice id — a caller may\n * legitimately pass either. Anything else is untracked (undefined = fail-open). */\nexport function getVoice(nameOrId: string): VoiceInfo | undefined {\n return ROWS.find((v) => v.name === nameOrId || v.id === nameOrId);\n}\n\n/** TEST-ONLY. Mark curated voices retired so the third state can be exercised while\n * no real retirement exists. Deliberately not exported from the package entry —\n * a consumer must never be able to mark our roster dead. Pair with\n * resetVoiceRegistry() so a test cannot leak state into the next one. */\nexport function setRetiredVoicesForTests(map: Record<string, string>): void {\n RETIRED = map;\n ROWS = build();\n}\n\n/** TEST-ONLY. Restore the shipped registry. */\nexport function resetVoiceRegistry(): void {\n RETIRED = RETIRED_DEFAULT;\n ROWS = build();\n}\n","// F037 — voice availability. Mirrors src/availability/ (models) for VOICES, and\n// exists for a reason the model side does not have.\n//\n// `resolveVoice()` has only TWO states: a curated name maps to an id, or the input\n// is passed through verbatim as a raw provider voice id. There is no way to say\n// \"we know this voice, and it is gone\". So when a provider retires a voice, the\n// obvious fix — delete it from the curated map — makes the call fail MORE\n// confusingly: the literal friendly name (\"mads\") gets POSTed as a voice id.\n//\n// That missing third state is what this module adds. It is not primarily a\n// drift-detector; it is the only way to act on a retirement at all.\n\nexport type VoiceStatus = \"available\" | \"retired\" | \"unknown\";\n\nexport type VoiceProvider = \"elevenlabs\" | \"azure\";\n\n/** One row of the shared voice read — what a UI voice-picker renders. */\nexport interface VoiceInfo {\n /** Full provider voice id, e.g. \"da-DK-ChristelNeural\" / \"4RklGmuxoAskAbGXplXN\". */\n id: string;\n /** Curated friendly name a caller passes as `voice`, e.g. \"christel\". */\n name: string;\n provider: VoiceProvider;\n /** BCP-47 locale of the voice itself, e.g. \"da-DK\". NB: an Azure multilingual\n * voice speaking Danish reports its own locale (\"de-DE\" for Seraphina) — that\n * is what the adapter actually sends as xml:lang. */\n locale: string;\n /** Only where the provider publishes it — absent is \"we do not know\", never a\n * guess from the first name. */\n gender?: \"female\" | \"male\";\n available: boolean;\n status: VoiceStatus;\n /** Why it is unavailable, or any caveat worth showing in a picker. */\n note?: string;\n /** ISO date this row's status was last confirmed AGAINST THE PROVIDER. Exposed\n * on purpose (the F034.1 lesson): a registry that cannot be seen to go stale\n * is worse than one that can, because nobody knows when to re-check it. */\n checkedAt: string;\n}\n\n/** Result of checkVoice — deliberately the same shape as ResolveResult (F022) so\n * a consumer learns one idiom for models and voices. */\nexport interface VoiceResolveResult {\n /** True when the requested voice itself is usable. */\n ok: boolean;\n /** The id to actually send: the requested voice's id when ok, else the\n * fallback's. When there is no usable fallback this is the dead id and `ok`\n * is false — mirroring resolveModel, the caller must read `ok`. */\n voiceId: string;\n /** What the caller asked for, verbatim. */\n requested: string;\n provider?: VoiceProvider;\n /** True when `voiceId` differs from what was requested because we fell back. */\n fellBack: boolean;\n status: VoiceStatus;\n /** Why it degraded / why it is unavailable. */\n reason?: string;\n}\n\n/** Thrown when the requested voice is retired and no usable fallback exists.\n * Callers flag on `.code === \"voice_unavailable\"`. */\nexport class VoiceUnavailableError extends Error {\n readonly code = \"voice_unavailable\";\n readonly requested: string;\n readonly provider?: VoiceProvider;\n readonly note?: string;\n constructor(requested: string, note?: string, provider?: VoiceProvider) {\n super(`voice \"${requested}\" is unavailable${note ? ` (${note})` : \"\"}`);\n this.name = \"VoiceUnavailableError\";\n this.requested = requested;\n this.note = note;\n this.provider = provider;\n }\n}\n","// F037 — the synchronous, zero-I/O voice resolve + roster read, mirroring\n// src/availability/resolve.ts (F022) so a consumer learns ONE idiom for models and\n// voices. Never awaits, never touches the network: this sits on the TTS call path.\nimport { allVoices, getVoice } from \"./registry.js\";\nimport { VoiceUnavailableError } from \"./types.js\";\nimport type { VoiceInfo, VoiceProvider, VoiceResolveResult } from \"./types.js\";\n\nexport interface CheckVoiceOptions {\n /** One name/id or an ordered chain to try when `requested` is retired. */\n fallback?: string | string[];\n /** Throw VoiceUnavailableError instead of returning ok:false when nothing in the\n * chain is usable. For callers that want to fail loudly rather than degrade. */\n throwIfUnavailable?: boolean;\n}\n\n/**\n * The shared voice read — a UI picker greys out `available:false` rows and can show\n * `checkedAt` so a stale registry is visible rather than silently trusted.\n *\n * NB: distinct from `elevenlabsAdapter().listVoices()`, which is an async call to\n * ElevenLabs' live API. This one is synchronous, cross-provider, and reads only the\n * curated registry.\n */\nexport function listVoices(opts: { provider?: VoiceProvider } = {}): VoiceInfo[] {\n return allVoices(opts.provider);\n}\n\n/** Usable? Untracked voices are fail-open — we never block a raw provider voice id\n * just because it is not on our curated roster. */\nfunction usable(nameOrId: string): boolean {\n const v = getVoice(nameOrId);\n return v ? v.available : true;\n}\n\n/** The id to actually send for a name/id: the registry's full id when we know it,\n * otherwise the input verbatim (a raw provider voice id). */\nfunction idFor(nameOrId: string): string {\n return getVoice(nameOrId)?.id ?? nameOrId;\n}\n\n/**\n * Resolve a requested voice (curated name or raw provider id) to one that is\n * actually usable. Synchronous + offline by contract.\n *\n * - Available → pass through ({ ok:true, fellBack:false }).\n * - Retired + a usable fallback → swap ({ ok:false, fellBack:true }).\n * - Retired + no usable fallback → throw (throwIfUnavailable) or return ok:false.\n * - Untracked id → treated usable ({ status:\"unknown\" }), passed through verbatim.\n */\nexport function checkVoice(requested: string, opts: CheckVoiceOptions = {}): VoiceResolveResult {\n const entry = getVoice(requested);\n const provider = entry?.provider;\n\n if (usable(requested)) {\n return {\n ok: true,\n voiceId: idFor(requested),\n requested,\n provider,\n fellBack: false,\n status: entry?.status ?? \"unknown\",\n };\n }\n\n // Requested is retired — walk the fallback chain for the first usable one.\n const chain = opts.fallback === undefined ? [] : Array.isArray(opts.fallback) ? opts.fallback : [opts.fallback];\n for (const fb of chain) {\n if (usable(fb)) {\n return {\n ok: false,\n voiceId: idFor(fb),\n requested,\n provider: getVoice(fb)?.provider ?? provider,\n fellBack: true,\n status: entry?.status ?? \"retired\",\n reason: entry?.note ?? `${requested} is unavailable`,\n };\n }\n }\n\n if (opts.throwIfUnavailable) {\n throw new VoiceUnavailableError(requested, entry?.note, provider);\n }\n return {\n ok: false,\n voiceId: idFor(requested),\n requested,\n provider,\n fellBack: false,\n status: entry?.status ?? \"retired\",\n reason: entry?.note ?? `${requested} is unavailable`,\n };\n}\n","// Zod is the single source of truth for the public input shapes. The TypeScript\n// types are derived via z.infer — no hand-written interface duplicates them.\n// The client .parse()s every input at the boundary, so invalid input throws a\n// ZodError before any provider work happens.\nimport { z } from \"zod\";\nimport type {\n ProviderAdapter,\n CostSink,\n TranslateResult,\n ChatResult,\n ChatStreamEvent,\n ImageResult,\n AnimateResult,\n TrainStyleResult,\n EmbeddingResult,\n TranscribeResult,\n OcrResult,\n ModerationResult,\n PodcastResult,\n BatchRequestItem,\n BatchJob,\n BatchResultItem,\n TierSpec,\n} from \"../types.js\";\nimport type { Contracts } from \"../capabilities/contracts/types.js\";\n\n// ── Reusable sub-schemas ───────────────────────────────────────────────────\n\nexport const transportSchema = z.enum([\"http\", \"subprocess\"]);\n\nexport const tierSchema = z.enum([\n \"fast\",\n \"smart\",\n \"powerful\",\n \"cheap\",\n \"vision\",\n \"video\",\n \"embedding\",\n]);\n\nexport const tierSpecSchema = z.object({\n provider: z.string(),\n model: z.string(),\n transport: transportSchema,\n});\n\nexport const toolSchema = z.object({\n name: z.string(),\n description: z.string(),\n parameters: z.record(z.unknown()),\n});\n\n// F043.4. `arguments` is ours and canonical; `args` is what @broberg/chat emits.\n// The TYPE accepted both from the start — this SCHEMA did not, and chatInputSchema\n// runs on every ai.chat()/ai.chatStream(), so the fix never reached a real consumer:\n// a message history using `args` still failed with\n// \"messages.0.toolCalls.0.arguments — Required\", verbatim the error we said was fixed.\n// The end-to-end test that \"proved\" it called the adapter directly and skipped\n// validation entirely — a test that exercised the one path nobody uses.\n//\n// Zod also STRIPS unknown keys, so making `arguments` optional alone would have\n// silently dropped `args` on the floor. Both keys must be declared, and at least one\n// present.\nexport const toolCallSchema = z\n .object({\n id: z.string(),\n name: z.string(),\n arguments: z.record(z.unknown()).optional(),\n args: z.record(z.unknown()).optional(),\n })\n .refine((tc) => tc.arguments !== undefined || tc.args !== undefined, {\n message: \"tool call needs `arguments` (canonical) or `args` (@broberg/chat's spelling)\",\n path: [\"arguments\"],\n });\n\nexport const contentPartSchema = z.union([\n z.object({ type: z.literal(\"text\"), text: z.string() }),\n z.object({\n type: z.literal(\"image\"),\n image: z.union([z.string(), z.instanceof(Uint8Array)]),\n mimeType: z.string().optional(),\n }),\n]);\n\nexport const messageSchema = z.object({\n role: z.enum([\"system\", \"user\", \"assistant\", \"tool\"]),\n content: z.union([z.string(), z.array(contentPartSchema)]),\n toolCalls: z.array(toolCallSchema).optional(),\n toolCallId: z.string().optional(),\n});\n\n/** Per-call options shared by every capability input. */\nconst callOptions = {\n tier: tierSchema.optional(),\n override: tierSpecSchema.partial().optional(),\n fallback: z.array(z.union([tierSchema, tierSpecSchema])).optional(),\n purpose: z.string().optional(),\n /** Consumer-defined attribution dimensions (e.g. {tenantId}) ridden into the\n * cost sink for per-tenant/per-customer cost breakdown (F011). */\n labels: z.record(z.string(), z.string()).optional(),\n} as const;\n\n// ── The 5 capability inputs ────────────────────────────────────────────────\n\nexport const chatInputSchema = z.object({\n /** F039 — reuse a cached prompt prefix on Mistral at 10% of the input rate.\n * A stable id for \"the same conversation\" (conversation id, session id).\n * Derive it from (tenant, conversation): the key is a shared-prefix identity,\n * so two tenants with identical transcripts must get different keys. */\n promptCacheKey: z.string().optional(),\n /** F039.2 — prompt caching is ON by default on providers that support it.\n * false opts out; an explicit promptCacheKey always wins. */\n promptCache: z.boolean().optional(),\n prompt: z.string().optional(),\n messages: z.array(messageSchema).optional(),\n system: z.string().optional(),\n tools: z.array(toolSchema).optional(),\n maxTokens: z.number().int().positive().optional(),\n temperature: z.number().min(0).max(2).optional(),\n /** \"json\" requests JSON-object output (OpenAI-compatible response_format). */\n responseFormat: z.enum([\"json\", \"text\"]).optional(),\n ...callOptions,\n});\n\nexport const visionInputSchema = z.object({\n image: z.union([z.string(), z.instanceof(Uint8Array)]),\n prompt: z.string(),\n mimeType: z.string().optional(),\n /** System instruction — drives instruction-following far better than stuffing\n * rules into `prompt` for instruction-heavy vision tasks (e.g. a JSON critic). */\n system: z.string().optional(),\n ...callOptions,\n});\n\n// F019 — analyze a video natively (e.g. \"what's in the first 30s?\"). Same shape\n// as vision but with a video payload (URL, data-URL, or raw bytes).\nexport const videoInputSchema = z.object({\n video: z.union([z.string(), z.instanceof(Uint8Array)]),\n prompt: z.string(),\n mimeType: z.string().optional(),\n /** System instruction — same instruction-following benefit as on vision. */\n system: z.string().optional(),\n ...callOptions,\n});\n\nexport const translateInputSchema = z.object({\n text: z.string(),\n to: z.string(),\n from: z.string().optional(),\n ...callOptions,\n});\n\nexport const loraWeightSchema = z.object({\n path: z.string(),\n scale: z.number().optional(),\n});\n\nexport const imageInputSchema = z.object({\n prompt: z.string(),\n width: z.number().int().positive().optional(),\n height: z.number().int().positive().optional(),\n /** LoRAs to merge at inference (F021). */\n loras: z.array(loraWeightSchema).optional(),\n /** Shorthand for a single LoRA — normalized to loras:[{path, scale:1}]. */\n lora: z.string().optional(),\n /** F023 — a BFL finetune id (subject trained in the BFL dashboard). Routes to the\n * EU-resident BFL finetuned-portrait endpoint. */\n finetune: z.string().optional(),\n /** F023 — BFL finetune_strength (~0–2; higher = stronger likeness). */\n finetuneStrength: z.number().min(0).max(2).optional(),\n /** F023.5 — 1–8 reference photos (URL or raw bytes) → EU-resident BFL FLUX 2\n * multi-reference generation (likeness, no training step). */\n referenceImages: z.array(z.union([z.string(), z.instanceof(Uint8Array)])).min(1).max(8).optional(),\n /** F023.5 — fixed seed for reproducible output (BFL). */\n seed: z.number().int().optional(),\n /** F023.5 — output container (BFL FLUX 2). Default jpeg. */\n outputFormat: z.enum([\"jpeg\", \"png\", \"webp\"]).optional(),\n /** F023.5 — BFL content-moderation strictness, 0 (strict) … 6 (lax). Default 2. */\n safetyTolerance: z.number().int().min(0).max(6).optional(),\n /** F021.4 — re-roll once if fal returns a black image (NSFW false-positive). */\n retryOnBlack: z.boolean().optional(),\n ...callOptions,\n});\n\n// Image-to-video (F024) — animate a still into a short clip via a pluggable provider.\nexport const animateInputSchema = z.object({\n /** Input image: a URL or raw bytes (uploaded to fal storage). */\n image: z.union([z.string(), z.instanceof(Uint8Array)]),\n /** Motion/scene prompt. */\n prompt: z.string().optional(),\n /** Clip length in seconds (provider-dependent; Veo ≤ 8s). */\n durationSec: z.number().positive().optional(),\n /** e.g. \"720p\" / \"1080p\" (provider-dependent). */\n resolution: z.string().optional(),\n ...callOptions,\n});\n\nexport const trainStyleInputSchema = z.object({\n /** A hosted archive URL, or an array of image URLs the SDK zips in-memory. */\n images: z.union([z.string(), z.array(z.string())]),\n /** Style LoRA (disables captioning/masks). Default true. */\n isStyle: z.boolean().optional(),\n triggerWord: z.string().optional(),\n steps: z.number().int().positive().optional(),\n createMasks: z.boolean().optional(),\n ...callOptions,\n});\n\nexport const embeddingInputSchema = z.object({\n text: z.union([z.string(), z.array(z.string())]),\n ...callOptions,\n});\n\nexport const transcribeInputSchema = z.object({\n /** Audio URL or raw bytes. */\n audio: z.union([z.string(), z.instanceof(Uint8Array)]),\n language: z.string().optional(),\n /** Audio length in seconds — enables Whisper per-minute cost. */\n durationSec: z.number().positive().optional(),\n /** Bias toward brand/jargon terms (Azure phraseList, F029.3); others ignore it. */\n phrases: z.array(z.string()).optional(),\n /** Opt-in timestamps (F036) — a single granularity or an array. Omit → the\n * current { text, usage } shape, unchanged. Pass [\"word\",\"segment\"] for both.\n * Supported by Whisper (openai) + Azure fast-transcription (F036.1); other\n * adapters (Voxtral/mistral) ignore it and return text only. */\n timestamps: z\n .union([z.enum([\"word\", \"segment\"]), z.array(z.enum([\"word\", \"segment\"]))])\n .optional(),\n ...callOptions,\n});\n\n// OCR (F016.2) — document/image → structured markdown text, billed per page.\nexport const ocrInputSchema = z.object({\n /** A URL, data-URL, or raw bytes of the document/image. */\n document: z.union([z.string(), z.instanceof(Uint8Array)]),\n /** image/* → routed as an image; anything else → a document (PDF etc.). */\n mimeType: z.string().optional(),\n ...callOptions,\n});\n\n// Moderation (F016.4) — classify text against safety categories, billed per token.\nexport const moderationInputSchema = z.object({\n input: z.union([z.string(), z.array(z.string())]),\n ...callOptions,\n});\n\n// Podcast (F020) — a finished manuscript (speaker turns) + a speaker→voiceId map →\n// one finished multi-voice audio episode (ElevenLabs Text-to-Dialogue).\nexport const podcastInputSchema = z.object({\n script: z.array(z.object({ speaker: z.string(), text: z.string() })).min(1),\n voices: z.record(z.string(), z.string()),\n format: z.string().optional(),\n ...callOptions,\n});\n\n// Single-voice TTS (F020.4) — text → audio. `voice` is a curated name or a voiceId.\n// `lang`/`format` (F026) are used by the Azure adapter; ElevenLabs ignores them.\nexport const ttsInputSchema = z.object({\n text: z.string(),\n voice: z.string(),\n /** F037: voice to use if `voice` is one we know the provider has retired. Without\n * it a retired voice throws VoiceUnavailableError rather than reaching the API.\n *\n * THINK BEFORE SETTING THIS. It is right for batch work where any acceptable voice\n * will do (a generated podcast, a bulk render). It is WRONG where the voice is an\n * identity a human recognises — a brand voice, a house narrator: falling back means\n * your product suddenly speaks with a stranger's voice and says nothing about why.\n * There, leave it unset and let the throw alarm you. Silence WITH a message beats\n * the wrong audio WITHOUT one. (torrent-search-api's call on their own house voice,\n * 2026-08-11 — they took the alarm over the fallback, deliberately.) */\n voiceFallback: z.string().optional(),\n lang: z.string().optional(),\n format: z.string().optional(),\n rate: z.number().positive().optional(),\n ...callOptions,\n});\n\n// ── Client config ──────────────────────────────────────────────────────────\n\nexport const budgetSchema = z.object({\n perCallUsd: z.number().positive().optional(),\n rollingUsd: z.number().positive().optional(),\n});\n\n/** F022 — opt-in proactive availability gate. Off by default so existing call\n * sites are byte-identical. When autoResolve is on, a suspended primary model\n * is transparently swapped to `fallback` before dispatch (synchronous, no I/O). */\nexport const availabilitySchema = z.object({\n autoResolve: z.boolean().optional(),\n fallback: z.union([z.string(), z.array(z.string())]).optional(),\n});\n\nexport const aiConfigSchema = z.object({\n /** F039.2 — client-wide opt-out from prompt caching (default: on where the\n * provider supports it). A per-call `promptCache` wins over this. */\n promptCache: z.boolean().optional(),\n defaults: z.record(tierSchema, tierSpecSchema).optional(),\n // Functions can't be deeply validated — z.custom asserts the TS type and\n // passes the value through untouched.\n providers: z.record(z.string(), z.custom<ProviderAdapter>()).optional(),\n /** Omit → cost-tracking auto-wires from the upmetrics env (F034). Pass `null`\n * to opt OUT explicitly — for a consumer that already reports its own costs\n * and would otherwise be counted twice (F034.3). An object is used as-is. */\n costSink: z.custom<CostSink>().nullable().optional(),\n budget: budgetSchema.optional(),\n availability: availabilitySchema.optional(),\n});\n\n// ── Derived types (z.infer is the single source) ───────────────────────────\n\nexport type ChatInput = z.infer<typeof chatInputSchema>;\nexport type VisionInput = z.infer<typeof visionInputSchema>;\nexport type VideoInput = z.infer<typeof videoInputSchema>;\nexport type TranslateInput = z.infer<typeof translateInputSchema>;\nexport type ImageInput = z.infer<typeof imageInputSchema>;\nexport type AnimateInput = z.infer<typeof animateInputSchema>;\nexport type TrainStyleInput = z.infer<typeof trainStyleInputSchema>;\nexport type EmbeddingInput = z.infer<typeof embeddingInputSchema>;\nexport type TranscribeInput = z.infer<typeof transcribeInputSchema>;\nexport type OcrInput = z.infer<typeof ocrInputSchema>;\nexport type ModerationInput = z.infer<typeof moderationInputSchema>;\nexport type PodcastInput = z.infer<typeof podcastInputSchema>;\nexport type TtsInput = z.infer<typeof ttsInputSchema>;\nexport type AiConfig = z.infer<typeof aiConfigSchema>;\n\n/** The public facade. Defined here because it depends on the derived inputs. */\nexport interface AiClient {\n chat(input: ChatInput): Promise<ChatResult>;\n /** Streaming chat (F8) — same input as chat; yields ChatStreamEvents. The\n * caller owns the tool-loop (per-turn engine, not an agent runtime). */\n chatStream(input: ChatInput): AsyncIterable<ChatStreamEvent>;\n vision(input: VisionInput): Promise<ChatResult>;\n /** Video Vision (F019) — analyze a video natively. Default tier: \"video\". */\n video(input: VideoInput): Promise<ChatResult>;\n translate(input: TranslateInput): Promise<TranslateResult>;\n image(input: ImageInput): Promise<ImageResult>;\n /** Image-to-video (F024) — animate a still into a short clip → { url, usage }. fal. */\n animate(input: AnimateInput): Promise<AnimateResult>;\n /** Train a style/brand LoRA from images (F021) → { loraUrl, configUrl }. fal. */\n trainStyle(input: TrainStyleInput): Promise<TrainStyleResult>;\n embedding(input: EmbeddingInput): Promise<EmbeddingResult>;\n transcribe(input: TranscribeInput): Promise<TranscribeResult>;\n /** OCR (F016.2) — document/image → structured markdown, billed per page. Mistral. */\n ocr(input: OcrInput): Promise<OcrResult>;\n /** Moderation (F016.4) — classify text against safety categories. Mistral. */\n moderate(input: ModerationInput): Promise<ModerationResult>;\n /** Podcast (F020) — a finished manuscript → one multi-voice audio episode. ElevenLabs. */\n podcast(input: PodcastInput): Promise<PodcastResult>;\n /** Single-voice TTS (F020.4) — text → audio. `voice` = curated name or voiceId. ElevenLabs. */\n tts(input: TtsInput): Promise<PodcastResult>;\n /** Batch (F016.1) — submit many chat requests for async (≤24h) processing at 50% cost. Mistral. */\n batch: {\n submit(input: { requests: BatchRequestItem[]; override?: TierSpec }): Promise<BatchJob>;\n status(jobId: string, override?: TierSpec): Promise<BatchJob>;\n results(jobId: string, override?: TierSpec): Promise<BatchResultItem[]>;\n };\n /** Prompt-contract capabilities (F5.5) layered on chat/vision. */\n contracts: Contracts;\n}\n","// AUTO-GENERATED by scripts/gen-version.mjs — do not edit, do not commit.\nexport const VERSION = \"0.36.6\" as const;\nexport const SDK_TAG = \"@broberg/ai-sdk@0.36.6\" as const;\n","// upmetricsSink — the canonical cost sink. Forwards each Usage to the upmetrics\n// agent-run ingest (POST /api/agent, mode:\"record\"). Field mapping follows\n// upmetrics/docs/AGENT-SCHEMA.md \"For cost-sink authors\" exactly:\n// - agent_kind / agent_name are injected (not in Usage; required by ingest)\n// - camelCase Usage → snake_case wire fields\n// - capability + transport ride in tags (no top-level column)\n// - toolCalls[].errorCount → tool_calls[].error_count (deep rename)\n// - latencyMs → duration_ms; ts → started_at; ended_at = ts + latency\n// Errors never propagate (CostSink invariant). Do NOT use @upmetrics/agent\n// wrapAnthropic here — the SDK already owns the provider call.\nimport { SDK_TAG } from \"../../version.js\";\nimport type { CostSink, Usage } from \"../../types.js\";\n\nexport interface UpmetricsSinkConfig {\n /** Ingest base URL, e.g. https://upmetrics.org */\n baseUrl: string;\n /** Per-project api_key → sent as the X-Upmetrics-Key header. */\n apiKey: string;\n /** Consumer name dashboards group by (e.g. \"cms\", \"trail\", \"xrt81\") — NOT the\n * capability. */\n agentName: string;\n /** Defaults to \"chatbot\" (\"embedding\" auto-selected for embedding calls). */\n agentKind?: string;\n /** When true, guarantees no prompt/response content is ever sent (the sink\n * sends none regardless — Usage carries no excerpts — so this is belt-and-\n * suspenders for GDPR-health projects). */\n complianceMode?: boolean;\n /** Injectable fetch for testing; defaults to global fetch. */\n fetch?: typeof fetch;\n /** Optional error hook (errors are otherwise swallowed silently). */\n onError?: (err: unknown) => void;\n}\n\nexport function upmetricsSink(config: UpmetricsSinkConfig): CostSink {\n const doFetch = config.fetch ?? fetch;\n const url = `${config.baseUrl.replace(/\\/$/, \"\")}/api/agent`;\n\n return {\n async record(usage: Usage): Promise<void> {\n try {\n const startedAt = usage.ts || new Date().toISOString();\n const endedAt = new Date(\n new Date(startedAt).getTime() + (usage.latencyMs || 0),\n ).toISOString();\n\n const agentKind =\n config.agentKind ?? (usage.capability === \"embedding\" ? \"embedding\" : \"chatbot\");\n\n const body: Record<string, unknown> = {\n mode: \"record\",\n agent_kind: agentKind,\n agent_name: config.agentName,\n provider: usage.provider,\n model: usage.model,\n status: \"success\",\n input_tokens: usage.inputTokens,\n output_tokens: usage.outputTokens,\n cache_read_tokens: usage.cacheReadTokens,\n cache_creation_tokens: usage.cacheCreationTokens,\n cost_usd: usage.costUsd,\n duration_ms: usage.latencyMs,\n started_at: startedAt,\n ended_at: endedAt,\n tags: {\n // Consumer attribution labels (e.g. tenantId) ride in tags so no new\n // top-level field risks the strict-shape ingest schema (F011). The\n // SDK-owned keys win — a label can never clobber capability/transport/sdk.\n ...usage.labels,\n capability: usage.capability,\n transport: usage.transport,\n // F042: data residency of the route that answered. Rides in tags like\n // capability/transport — no ingest-schema change, and without it the one\n // field built for auditability existed only in memory.\n region: usage.region,\n sdk: SDK_TAG,\n },\n };\n if (usage.tier !== undefined) body.tier = usage.tier;\n if (usage.purpose !== undefined) body.purpose = usage.purpose;\n if (usage.toolCalls) {\n body.tool_calls = usage.toolCalls.map((t) => ({\n name: t.name,\n count: t.count,\n error_count: t.errorCount ?? 0,\n }));\n }\n // complianceMode is a no-op today (we never send excerpts) but documents intent.\n void config.complianceMode;\n\n const res = await doFetch(url, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n \"X-Upmetrics-Key\": config.apiKey,\n },\n body: JSON.stringify(body),\n });\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n config.onError?.(\n new Error(`upmetricsSink: ingest returned ${res.status}: ${text.slice(0, 200)}`),\n );\n }\n } catch (err) {\n // Never let a sink failure crash a real AI call.\n config.onError?.(err);\n }\n },\n };\n}\n","// createAI() — the facade factory. Resolves routing, picks a provider adapter,\n// delegates the call, stamps call-context metadata onto Usage, and reports to the\n// cost sink. Provider specifics live in adapters; cost compute/budget land in F3.\nimport { assertOverrideProvider, resolveTier } from \"./routing/tier-map.js\";\nimport { resolveModel } from \"./availability/resolve.js\";\nimport { defaultProviders } from \"./providers/registry.js\";\nimport { computeCost } from \"./cost/usage.js\";\nimport { BudgetGuard } from \"./cost/budget.js\";\nimport { buildVisionMessages, VISION_DEFAULT_TIER } from \"./capabilities/vision.js\";\nimport { buildVideoMessages, VIDEO_DEFAULT_TIER } from \"./capabilities/video.js\";\nimport { buildTranslateMessages, TRANSLATE_DEFAULT_TIER } from \"./capabilities/translate.js\";\nimport { EMBEDDING_DEFAULT_TIER } from \"./capabilities/embedding.js\";\nimport { DEFAULT_TRANSCRIBE_SPEC, resolveAudio } from \"./capabilities/transcribe.js\";\nimport { makeContracts } from \"./capabilities/contracts/index.js\";\nimport { checkVoice, VoiceUnavailableError } from \"./voices/index.js\";\nimport {\n aiConfigSchema,\n chatInputSchema,\n visionInputSchema,\n videoInputSchema,\n translateInputSchema,\n imageInputSchema,\n animateInputSchema,\n trainStyleInputSchema,\n embeddingInputSchema,\n transcribeInputSchema,\n ocrInputSchema,\n moderationInputSchema,\n podcastInputSchema,\n ttsInputSchema,\n} from \"./schema/inputs.js\";\nimport type {\n AiConfig,\n AiClient,\n ChatInput,\n VisionInput,\n VideoInput,\n TranslateInput,\n ImageInput,\n AnimateInput,\n TrainStyleInput,\n EmbeddingInput,\n TranscribeInput,\n OcrInput,\n ModerationInput,\n PodcastInput,\n TtsInput,\n} from \"./schema/inputs.js\";\nimport type {\n ChatResult,\n ChatStreamEvent,\n ImageResult,\n AnimateResult,\n TrainStyleResult,\n EmbeddingResult,\n TranscribeResult,\n OcrResult,\n ModerationResult,\n PodcastResult,\n BatchRequestItem,\n BatchJob,\n BatchResultItem,\n TranslateResult,\n ProviderAdapter,\n Message,\n Capability,\n Tier,\n TierSpec,\n Usage,\n CostSink,\n} from \"./types.js\";\nimport { upmetricsSink } from \"./cost/sinks/upmetrics.js\";\n\n/** Built-in image route (no image tier in the tier map — fal owns its routing). */\nconst DEFAULT_IMAGE_SPEC: TierSpec = {\n provider: \"fal\",\n model: \"fal-ai/flux/schnell\",\n transport: \"http\",\n};\n/** LoRA-inference route (F021) — used by ai.image when loras are supplied. */\nconst DEFAULT_LORA_IMAGE_SPEC: TierSpec = {\n provider: \"fal\",\n model: \"fal-ai/flux-lora\",\n transport: \"http\",\n};\n/** Style-LoRA training route (F021) — fal flux-lora-fast-training. */\nconst DEFAULT_TRAINSTYLE_SPEC: TierSpec = {\n provider: \"fal\",\n model: \"fal-ai/flux-lora-fast-training\",\n transport: \"http\",\n};\n/** Image-to-video route (F024) — Veo 3.1 DIRECT via the Gemini API (no fal markup,\n * our existing GEMINI_API_KEY, and the path to EU via Vertex later). Override to\n * {provider:\"fal\", model:\"fal-ai/veo3.1/...\"} for the aggregator / other models\n * (Kling, Seedance). US-hosted: consent-gated use (F024). */\nconst DEFAULT_ANIMATE_SPEC: TierSpec = {\n provider: \"gemini\",\n model: \"veo-3.1-generate-preview\",\n transport: \"http\",\n};\n/** Default audio directive appended to every ai.animate prompt (F024, Christian's\n * preference): no generated speech (it's the weak link, esp. non-English), but\n * ambient sounds matched to the scene are wanted. A soft prompt instruction. */\nconst ANIMATE_AUDIO_DIRECTIVE =\n \"No spoken dialogue, no talking, no voiceover. Include natural ambient background sounds that match the environment.\";\n/** EU-resident finetuned-portrait route (F023) — BFL, used by ai.image when a\n * `finetune` id is supplied. Hard-pinned to api.eu.bfl.ai inside the adapter. */\nconst DEFAULT_BFL_FINETUNE_SPEC: TierSpec = {\n provider: \"bfl\",\n model: \"flux-pro-1.1-ultra-finetuned\",\n transport: \"http\",\n};\n/** EU-resident multi-reference route (F023.5) — BFL FLUX 2, used by ai.image when\n * `referenceImages` are supplied (likeness with no training step). flux-2-max =\n * premium-quality default; override to flux-2-pro/flex for volume. EU-pinned. */\nconst DEFAULT_BFL_REFERENCE_SPEC: TierSpec = {\n provider: \"bfl\",\n model: \"flux-2-max\",\n transport: \"http\",\n};\n\n/** OCR + moderation are Mistral specialty endpoints (F016) — no tier, route by default. */\nconst DEFAULT_OCR_SPEC: TierSpec = { provider: \"mistral\", model: \"mistral-ocr-latest\", transport: \"http\" };\nconst DEFAULT_MODERATION_SPEC: TierSpec = { provider: \"mistral\", model: \"mistral-moderation-latest\", transport: \"http\" };\n/** Podcast route (F020) — ElevenLabs Text-to-Dialogue, eleven_v3 (multi-voice, multilingual). */\nconst DEFAULT_PODCAST_SPEC: TierSpec = { provider: \"elevenlabs\", model: \"eleven_v3\", transport: \"http\" };\n/** Single-voice TTS route (F020.4) — ElevenLabs eleven_multilingual_v2 (good Danish). */\nconst DEFAULT_TTS_SPEC: TierSpec = { provider: \"elevenlabs\", model: \"eleven_multilingual_v2\", transport: \"http\" };\n/** Batch route (F016.1) — Mistral batch jobs (50% cost), cheap default model. */\nconst DEFAULT_BATCH_SPEC: TierSpec = { provider: \"mistral\", model: \"mistral-small-latest\", transport: \"http\" };\n\n/** Cost-tracking on by DEFAULT (F034): an explicit config.costSink always wins;\n * otherwise, when the upmetrics env is present, auto-wire the canonical sink so\n * fleet-wide call-sites report without per-repo wiring (per-repo wiring drifts —\n * ~91% of Mistral spend was invisible because most call-sites passed no sink).\n * Env absent (no UPMETRICS_API_KEY) → undefined = ship-dark, current behaviour.\n * Server-entry only: createAI already pulls the provider adapters (which read\n * process.env at call time), so this module is never in the browser build (the\n * browser imports \"@broberg/ai-sdk/registry\"). */\nfunction defaultCostSink(): CostSink | undefined {\n const apiKey = process.env.UPMETRICS_API_KEY;\n if (!apiKey) return undefined;\n return upmetricsSink({\n baseUrl: process.env.UPMETRICS_BASE_URL ?? \"https://upmetrics.org\",\n apiKey,\n agentName: process.env.UPMETRICS_AGENT_NAME ?? process.env.npm_package_name ?? \"unknown\",\n complianceMode: process.env.UPMETRICS_COMPLIANCE === \"1\",\n });\n}\n\nexport function createAI(config: AiConfig = {}): AiClient {\n // Validate config at the boundary (throws ZodError on bad shape).\n const cfg = aiConfigSchema.parse(config);\n const providers = cfg.providers ?? defaultProviders;\n // Explicit wins — including explicit NONE. `undefined` (omitted) auto-wires\n // from env (F034); `null` is a deliberate opt-out for a consumer that already\n // reports its own costs and would otherwise be double-counted (F034.3); an\n // object is used as-is.\n const costSink = cfg.costSink === undefined ? defaultCostSink() : (cfg.costSink ?? undefined);\n const budget = cfg.budget ? new BudgetGuard(cfg.budget) : undefined;\n\n const estTokens = (s: string): number => Math.ceil(s.length / 4);\n\n /** Pre-flight budget check. Estimates this call's cost and throws\n * BudgetExceededError before the transport fires. No-op without a budget. */\n async function preflight(spec: TierSpec, estInTokens: number, estOutTokens: number): Promise<void> {\n if (!budget) return;\n await budget.check(computeCost(spec.provider, spec.model, estInTokens, estOutTokens));\n }\n\n /** Fold the actual cost into the rolling total after a successful call. */\n async function settle(usage: Usage): Promise<void> {\n if (budget) await budget.record(usage.costUsd);\n }\n\n const providerNames = Object.keys(providers);\n\n /** THE ONE PLACE a non-tier capability merges its override (F043.2). The guard used\n * to live inside resolveTier, which nine capabilities never call — so they merged\n * the override themselves and skipped it, and ai.image({override:{provider:\"fal\"}})\n * still posted BFL's flux-2-pro to fal.\n *\n * NOT used by tts/podcast/transcribe, and the reason is measured rather than\n * assumed: the guard exists because a foreign model id gets POSTED to the provider.\n * Azure's TTS never sends spec.model at all — it reads req.voiceId and puts the\n * model only in the usage record — so `ai.tts({override:{provider:\"azure\"}})` is a\n * legitimate, already-tested call with nothing to refuse. Guarding it broke that\n * test, and the test was right. Speech routes by VOICE; the model is an engine hint\n * each adapter interprets for itself. */\n function withOverride(\n base: TierSpec,\n override: Partial<TierSpec> | undefined,\n label: string,\n ): TierSpec {\n assertOverrideProvider(base, override, label, providerNames);\n return { ...base, ...override };\n }\n\n /** Merge an override WITHOUT the provider/model guard, stating why in the call.\n *\n * The guard exists because a foreign model id gets POSTED to the provider. Where\n * the provider never sends spec.model, there is nothing to refuse and guarding\n * breaks a legitimate call. That exemption is real — but until now a raw\n * `{...base, ...override}` looked identical whether it was DELIBERATE or FORGOTTEN,\n * and telling those two apart by counting call sites is exactly what failed three\n * times in the fleet this week.\n *\n * So the exemption gets a name and a mandatory reason, and a structural test\n * forbids the raw spread everywhere else. `why` is unused at runtime on purpose:\n * its whole job is to make a silent exemption impossible to write. */\n function mergeUnguarded(base: TierSpec, override: Partial<TierSpec> | undefined, why: string): TierSpec {\n void why;\n return { ...base, ...override };\n }\n\n function pickProvider(name: string): ProviderAdapter {\n // Object.hasOwn, not a bare lookup: `providers` inherits from Object.prototype, so\n // providers[\"constructor\"] returns a FUNCTION and passes the !adapter check. The\n // caller then got \"provider \\\"constructor\\\" does not support chat\" instead of \"no\n // provider adapter registered\" — it fails closed, but on exactly the override path\n // F043.2 just fixed for giving a misleading message, so leaving it would be\n // inconsistent with that change.\n const adapter = Object.hasOwn(providers, name) ? providers[name] : undefined;\n if (!adapter) {\n throw new Error(\n `createAI: no provider adapter registered for \"${name}\". Registered: ${Object.keys(providers).join(\", \") || \"(none)\"}`,\n );\n }\n return adapter;\n }\n\n /** Stamp call-context metadata the client owns onto the adapter's Usage:\n * capability, tier, purpose, the wall-clock latency, and the timestamp. */\n function enrich(\n usage: Usage,\n capability: Capability,\n tier: Tier | undefined,\n purpose: string | undefined,\n latencyMs: number,\n labels: Record<string, string> | undefined,\n ): Usage {\n usage.capability = capability;\n if (tier) usage.tier = tier;\n if (purpose) usage.purpose = purpose;\n if (labels && Object.keys(labels).length > 0) usage.labels = labels;\n usage.latencyMs = Math.round(latencyMs);\n if (!usage.ts) usage.ts = new Date().toISOString();\n return usage;\n }\n\n async function report(usage: Usage): Promise<void> {\n if (!costSink) return;\n try {\n await costSink.record(usage);\n } catch {\n // A broken sink must never crash a real AI call (F3.3 invariant).\n }\n }\n\n function toMessages(input: ChatInput): Message[] {\n if (input.messages && input.messages.length > 0) {\n // A top-level `system` must survive when `messages` is also supplied — prepend\n // it (unless the caller already leads with a system message) instead of\n // silently dropping it. Regression: system + messages → system was lost, so a\n // \"return ONLY JSON\" system instruction never reached the model (cms #4234).\n if (input.system && input.messages[0]?.role !== \"system\") {\n return [{ role: \"system\", content: input.system }, ...input.messages];\n }\n return input.messages;\n }\n const msgs: Message[] = [];\n if (input.system) msgs.push({ role: \"system\", content: input.system });\n msgs.push({ role: \"user\", content: input.prompt ?? \"\" });\n return msgs;\n }\n\n /** F022 — opt-in proactive availability gate. When cfg.availability.autoResolve\n * is set, swap a known-suspended primary model to its configured fallback\n * BEFORE dispatch (synchronous, registry-only — no I/O). Default off → the\n * spec is returned untouched and behaviour is byte-identical. This sits in\n * front of the reactive route-fallback below. */\n function applyAvailability(spec: TierSpec): TierSpec {\n if (!cfg.availability?.autoResolve) return spec;\n const r = resolveModel(spec.model, { fallback: cfg.availability.fallback, provider: spec.provider });\n return r.fellBack ? { ...spec, model: r.model } : spec;\n }\n\n /** Run a capability with an optional fallback chain. Tries the primary route,\n * then each fallback (Tier or TierSpec) in order if the call errors. A budget\n * breach propagates immediately (not a fallback trigger). On the first\n * success: stamp Usage, settle the budget, report to the sink, return. */\n async function runCapability<R extends { usage: Usage }>(opts: {\n primary: TierSpec;\n fallback?: (Tier | TierSpec)[];\n capability: Capability;\n tier?: Tier;\n purpose?: string;\n labels?: Record<string, string>;\n estIn: number;\n estOut: number;\n invoke: (spec: TierSpec) => Promise<R>;\n }): Promise<R> {\n const routes: TierSpec[] = [\n applyAvailability(opts.primary),\n ...(opts.fallback ?? []).map((f) =>\n typeof f === \"string\" ? resolveTier(f, undefined, cfg.defaults) : f,\n ),\n ];\n let lastErr: unknown;\n for (let i = 0; i < routes.length; i++) {\n const spec = routes[i]!;\n await preflight(spec, opts.estIn, opts.estOut); // BudgetExceededError propagates\n try {\n const t0 = performance.now();\n const res = await opts.invoke(spec);\n enrich(res.usage, opts.capability, i === 0 ? opts.tier : undefined, opts.purpose, performance.now() - t0, opts.labels);\n await settle(res.usage);\n await report(res.usage);\n return res;\n } catch (e) {\n lastErr = e; // try the next fallback route\n }\n }\n throw lastErr;\n }\n\n /** Whether a pre-first-token streaming error should fall back to the next\n * route. Eligible: network/timeout/parse (no status) + 429 + 5xx. Hard 4xx\n * bubbles up (no silent re-route) — sa contract #2565. */\n function eligibleForFallback(e: unknown): boolean {\n const status = (e as { status?: number } | null)?.status;\n if (status === undefined) return true;\n return status === 429 || status >= 500;\n }\n\n function errorEvent(e: unknown): ChatStreamEvent {\n const ev: ChatStreamEvent = {\n type: \"error\",\n message: e instanceof Error ? e.message : String(e),\n };\n const status = (e as { status?: number } | null)?.status;\n if (status !== undefined) ev.status = status;\n return ev;\n }\n\n /** Streaming chat with pre-stream fallback (F8.1). Yields ChatStreamEvents as\n * the turn unfolds. Fallback re-routes only BEFORE the first text/tool_call\n * event (deltas can't be un-emitted); once streaming has begun, an error is\n * surfaced as an error event and the stream ends. Budget breaches propagate. */\n async function* chatStreamImpl(input: ChatInput): AsyncIterable<ChatStreamEvent> {\n input = chatInputSchema.parse(input);\n const tier = input.tier ?? \"smart\";\n const messages = toMessages(input);\n const estIn = messages.reduce(\n (n, m) => n + estTokens(typeof m.content === \"string\" ? m.content : JSON.stringify(m.content)),\n 0,\n );\n const estOut = input.maxTokens ?? 512;\n const routes: TierSpec[] = [\n resolveTier(tier, input.override, cfg.defaults, providerNames),\n ...(input.fallback ?? []).map((f) =>\n typeof f === \"string\" ? resolveTier(f, undefined, cfg.defaults) : f,\n ),\n ];\n\n let lastErr: unknown;\n for (let i = 0; i < routes.length; i++) {\n const spec = routes[i]!;\n await preflight(spec, estIn, estOut); // BudgetExceededError propagates\n const adapter = pickProvider(spec.provider);\n if (!adapter.chatStream) {\n throw new Error(`createAI: provider \"${spec.provider}\" does not support streaming`);\n }\n const t0 = performance.now();\n let emitted = false;\n try {\n for await (const ev of adapter.chatStream({\n messages,\n spec,\n tools: input.tools,\n maxTokens: input.maxTokens,\n temperature: input.temperature,\n responseFormat: input.responseFormat,\n // F043: these two were dropped here, so a streamed call could not cache even\n // after the adapter learned how. A chat UI streams every turn and repeats the\n // same system prompt each time — the call shape with the most to gain was the\n // one paying full price. Kept identical to the chat branch above on purpose.\n promptCacheKey: input.promptCacheKey,\n promptCache: input.promptCache ?? cfg.promptCache,\n })) {\n if (ev.type === \"text\" || ev.type === \"tool_call\") emitted = true;\n if (ev.type === \"usage\") {\n enrich(ev.usage, \"chat\", i === 0 ? tier : undefined, input.purpose, performance.now() - t0, input.labels);\n await settle(ev.usage);\n await report(ev.usage);\n }\n yield ev;\n }\n return; // stream completed cleanly\n } catch (e) {\n lastErr = e;\n if (emitted || !eligibleForFallback(e)) {\n yield errorEvent(e); // mid-stream or hard error → surface + stop\n return;\n }\n // pre-first-token eligible error → try the next route\n }\n }\n yield errorEvent(lastErr);\n }\n\n const client: AiClient = {\n async chat(input: ChatInput): Promise<ChatResult> {\n input = chatInputSchema.parse(input);\n const tier = input.tier ?? \"smart\";\n const messages = toMessages(input);\n const estIn = messages.reduce(\n (n, m) => n + estTokens(typeof m.content === \"string\" ? m.content : JSON.stringify(m.content)),\n 0,\n );\n return runCapability({\n primary: resolveTier(tier, input.override, cfg.defaults, providerNames),\n fallback: input.fallback,\n capability: \"chat\",\n tier,\n purpose: input.purpose,\n labels: input.labels,\n estIn,\n estOut: input.maxTokens ?? 512,\n invoke: async (spec) => {\n const adapter = pickProvider(spec.provider);\n if (!adapter.chat) throw new Error(`createAI: provider \"${spec.provider}\" does not support chat`);\n return adapter.chat({ messages, spec, tools: input.tools, maxTokens: input.maxTokens, temperature: input.temperature, responseFormat: input.responseFormat, promptCacheKey: input.promptCacheKey, promptCache: input.promptCache ?? cfg.promptCache });\n },\n });\n },\n\n chatStream: chatStreamImpl,\n\n async vision(input: VisionInput): Promise<ChatResult> {\n input = visionInputSchema.parse(input);\n const tier = input.tier ?? VISION_DEFAULT_TIER;\n const messages: Message[] = buildVisionMessages(input);\n return runCapability({\n primary: resolveTier(tier, input.override, cfg.defaults, providerNames),\n fallback: input.fallback,\n capability: \"vision\",\n tier,\n purpose: input.purpose,\n labels: input.labels,\n estIn: estTokens(input.prompt) + 1000, // prompt + ~1k image payload\n estOut: 512,\n invoke: async (spec) => {\n const adapter = pickProvider(spec.provider);\n if (!adapter.vision) throw new Error(`createAI: provider \"${spec.provider}\" does not support vision`);\n return adapter.vision({ messages, spec });\n },\n });\n },\n\n async video(input: VideoInput): Promise<ChatResult> {\n input = videoInputSchema.parse(input);\n const tier = input.tier ?? VIDEO_DEFAULT_TIER;\n const messages: Message[] = buildVideoMessages(input);\n return runCapability({\n primary: resolveTier(tier, input.override, cfg.defaults, providerNames),\n fallback: input.fallback,\n capability: \"video\",\n tier,\n purpose: input.purpose,\n labels: input.labels,\n estIn: estTokens(input.prompt) + 4000, // prompt + video tokens (native video ≈ frames)\n estOut: 512,\n invoke: async (spec) => {\n const adapter = pickProvider(spec.provider);\n // Video routes through the vision method — same multimodal message path.\n if (!adapter.vision) throw new Error(`createAI: provider \"${spec.provider}\" does not support video`);\n return adapter.vision({ messages, spec });\n },\n });\n },\n\n async translate(input: TranslateInput): Promise<TranslateResult> {\n input = translateInputSchema.parse(input);\n const tier = input.tier ?? TRANSLATE_DEFAULT_TIER;\n const messages: Message[] = buildTranslateMessages(input);\n const estIn = estTokens(input.text) + 40;\n const res = await runCapability<TranslateResult>({\n primary: resolveTier(tier, input.override, cfg.defaults, providerNames),\n fallback: input.fallback,\n capability: \"translate\",\n tier,\n purpose: input.purpose,\n labels: input.labels,\n estIn,\n estOut: estIn,\n invoke: async (spec) => {\n const adapter = pickProvider(spec.provider);\n // A dedicated translation engine (F032, e.g. DeepL) is preferred when the\n // resolved provider implements it — its `to`/`from` are provider-specific\n // codes, not the free-form names the chat prompt-contract accepts.\n if (adapter.translate) return adapter.translate({ text: input.text, to: input.to, from: input.from, spec });\n if (!adapter.chat) throw new Error(`createAI: provider \"${spec.provider}\" does not support chat (translate routes through chat)`);\n return adapter.chat({ messages, spec });\n },\n });\n return { text: res.text, usage: res.usage };\n },\n\n async image(input: ImageInput): Promise<ImageResult> {\n input = imageInputSchema.parse(input);\n // Normalize the `lora` shorthand into the loras array.\n const loras = [\n ...(input.loras ?? []),\n ...(input.lora ? [{ path: input.lora }] : []),\n ];\n // Route by what's supplied (override still wins): `referenceImages` → the EU\n // BFL FLUX 2 multi-reference endpoint (F023.5, no training step); a `finetune`\n // id → the EU BFL finetuned-portrait endpoint (F023); LoRAs → flux-lora (F021,\n // flux/schnell can't merge LoRAs); else the plain image route.\n const base = input.referenceImages?.length\n ? DEFAULT_BFL_REFERENCE_SPEC\n : input.finetune\n ? DEFAULT_BFL_FINETUNE_SPEC\n : loras.length > 0\n ? DEFAULT_LORA_IMAGE_SPEC\n : DEFAULT_IMAGE_SPEC;\n return runCapability({\n primary: withOverride(base, input.override, \"image\"),\n fallback: input.fallback,\n capability: \"image\",\n purpose: input.purpose,\n labels: input.labels,\n estIn: 0, // image cost is not token-based\n estOut: 0,\n invoke: async (spec) => {\n const adapter = pickProvider(spec.provider);\n if (!adapter.image) throw new Error(`createAI: provider \"${spec.provider}\" does not support image`);\n return adapter.image({\n prompt: input.prompt,\n spec,\n width: input.width,\n height: input.height,\n loras: loras.length ? loras : undefined,\n finetune: input.finetune,\n finetuneStrength: input.finetuneStrength,\n referenceImages: input.referenceImages,\n seed: input.seed,\n outputFormat: input.outputFormat,\n safetyTolerance: input.safetyTolerance,\n retryOnBlack: input.retryOnBlack,\n });\n },\n });\n },\n\n async animate(input: AnimateInput): Promise<AnimateResult> {\n input = animateInputSchema.parse(input);\n // Append the default audio directive (no speech, ambient sounds matched to scene).\n const prompt = input.prompt?.trim()\n ? `${input.prompt.trim()} ${ANIMATE_AUDIO_DIRECTIVE}`\n : ANIMATE_AUDIO_DIRECTIVE;\n return runCapability({\n primary: withOverride(DEFAULT_ANIMATE_SPEC, input.override, \"animate\"),\n fallback: input.fallback,\n capability: \"animate\",\n purpose: input.purpose,\n labels: input.labels,\n estIn: 0, // video cost is per-second, not token-based\n estOut: 0,\n invoke: async (spec) => {\n const adapter = pickProvider(spec.provider);\n if (!adapter.animate) throw new Error(`createAI: provider \"${spec.provider}\" does not support animate`);\n return adapter.animate({\n image: input.image,\n prompt,\n durationSec: input.durationSec,\n resolution: input.resolution,\n spec,\n });\n },\n });\n },\n\n async trainStyle(input: TrainStyleInput): Promise<TrainStyleResult> {\n input = trainStyleInputSchema.parse(input);\n return runCapability({\n primary: withOverride(DEFAULT_TRAINSTYLE_SPEC, input.override, \"trainStyle\"),\n fallback: input.fallback,\n capability: \"trainStyle\",\n purpose: input.purpose,\n labels: input.labels,\n estIn: 0, // training is priced flat by fal, not token-based\n estOut: 0,\n invoke: async (spec) => {\n const adapter = pickProvider(spec.provider);\n if (!adapter.trainStyle)\n throw new Error(`createAI: provider \"${spec.provider}\" does not support trainStyle`);\n return adapter.trainStyle({\n images: input.images,\n spec,\n isStyle: input.isStyle,\n triggerWord: input.triggerWord,\n steps: input.steps,\n createMasks: input.createMasks,\n });\n },\n });\n },\n\n async ocr(input: OcrInput): Promise<OcrResult> {\n input = ocrInputSchema.parse(input);\n return runCapability({\n primary: withOverride(DEFAULT_OCR_SPEC, input.override, \"ocr\"),\n fallback: input.fallback,\n capability: \"ocr\",\n purpose: input.purpose,\n labels: input.labels,\n estIn: 0, // OCR cost is per-page, not token-based\n estOut: 0,\n invoke: async (spec) => {\n const adapter = pickProvider(spec.provider);\n if (!adapter.ocr) throw new Error(`createAI: provider \"${spec.provider}\" does not support ocr`);\n return adapter.ocr({ document: input.document, mimeType: input.mimeType, spec });\n },\n });\n },\n\n async moderate(input: ModerationInput): Promise<ModerationResult> {\n input = moderationInputSchema.parse(input);\n const items = Array.isArray(input.input) ? input.input : [input.input];\n return runCapability({\n primary: withOverride(DEFAULT_MODERATION_SPEC, input.override, \"moderate\"),\n fallback: input.fallback,\n capability: \"moderation\",\n purpose: input.purpose,\n labels: input.labels,\n estIn: items.reduce((n, s) => n + estTokens(s), 0),\n estOut: 0,\n invoke: async (spec) => {\n const adapter = pickProvider(spec.provider);\n if (!adapter.moderate) throw new Error(`createAI: provider \"${spec.provider}\" does not support moderation`);\n return adapter.moderate({ input: items, spec });\n },\n });\n },\n\n async podcast(input: PodcastInput): Promise<PodcastResult> {\n input = podcastInputSchema.parse(input);\n // Map each manuscript turn to a {text, voiceId} dialogue input.\n const inputs = input.script.map((turn) => {\n const mapped = input.voices[turn.speaker];\n if (!mapped) throw new Error(`ai.podcast: no voice mapped for speaker \"${turn.speaker}\"`);\n // F037: refuse a voice we know is retired. No fallback here on purpose —\n // silently collapsing two speakers onto one voice ruins a dialogue, so a\n // dead voice in a cast is a refusal, not a degradation.\n const res = checkVoice(mapped); // curated name → voiceId\n if (!res.ok) throw new VoiceUnavailableError(mapped, `${res.reason} — speaker \"${turn.speaker}\"`, res.provider);\n return { text: turn.text, voiceId: res.voiceId };\n });\n const chars = input.script.reduce((n, t) => n + t.text.length, 0);\n return runCapability({\n primary: mergeUnguarded(DEFAULT_PODCAST_SPEC, input.override, \"routes by voice, not by model — the adapter never sends spec.model\"),\n fallback: input.fallback,\n capability: \"podcast\",\n purpose: input.purpose,\n labels: input.labels,\n estIn: chars, // per-character cost (not token-based)\n estOut: 0,\n invoke: async (spec) => {\n const adapter = pickProvider(spec.provider);\n if (!adapter.dialogue) throw new Error(`createAI: provider \"${spec.provider}\" does not support podcast/dialogue`);\n return adapter.dialogue({ inputs, format: input.format, spec });\n },\n });\n },\n\n async tts(input: TtsInput): Promise<PodcastResult> {\n input = ttsInputSchema.parse(input);\n // F037: gate the voice BEFORE the call path. Resolving here rather than inside\n // invoke() means a refusal is immediate and cannot be mistaken for a provider\n // failure and retried against the fallback chain.\n const { voiceId } = checkVoice(input.voice, { fallback: input.voiceFallback, throwIfUnavailable: true });\n return runCapability({\n primary: mergeUnguarded(DEFAULT_TTS_SPEC, input.override, \"routes by voice, not by model — the adapter never sends spec.model\"),\n fallback: input.fallback,\n capability: \"tts\",\n purpose: input.purpose,\n labels: input.labels,\n estIn: input.text.length, // per-character cost\n estOut: 0,\n invoke: async (spec) => {\n const adapter = pickProvider(spec.provider);\n if (!adapter.tts) throw new Error(`createAI: provider \"${spec.provider}\" does not support tts`);\n return adapter.tts({ text: input.text, voiceId, lang: input.lang, format: input.format, rate: input.rate, spec });\n },\n });\n },\n\n async embedding(input: EmbeddingInput): Promise<EmbeddingResult> {\n input = embeddingInputSchema.parse(input);\n const tier = input.tier ?? EMBEDDING_DEFAULT_TIER;\n const text = Array.isArray(input.text) ? input.text : [input.text];\n return runCapability({\n primary: resolveTier(tier, input.override, cfg.defaults, providerNames),\n fallback: input.fallback,\n capability: \"embedding\",\n tier,\n purpose: input.purpose,\n labels: input.labels,\n estIn: text.reduce((n, t) => n + estTokens(t), 0),\n estOut: 0,\n invoke: async (spec) => {\n const adapter = pickProvider(spec.provider);\n if (!adapter.embedding) throw new Error(`createAI: provider \"${spec.provider}\" does not support embedding`);\n return adapter.embedding({ input: text, spec });\n },\n });\n },\n\n async transcribe(input: TranscribeInput): Promise<TranscribeResult> {\n input = transcribeInputSchema.parse(input);\n const audio = await resolveAudio(input.audio);\n return runCapability({\n primary: mergeUnguarded(DEFAULT_TRANSCRIBE_SPEC, input.override, \"routes by voice, not by model — the adapter never sends spec.model\"),\n fallback: input.fallback,\n capability: \"transcribe\",\n purpose: input.purpose,\n labels: input.labels,\n estIn: 0,\n estOut: 0,\n invoke: async (spec) => {\n const adapter = pickProvider(spec.provider);\n if (!adapter.transcribe) throw new Error(`createAI: provider \"${spec.provider}\" does not support transcribe`);\n const timestamps =\n input.timestamps === undefined\n ? undefined\n : Array.isArray(input.timestamps)\n ? input.timestamps\n : [input.timestamps];\n return adapter.transcribe({ audio, language: input.language, durationSec: input.durationSec, phrases: input.phrases, timestamps, spec });\n },\n });\n },\n\n batch: {\n async submit(input: { requests: BatchRequestItem[]; override?: TierSpec }): Promise<BatchJob> {\n const spec = withOverride(DEFAULT_BATCH_SPEC, input.override, \"batch\");\n const adapter = pickProvider(spec.provider);\n if (!adapter.batchSubmit) throw new Error(`createAI: provider \"${spec.provider}\" does not support batch`);\n return adapter.batchSubmit({ items: input.requests, spec });\n },\n async status(jobId: string, override?: TierSpec): Promise<BatchJob> {\n const spec = withOverride(DEFAULT_BATCH_SPEC, override, \"batch.status\");\n const adapter = pickProvider(spec.provider);\n if (!adapter.batchStatus) throw new Error(`createAI: provider \"${spec.provider}\" does not support batch`);\n return adapter.batchStatus({ jobId, spec });\n },\n async results(jobId: string, override?: TierSpec): Promise<BatchResultItem[]> {\n const spec = withOverride(DEFAULT_BATCH_SPEC, override, \"batch.results\");\n const adapter = pickProvider(spec.provider);\n if (!adapter.batchResults) throw new Error(`createAI: provider \"${spec.provider}\" does not support batch`);\n return adapter.batchResults({ jobId, spec });\n },\n },\n\n // Replaced below with the real prompt-contracts (needs the client itself).\n contracts: undefined as unknown as AiClient[\"contracts\"],\n };\n\n client.contracts = makeContracts(client);\n return client;\n}\n","// Stub provider adapters (F2.5). They satisfy ProviderAdapter so the client wires\n// up and resolves without real network calls. Real implementations land in F4\n// (anthropic/openai/gemini/openrouter/deepinfra) and F5.3 (fal image). The stub\n// usage carries zero tokens/cost — F3.1 fills real numbers in the live adapters.\nimport type {\n ProviderAdapter,\n ChatRequest,\n ChatResult,\n ImageRequest,\n ImageResult,\n EmbeddingRequest,\n EmbeddingResult,\n Usage,\n Capability,\n} from \"../types.js\";\n\nfunction stubUsage(\n provider: string,\n model: string,\n transport: \"http\" | \"subprocess\",\n capability: Capability,\n): Usage {\n return {\n provider,\n model,\n // Stubs answer no network, so there is no endpoint whose residency we could\n // report. \"unknown\" is the truthful reading — not a placeholder \"eu\".\n region: \"unknown\",\n transport,\n inputTokens: 0,\n outputTokens: 0,\n cacheReadTokens: 0,\n cacheCreationTokens: 0,\n costUsd: 0,\n latencyMs: 0,\n capability,\n // ts is supplied by the caller-side at real call time; stub uses a fixed marker\n // ('' avoids Date.now() — keeps the stub pure/deterministic for tests).\n ts: \"\",\n };\n}\n\nfunction lastUserText(req: ChatRequest): string {\n for (let i = req.messages.length - 1; i >= 0; i--) {\n const m = req.messages[i];\n if (m && m.role === \"user\") {\n return typeof m.content === \"string\"\n ? m.content\n : m.content.map((p) => (p.type === \"text\" ? p.text : \"[image]\")).join(\" \");\n }\n }\n return \"\";\n}\n\n/** Anthropic adapter stub (HTTP path). */\nexport const anthropicApiAdapter: ProviderAdapter = {\n name: \"anthropic\",\n async chat(req: ChatRequest): Promise<ChatResult> {\n return {\n text: `[stub:anthropic-api] ${lastUserText(req)}`,\n usage: stubUsage(\"anthropic\", req.spec.model, \"http\", \"chat\"),\n };\n },\n async vision(req: ChatRequest): Promise<ChatResult> {\n return {\n text: `[stub:anthropic-api:vision] ${lastUserText(req)}`,\n usage: stubUsage(\"anthropic\", req.spec.model, \"http\", \"vision\"),\n };\n },\n};\n\n/** Anthropic adapter stub (subprocess / `claude -p` path). */\nexport const anthropicSubprocessAdapter: ProviderAdapter = {\n name: \"anthropic\",\n async chat(req: ChatRequest): Promise<ChatResult> {\n const usage = stubUsage(\"anthropic\", req.spec.model, \"subprocess\", \"chat\");\n usage.subprocess = true;\n return { text: `[stub:anthropic-subprocess] ${lastUserText(req)}`, usage };\n },\n};\n\n/** Mistral adapter stub — covers the default text/vision tiers (F030: fast/smart/\n * powerful/vision/cheap all default to Mistral EU after the Anthropic phase-out). */\nexport const mistralStubAdapter: ProviderAdapter = {\n name: \"mistral\",\n async chat(req: ChatRequest): Promise<ChatResult> {\n return {\n text: `[stub:mistral] ${lastUserText(req)}`,\n usage: stubUsage(\"mistral\", req.spec.model, \"http\", \"chat\"),\n };\n },\n async vision(req: ChatRequest): Promise<ChatResult> {\n return {\n text: `[stub:mistral:vision] ${lastUserText(req)}`,\n usage: stubUsage(\"mistral\", req.spec.model, \"http\", \"vision\"),\n };\n },\n};\n\n/** OpenAI adapter stub — covers the embedding default tier + a chat fallback. */\nexport const openaiStubAdapter: ProviderAdapter = {\n name: \"openai\",\n async chat(req: ChatRequest): Promise<ChatResult> {\n return {\n text: `[stub:openai] ${lastUserText(req)}`,\n usage: stubUsage(\"openai\", req.spec.model, \"http\", \"chat\"),\n };\n },\n async embedding(req: EmbeddingRequest): Promise<EmbeddingResult> {\n return {\n vectors: req.input.map(() => [0, 0, 0]),\n usage: stubUsage(\"openai\", req.spec.model, \"http\", \"embedding\"),\n };\n },\n};\n\n/** fal.ai adapter stub — image generation (real one in fal.ts, F5.3). */\nexport const falStubAdapter: ProviderAdapter = {\n name: \"fal\",\n async image(req: ImageRequest): Promise<ImageResult> {\n return {\n url: `https://stub.fal/${encodeURIComponent(req.prompt).slice(0, 32)}.png`,\n usage: stubUsage(\"fal\", req.spec.model, \"http\", \"image\"),\n };\n },\n};\n\n/** Stub provider registry — deterministic, no network. Used by tests via\n * createAI({ providers: stubProviders }). The real default registry (registry.ts)\n * wires the live adapters. */\nexport const stubProviders: Record<string, ProviderAdapter> = {\n anthropic: anthropicApiAdapter,\n mistral: mistralStubAdapter,\n openai: openaiStubAdapter,\n fal: falStubAdapter,\n};\n","// F022 — async, off-the-hot-path availability refresh. The host runs this\n// out-of-band (a timer / at idle); it mutates the registry overlay so the next\n// synchronous resolveModel() sees overnight changes like the 2026-06-12 Fable /\n// Mythos suspension. NEVER on the resolve hot path. Never hard-fails the SDK:\n// a network/auth error keeps the curated defaults.\nimport { providerIds, setAvailability } from \"./registry.js\";\n\nexport interface RefreshOptions {\n /** Only \"anthropic\" is wired in v1 (where the incident hit). */\n provider?: \"anthropic\";\n /** Injectable for tests. Defaults to global fetch. */\n fetch?: typeof fetch;\n /** Defaults to process.env.ANTHROPIC_API_KEY. */\n apiKey?: string;\n /** Min ms between live fetches for a provider (default 1h). */\n ttlMs?: number;\n /** Injectable clock for deterministic TTL tests. Defaults to Date.now(). */\n now?: number;\n}\n\nexport interface RefreshResult {\n refreshed: boolean;\n checked: number;\n markedUnavailable: string[];\n}\n\nconst NOT_REFRESHED: RefreshResult = { refreshed: false, checked: 0, markedUnavailable: [] };\nconst DEFAULT_TTL_MS = 60 * 60 * 1000; // 1h\nconst ANTHROPIC_MODELS_URL = \"https://api.anthropic.com/v1/models\";\n\n/** Last successful live fetch per provider, for TTL short-circuiting. */\nconst lastRefreshAt = new Map<string, number>();\n\n/** Reset the TTL bookkeeping. For tests. */\nexport function resetRefreshState(): void {\n lastRefreshAt.clear();\n}\n\ninterface AnthropicModelsResponse {\n data?: { id?: string }[];\n}\n\n/**\n * Reconcile tracked models against the provider's live list. For Anthropic:\n * GET /v1/models — any tracked anthropic id NOT in the live set is marked\n * unavailable; ids present are (re)marked available. TTL-cached; a fetch within\n * the window is a no-op. Returns { refreshed:false } on any error or missing key.\n */\nexport async function refreshAvailability(opts: RefreshOptions = {}): Promise<RefreshResult> {\n const provider = opts.provider ?? \"anthropic\";\n if (provider !== \"anthropic\") return NOT_REFRESHED;\n\n const ttl = opts.ttlMs ?? DEFAULT_TTL_MS;\n const now = opts.now ?? Date.now();\n const last = lastRefreshAt.get(provider);\n if (last !== undefined && now - last < ttl) return NOT_REFRESHED; // within TTL → skip\n\n const apiKey = opts.apiKey ?? process.env.ANTHROPIC_API_KEY;\n if (!apiKey) return NOT_REFRESHED;\n\n const f = opts.fetch ?? fetch;\n let liveIds: Set<string>;\n try {\n const res = await f(ANTHROPIC_MODELS_URL, {\n headers: { \"x-api-key\": apiKey, \"anthropic-version\": \"2023-06-01\", accept: \"application/json\" },\n });\n if (!res.ok) return NOT_REFRESHED;\n const json = (await res.json()) as AnthropicModelsResponse;\n liveIds = new Set((json.data ?? []).map((m) => m.id).filter((id): id is string => typeof id === \"string\"));\n } catch {\n return NOT_REFRESHED; // network error → keep defaults\n }\n\n // A models list that came back empty is almost certainly an API hiccup, not\n // \"every model is dead\" — don't suspend the whole provider on it.\n if (liveIds.size === 0) return NOT_REFRESHED;\n\n const tracked = providerIds(provider);\n const markedUnavailable: string[] = [];\n for (const id of tracked) {\n const live = liveIds.has(id);\n if (live) {\n setAvailability(id, true);\n } else {\n setAvailability(id, false, \"not in provider model list (live refresh)\");\n markedUnavailable.push(id);\n }\n }\n\n lastRefreshAt.set(provider, now);\n return { refreshed: true, checked: tracked.length, markedUnavailable };\n}\n","// Persistent BudgetStore backed by bun:sqlite (F7.1). The rolling total survives\n// process restarts and is shared by every process pointing at the same file, so\n// a budget ceiling is a real production guard — not a per-process counter that\n// resets on deploy. bun:sqlite is imported lazily (Node-safe import, like sqliteSink).\nimport type { BudgetStore } from \"../types.js\";\n\nexport interface SqliteBudgetStoreConfig {\n /** SQLite file path, e.g. \"./ai-budget.db\". */\n dbPath: string;\n /** Window/bucket key — use e.g. a day-stamp for a daily budget. Default \"default\". */\n key?: string;\n}\n\nexport function sqliteBudgetStore(config: SqliteBudgetStoreConfig): BudgetStore {\n const key = config.key ?? \"default\";\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let ready: Promise<any> | null = null;\n const open = async () => {\n const { Database } = await import(\"bun:sqlite\");\n const db = new Database(config.dbPath);\n db.run(\n `CREATE TABLE IF NOT EXISTS budget_spend (key TEXT PRIMARY KEY, spent_usd REAL NOT NULL DEFAULT 0)`,\n );\n return db;\n };\n\n return {\n async getSpent(): Promise<number> {\n const db = await (ready ??= open());\n const row = db\n .query(`SELECT spent_usd FROM budget_spend WHERE key = $key`)\n .get({ $key: key }) as { spent_usd: number } | null;\n return row?.spent_usd ?? 0;\n },\n async addSpent(usd: number): Promise<void> {\n const db = await (ready ??= open());\n db.run(\n `INSERT INTO budget_spend (key, spent_usd) VALUES ($key, $usd)\n ON CONFLICT(key) DO UPDATE SET spent_usd = spent_usd + $usd`,\n { $key: key, $usd: usd },\n );\n },\n };\n}\n","import type { CostSink } from \"../../types.js\";\n\n/** A sink that does nothing. The default when no costSink is configured. */\nexport const noopSink: CostSink = {\n record() {\n // intentionally empty\n },\n};\n","import type { CostSink, Usage } from \"../../types.js\";\n\n/** Fan a Usage out to several sinks. Uses allSettled so one failing sink never\n * prevents the others from recording (and never propagates to the caller). */\nexport function multiSink(sinks: CostSink[]): CostSink {\n return {\n async record(usage: Usage): Promise<void> {\n // async wrapper turns a synchronous throw in s.record into a rejected\n // promise, so allSettled isolates it (a sync throw would otherwise escape\n // the .map before allSettled ran).\n await Promise.allSettled(sinks.map(async (s) => s.record(usage)));\n },\n };\n}\n","// discordSink — posts a per-call cost embed to a Discord webhook. Secondary sink\n// (upmetricsSink is canonical); handy for repos not wired to Upmetrics or for an\n// at-a-glance spend feed. Plain fetch, no Discord SDK. Errors never propagate.\nimport type { CostSink, Usage } from \"../../types.js\";\n\nexport interface DiscordSinkConfig {\n webhookUrl: string;\n /** Skip posting paid calls below this USD threshold (anti-spam). Subprocess\n * (Max-plan free) calls always post so the \"free\" feed stays visible.\n * Default 0 → post everything. */\n minUsd?: number;\n fetch?: typeof fetch;\n onError?: (err: unknown) => void;\n}\n\nexport function discordSink(config: DiscordSinkConfig): CostSink {\n const doFetch = config.fetch ?? fetch;\n const minUsd = config.minUsd ?? 0;\n\n return {\n async record(usage: Usage): Promise<void> {\n try {\n // Skip cheap PAID calls; always show subprocess (free) calls.\n if (!usage.subprocess && usage.costUsd < minUsd) return;\n\n const costLabel = usage.subprocess\n ? \"Max plan (free)\"\n : `$${usage.costUsd.toFixed(6)}`;\n\n const embed = {\n title: `AI call — ${usage.capability}`,\n fields: [\n { name: \"Provider\", value: usage.provider, inline: true },\n { name: \"Model\", value: usage.model, inline: true },\n { name: \"Transport\", value: usage.transport, inline: true },\n { name: \"Cost\", value: costLabel, inline: true },\n {\n name: \"Tokens\",\n value: `${usage.inputTokens} in / ${usage.outputTokens} out`,\n inline: true,\n },\n { name: \"Latency\", value: `${usage.latencyMs} ms`, inline: true },\n ],\n timestamp: usage.ts || new Date().toISOString(),\n };\n\n const res = await doFetch(config.webhookUrl, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ embeds: [embed] }),\n });\n if (!res.ok) {\n config.onError?.(new Error(`discordSink: webhook returned ${res.status}`));\n }\n } catch (err) {\n config.onError?.(err);\n }\n },\n };\n}\n","// sqliteSink — persists every Usage to a local bun:sqlite DB. Secondary/offline\n// sink (upmetricsSink is canonical). No npm dependency — bun:sqlite is built in.\n//\n// IMPORTANT: bun:sqlite is imported LAZILY (dynamic import on first use), not at\n// module top level. A static `import \"bun:sqlite\"` would leak into the package\n// entry and crash every Node consumer (`ERR_UNSUPPORTED_ESM_URL_SCHEME`). With\n// the lazy import, importing @broberg/ai-sdk works everywhere; bun:sqlite only\n// loads when sqliteSink/getCostSummary actually run (Bun only).\nimport type { CostSink, Usage } from \"../../types.js\";\n\nexport interface SqliteSinkConfig {\n /** Path to the SQLite file, e.g. \"./ai-cost.db\" (or \":memory:\"). */\n dbPath: string;\n}\n\nconst CREATE_TABLE = `\nCREATE TABLE IF NOT EXISTS ai_usage (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n ts TEXT NOT NULL,\n provider TEXT NOT NULL,\n model TEXT NOT NULL,\n tier TEXT,\n transport TEXT NOT NULL,\n capability TEXT NOT NULL,\n region TEXT NOT NULL DEFAULT 'unknown',\n purpose TEXT,\n input_tokens INTEGER NOT NULL,\n output_tokens INTEGER NOT NULL,\n cache_read_tokens INTEGER NOT NULL,\n cache_creation_tokens INTEGER NOT NULL,\n cost_usd REAL NOT NULL,\n latency_ms INTEGER NOT NULL,\n subprocess INTEGER NOT NULL DEFAULT 0\n)`;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nasync function openDb(dbPath: string, readonly = false): Promise<any> {\n const { Database } = await import(\"bun:sqlite\");\n return new Database(dbPath, readonly ? { readonly: true } : undefined);\n}\n\nexport function sqliteSink(config: SqliteSinkConfig): CostSink {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let ready: Promise<any> | null = null;\n const init = async () => {\n const db = await openDb(config.dbPath);\n db.run(CREATE_TABLE);\n // CREATE TABLE IF NOT EXISTS does NOTHING to a table that already exists, so a\n // consumer with a db from an earlier version keeps the old columns and every\n // INSERT would fail on the new one. The DEFAULT means existing rows read back as\n // 'unknown' — which is the truthful answer for a call made before we recorded it,\n // not a placeholder.\n const cols = db.query(`PRAGMA table_info(ai_usage)`).all() as { name: string }[];\n if (!cols.some((c) => c.name === \"region\")) {\n db.run(`ALTER TABLE ai_usage ADD COLUMN region TEXT NOT NULL DEFAULT 'unknown'`);\n }\n const insert = db.prepare(\n `INSERT INTO ai_usage\n (ts, provider, model, tier, transport, capability, region, purpose,\n input_tokens, output_tokens, cache_read_tokens, cache_creation_tokens,\n cost_usd, latency_ms, subprocess)\n VALUES ($ts, $provider, $model, $tier, $transport, $capability, $region, $purpose,\n $input, $output, $cacheRead, $cacheCreation, $cost, $latency, $subprocess)`,\n );\n return insert;\n };\n\n return {\n async record(usage: Usage): Promise<void> {\n const insert = await (ready ??= init());\n insert.run({\n $ts: usage.ts || new Date().toISOString(),\n $provider: usage.provider,\n $model: usage.model,\n $tier: usage.tier ?? null,\n $transport: usage.transport,\n $capability: usage.capability,\n $region: usage.region,\n $purpose: usage.purpose ?? null,\n $input: usage.inputTokens,\n $output: usage.outputTokens,\n $cacheRead: usage.cacheReadTokens,\n $cacheCreation: usage.cacheCreationTokens,\n $cost: usage.costUsd,\n $latency: usage.latencyMs,\n $subprocess: usage.subprocess ? 1 : 0,\n });\n },\n };\n}\n\nexport interface CostSummary {\n totalUsd: number;\n byProvider: Record<string, number>;\n byCapability: Record<string, number>;\n}\n\n/** Aggregate the recorded spend from a sqliteSink DB. Creates the table if the\n * DB has never been written to, so an empty DB summarises cleanly to 0. */\nexport async function getCostSummary(dbPath: string): Promise<CostSummary> {\n const db = await openDb(dbPath);\n db.run(CREATE_TABLE);\n const total = db\n .query(`SELECT SUM(cost_usd) AS total FROM ai_usage`)\n .get() as { total: number | null };\n const byProvider: Record<string, number> = {};\n for (const row of db\n .query(`SELECT provider, SUM(cost_usd) AS sum FROM ai_usage GROUP BY provider`)\n .all() as { provider: string; sum: number }[]) {\n byProvider[row.provider] = row.sum;\n }\n const byCapability: Record<string, number> = {};\n for (const row of db\n .query(`SELECT capability, SUM(cost_usd) AS sum FROM ai_usage GROUP BY capability`)\n .all() as { capability: string; sum: number }[]) {\n byCapability[row.capability] = row.sum;\n }\n return { totalUsd: total?.total ?? 0, byProvider, byCapability };\n}\n","// upmetricsCostClient — the cost READ-back side, companion to upmetricsSink (the\n// write side). Upmetrics owns cost AGGREGATION (it already rolls up agent_runs):\n// this is a thin, browser-clean wrapper over its public cost read-API\n// (upmetrics/docs/COST-API.md, F014) so a consuming app reads its OWN accumulated\n// cost from the canonical source instead of re-aggregating locally.\n//\n// Money is integer micro-USD ($1 = 1_000_000); Upmetrics rounds once at the\n// response boundary so sub-cent calls aren't lost. Pure fetch, zero new deps, no\n// bun:sqlite import → safe to import from a browser/Vite build.\n\n/** Thrown when the cost read-API rejects (e.g. 401 invalid_api_key) or is unreachable. */\nexport class UpmetricsCostError extends Error {\n readonly status?: number;\n readonly code?: string;\n constructor(message: string, opts?: { status?: number; code?: string }) {\n super(message);\n this.name = \"UpmetricsCostError\";\n this.status = opts?.status;\n this.code = opts?.code;\n }\n}\n\nexport interface UpmetricsCostClientConfig {\n /** Read-API base URL, e.g. https://upmetrics.org */\n baseUrl: string;\n /** Per-project api_key (uk_…) — sent as X-Upmetrics-Key; resolves to your own project only. */\n apiKey: string;\n /** Injectable fetch for testing; defaults to global fetch. */\n fetch?: typeof fetch;\n}\n\n/** Shared filter surface for summary + timeseries (mirrors COST-API.md query params). */\nexport interface CostQuery {\n /** Relative window; ignored when from/to are given. */\n window?: \"day\" | \"week\" | \"month\";\n /** Explicit window start (ISO-8601 or epoch-ms) — overrides `window`. */\n from?: string | number;\n /** Explicit window end (ISO-8601 or epoch-ms) — overrides `window`. */\n to?: string | number;\n provider?: string;\n model?: string;\n tier?: string;\n /** Filter to one consumer (the sink's agent_name). */\n agentName?: string;\n transport?: \"http\" | \"subprocess\";\n /** Tag filters → `tag.<key>=<value>` (e.g. { tenantId: \"sanne\" }). */\n tags?: Record<string, string>;\n}\n\nexport interface CostSummaryQuery extends CostQuery {\n /** Break the total down per distinct value of this tag key (the per-tenant view). */\n groupBy?: string;\n}\n\nexport interface CostTimeseriesQuery extends CostQuery {\n /** Bucket granularity (default \"day\"). */\n bucket?: \"day\" | \"hour\";\n}\n\n/** One breakdown row, ordered by cost desc. `tier`/`capability` fall back to \"(none)\". */\nexport interface UpmetricsCostRow {\n key: string;\n micro_usd: number;\n input_tokens: number;\n output_tokens: number;\n run_count: number;\n}\n\nexport interface UpmetricsCostSummary {\n generated_at: string;\n window: { from: string; to: string };\n total_micro_usd: number;\n input_tokens: number;\n output_tokens: number;\n cache_read_tokens: number;\n cache_creation_tokens: number;\n run_count: number;\n metered: { metered_micro_usd: number; free_run_count: number };\n by_provider: UpmetricsCostRow[];\n by_model: UpmetricsCostRow[];\n by_tier: UpmetricsCostRow[];\n by_capability: UpmetricsCostRow[];\n /** Present only when `groupBy` was requested. */\n group_by?: string;\n by_group?: UpmetricsCostRow[];\n}\n\nexport interface UpmetricsCostTimeseries {\n generated_at: string;\n bucket: \"day\" | \"hour\";\n window: { from: string; to: string };\n /** Only non-zero buckets are returned — pad missing buckets yourself. */\n points: Array<{\n ts: string;\n micro_usd: number;\n input_tokens: number;\n output_tokens: number;\n run_count: number;\n }>;\n}\n\n/** Convert integer micro-USD to a USD float for display. `$1 = 1_000_000`. */\nexport const usdFromMicro = (microUsd: number): number => microUsd / 1_000_000;\n\nfunction buildQuery(q: CostQuery & { groupBy?: string; bucket?: string }): string {\n const p = new URLSearchParams();\n if (q.bucket) p.set(\"bucket\", q.bucket);\n if (q.from !== undefined) p.set(\"from\", String(q.from));\n if (q.to !== undefined) p.set(\"to\", String(q.to));\n // `window` is ignored server-side when from/to are present; only send it otherwise.\n if (q.window && q.from === undefined && q.to === undefined) p.set(\"window\", q.window);\n if (q.provider) p.set(\"provider\", q.provider);\n if (q.model) p.set(\"model\", q.model);\n if (q.tier) p.set(\"tier\", q.tier);\n if (q.agentName) p.set(\"agent_name\", q.agentName);\n if (q.transport) p.set(\"transport\", q.transport);\n if (q.groupBy) p.set(\"groupBy\", q.groupBy);\n for (const [k, v] of Object.entries(q.tags ?? {})) p.set(`tag.${k}`, v);\n const s = p.toString();\n return s ? `?${s}` : \"\";\n}\n\nexport function upmetricsCostClient(config: UpmetricsCostClientConfig): {\n summary(query?: CostSummaryQuery): Promise<UpmetricsCostSummary>;\n timeseries(query?: CostTimeseriesQuery): Promise<UpmetricsCostTimeseries>;\n} {\n const doFetch = config.fetch ?? fetch;\n const base = config.baseUrl.replace(/\\/$/, \"\");\n\n async function get<T>(path: string, query: string): Promise<T> {\n let res: Response;\n try {\n res = await doFetch(`${base}${path}${query}`, {\n method: \"GET\",\n headers: { \"X-Upmetrics-Key\": config.apiKey },\n });\n } catch (err) {\n throw new UpmetricsCostError(\n `upmetricsCostClient: ${path} unreachable: ${(err as Error)?.message ?? String(err)}`,\n );\n }\n if (!res.ok) {\n let code: string | undefined;\n const text = await res.text().catch(() => \"\");\n try {\n code = (JSON.parse(text) as { error?: string }).error;\n } catch {\n /* non-JSON error body */\n }\n throw new UpmetricsCostError(\n `upmetricsCostClient: ${path} returned ${res.status}${code ? ` (${code})` : \"\"}`,\n { status: res.status, code },\n );\n }\n return (await res.json()) as T;\n }\n\n return {\n summary(query: CostSummaryQuery = {}): Promise<UpmetricsCostSummary> {\n return get<UpmetricsCostSummary>(\"/api/cost/summary\", buildQuery(query));\n },\n timeseries(query: CostTimeseriesQuery = {}): Promise<UpmetricsCostTimeseries> {\n return get<UpmetricsCostTimeseries>(\"/api/cost/timeseries\", buildQuery(query));\n },\n };\n}\n"],"mappings":"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","names":["url","mimeType","data","listVoices","DEFAULT_REGION","EU_BASE","sleep","res"]}
|
|
1
|
+
{"version":3,"sources":["../src/transport/http.ts","../src/transport/subprocess.ts","../src/transport/stream.ts","../src/providers/tools.ts","../src/cost/region.ts","../src/cost/usage.ts","../src/providers/anthropic.ts","../src/providers/openai-compatible.ts","../src/providers/openai.ts","../src/providers/media.ts","../src/providers/gemini.ts","../src/providers/deepinfra.ts","../src/providers/openrouter.ts","../src/providers/requesty.ts","../src/providers/deepseek.ts","../src/providers/mistral.ts","../src/providers/elevenlabs.ts","../src/providers/azure.ts","../src/providers/vertex.ts","../src/providers/deepl.ts","../src/providers/fal.ts","../src/providers/bfl.ts","../src/providers/registry.ts","../src/cost/budget.ts","../src/capabilities/vision.ts","../src/capabilities/video.ts","../src/capabilities/translate.ts","../src/capabilities/embedding.ts","../src/capabilities/transcribe.ts","../src/capabilities/contracts/index.ts","../src/voices/registry.ts","../src/voices/types.ts","../src/voices/resolve.ts","../src/schema/inputs.ts","../src/version.ts","../src/cost/sinks/upmetrics.ts","../src/client.ts","../src/providers/stub.ts","../src/availability/refresh.ts","../src/cost/budget-store.ts","../src/cost/sinks/noop.ts","../src/cost/sinks/multi.ts","../src/cost/sinks/discord.ts","../src/cost/sinks/sqlite.ts","../src/cost/upmetrics-read.ts"],"sourcesContent":["// HTTP transport: a thin fetch wrapper. Provider-agnostic — the adapter supplies\n// the fully-built url/headers/body and parses the returned json itself.\nimport type { TransportRequest, HttpResponse } from \"./types.js\";\n\nexport async function httpTransport(req: TransportRequest): Promise<HttpResponse> {\n if (!req.http) {\n throw new Error(\"httpTransport: req.http is required for http transport\");\n }\n const { url, method = \"POST\", headers, body } = req.http;\n const res = await fetch(url, {\n method,\n headers,\n body:\n body === undefined\n ? undefined\n : typeof body === \"string\"\n ? body\n : JSON.stringify(body),\n });\n // Read the body ONCE as text, then try to parse it. Reading .json() directly\n // discarded the body whenever it would not parse — so the very case errorBody was\n // written for (an HTML 502 from a gateway) produced \"(no body)\" and the outage page\n // we wanted to show was already gone. Keeping the text costs nothing and is the\n // difference between a debuggable message and a status code.\n const text = await res.text().catch(() => \"\");\n let json: unknown;\n try {\n json = text ? JSON.parse(text) : undefined;\n } catch {\n json = undefined;\n }\n return { ok: res.ok, status: res.status, json, text };\n}\n\n/** Render a provider error body for an exception message, without ever throwing.\n *\n * F043. `httpTransport` sets `json` to undefined when the response body is not JSON\n * — an HTML 502 from a gateway, a proxy timeout page, an empty body. Four adapters\n * then wrote `JSON.stringify(res.json).slice(0, 300)`, and JSON.stringify(undefined)\n * returns undefined rather than a string, so the ERROR HANDLER crashed with\n * \"Cannot read properties of undefined (reading 'slice')\" — replacing a useful\n * \"502 <gateway page>\" with a TypeError that pointed nowhere near the real cause.\n * Reported by cms via components (#24152) as a one-off they could not reproduce;\n * it is not rare behaviour, it is a rare RESPONSE.\n *\n * Same family as the two other faults measured that day: a missing value degrading\n * into something that does not look like a missing value. Here it must look like one. */\nexport function errorBody(json: unknown, rawText?: string): string {\n const fallback = rawText && rawText.trim() ? rawText.slice(0, 300) : \"(no body)\";\n if (json === undefined || json === null) return fallback;\n if (typeof json === \"string\") return json.slice(0, 300);\n try {\n return (JSON.stringify(json) ?? fallback).slice(0, 300);\n } catch {\n return fallback; // circular / non-serialisable — still must not throw\n }\n}\n","// Subprocess transport: runs the local `claude -p` CLI (Anthropic Max plan).\n// No API key, no metered charge — costUsd is always 0, flagged subprocess:true so\n// dashboards can split free (Max) from paid (API). Token counts still come back\n// from the CLI's JSON so usage is tracked even when cost is zero.\nimport type { TransportRequest, SubprocessResponse } from \"./types.js\";\n\n/** The subset of `claude -p --output-format json` output we read. The CLI emits\n * more fields; we only need the result text + token usage. */\ninterface ClaudeCliJson {\n result?: string;\n usage?: {\n input_tokens?: number;\n output_tokens?: number;\n cache_creation_input_tokens?: number;\n cache_read_input_tokens?: number;\n };\n}\n\n/** Pure parser for the `claude -p --output-format json` stdout. Exported so it\n * can be unit-tested without spawning the binary. costUsd is pinned to 0. */\nexport function parseClaudeCliJson(raw: string): SubprocessResponse {\n let parsed: ClaudeCliJson;\n try {\n parsed = JSON.parse(raw) as ClaudeCliJson;\n } catch {\n throw new Error(\n `subprocessTransport: could not parse claude -p JSON output: ${raw.slice(0, 200)}`,\n );\n }\n const u = parsed.usage ?? {};\n return {\n text: parsed.result ?? \"\",\n inputTokens: u.input_tokens ?? 0,\n outputTokens: u.output_tokens ?? 0,\n cacheReadTokens: u.cache_read_input_tokens ?? 0,\n cacheCreationTokens: u.cache_creation_input_tokens ?? 0,\n costUsd: 0,\n subprocess: true,\n };\n}\n\nexport async function subprocessTransport(\n req: TransportRequest,\n): Promise<SubprocessResponse> {\n if (!req.subprocess) {\n throw new Error(\"subprocessTransport: req.subprocess is required for subprocess transport\");\n }\n const { prompt, systemPrompt } = req.subprocess;\n\n const cmd = [\"claude\", \"-p\", \"--output-format\", \"json\", \"--model\", req.spec.model];\n if (systemPrompt) cmd.push(\"--system-prompt\", systemPrompt);\n\n // Prompt goes in on stdin as a Blob (no argv length limit, no manual FileSink).\n const proc = (() => {\n try {\n return Bun.spawn(cmd, {\n stdin: new Blob([prompt]),\n stdout: \"pipe\",\n stderr: \"pipe\",\n });\n } catch (err) {\n throw new Error(\n `subprocessTransport: failed to spawn 'claude' — is the CLI installed and on PATH? (${String(err)})`,\n );\n }\n })();\n\n const [stdout, stderr, exitCode] = await Promise.all([\n new Response(proc.stdout).text(),\n new Response(proc.stderr).text(),\n proc.exited,\n ]);\n\n if (exitCode !== 0) {\n throw new Error(\n `subprocessTransport: claude -p exited ${exitCode}: ${stderr.slice(0, 300) || stdout.slice(0, 300)}`,\n );\n }\n\n return parseClaudeCliJson(stdout);\n}\n","// SSE streaming transport (F8.1). Like httpTransport but yields the parsed\n// `data:` payloads from the response body instead of awaiting .json() — pure\n// fetch + a ReadableStream reader, so it is Node 18+ and Bun safe. The adapter\n// supplies the `stream:true` body and parses each yielded JSON string itself.\nimport type { TransportRequest } from \"./types.js\";\n\n/** HTTP error from a streaming connect — carries `status` so the client's\n * pre-stream fallback can tell an eligible 429/5xx from a hard 4xx. */\nexport class StreamHttpError extends Error {\n readonly status: number;\n constructor(message: string, status: number) {\n super(message);\n this.name = \"StreamHttpError\";\n this.status = status;\n }\n}\n\nexport interface StreamTransportRequest extends TransportRequest {\n /** Injectable fetch for tests. */\n fetch?: typeof fetch;\n}\n\n/**\n * Open an SSE stream and yield each event's `data:` payload as a raw string\n * (the JSON after `data: `), skipping the `[DONE]` terminator and non-data\n * lines. Throws StreamHttpError before the first yield on a non-2xx connect.\n */\nexport async function* streamTransport(req: StreamTransportRequest): AsyncIterable<string> {\n if (!req.http) throw new Error(\"streamTransport: req.http is required for http transport\");\n const { url, method = \"POST\", headers, body } = req.http;\n const fetchImpl = req.fetch ?? fetch;\n const res = await fetchImpl(url, {\n method,\n headers,\n body:\n body === undefined\n ? undefined\n : typeof body === \"string\"\n ? body\n : JSON.stringify(body),\n });\n if (!res.ok || !res.body) {\n const text = await res.text().catch(() => \"\");\n throw new StreamHttpError(`stream ${res.status}: ${text.slice(0, 300)}`, res.status);\n }\n const reader = res.body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n // OpenAI/Anthropic emit one `data: {json}\\n\\n` per event — parse per line.\n let nl: number;\n while ((nl = buffer.indexOf(\"\\n\")) >= 0) {\n const line = buffer.slice(0, nl).replace(/\\r$/, \"\");\n buffer = buffer.slice(nl + 1);\n if (!line.startsWith(\"data:\")) continue; // skip comments / event: / id:\n const data = line.slice(5).trim();\n if (data === \"[DONE]\") return;\n if (data) yield data;\n }\n }\n } finally {\n reader.releaseLock();\n }\n}\n","// Cross-provider tool/function-calling normalization. The SDK speaks one Tool /\n// ToolCall shape; each provider has its own. toProviderTools builds the request\n// tools array; fromProviderToolCall parses one tool-call out of a response.\n// OpenAI, DeepInfra and OpenRouter share the OpenAI-compatible format.\nimport type { ToolCallLike, Tool, ToolCall } from \"../types.js\";\n\ntype ToolProvider = \"openai\" | \"deepinfra\" | \"openrouter\" | \"gemini\" | \"anthropic\";\n\nfunction family(provider: string): ToolProvider {\n if (provider === \"gemini\" || provider === \"google\") return \"gemini\";\n if (provider === \"anthropic\") return \"anthropic\";\n // openai, deepinfra, openrouter — all OpenAI-compatible\n return \"openai\";\n}\n\n/** Convert SDK tools to a provider's request format. */\nexport function toProviderTools(tools: Tool[], provider: string): unknown {\n switch (family(provider)) {\n case \"openai\":\n return tools.map((t) => ({\n type: \"function\",\n function: { name: t.name, description: t.description, parameters: t.parameters },\n }));\n case \"gemini\":\n return [\n {\n functionDeclarations: tools.map((t) => ({\n name: t.name,\n description: t.description,\n parameters: t.parameters,\n })),\n },\n ];\n case \"anthropic\":\n return tools.map((t) => ({\n name: t.name,\n description: t.description,\n input_schema: t.parameters,\n }));\n default:\n throw new Error(`toProviderTools: unsupported provider family for \"${provider}\"`);\n }\n}\n\n/** Parse a single provider-shaped tool call back into the SDK ToolCall shape. */\nexport function fromProviderToolCall(raw: unknown, provider: string): ToolCall {\n const r = raw as Record<string, unknown>;\n switch (family(provider)) {\n case \"openai\": {\n // { id, type:\"function\", function:{ name, arguments:\"<json>\" } }\n const fn = (r.function ?? {}) as { name?: string; arguments?: string };\n return {\n id: typeof r.id === \"string\" ? r.id : \"\",\n name: fn.name ?? \"\",\n arguments: parseArgs(fn.arguments),\n };\n }\n case \"gemini\": {\n // { functionCall:{ name, args } } or { name, args }\n const fc = (r.functionCall ?? r) as { name?: string; args?: unknown };\n return {\n id: \"\", // Gemini function calls have no id\n name: fc.name ?? \"\",\n arguments: (fc.args as Record<string, unknown>) ?? {},\n };\n }\n case \"anthropic\": {\n // { type:\"tool_use\", id, name, input }\n return {\n id: typeof r.id === \"string\" ? r.id : \"\",\n name: typeof r.name === \"string\" ? r.name : \"\",\n arguments: (r.input as Record<string, unknown>) ?? {},\n };\n }\n default:\n throw new Error(`fromProviderToolCall: unsupported provider family for \"${provider}\"`);\n }\n}\n\nfunction parseArgs(raw: unknown): Record<string, unknown> {\n if (raw === undefined || raw === null) return {};\n if (typeof raw === \"object\") return raw as Record<string, unknown>;\n if (typeof raw === \"string\") {\n try {\n return JSON.parse(raw) as Record<string, unknown>;\n } catch {\n return {};\n }\n }\n return {};\n}\n\n/** Read a tool call's arguments regardless of which spelling the caller used.\n * `arguments` is ours and wins; `args` is what @broberg/chat emits. See ToolCallLike\n * in types.ts for why both are accepted rather than one of us renaming. */\nexport function toolCallArgs(tc: ToolCallLike): Record<string, unknown> {\n return tc.arguments ?? tc.args ?? {};\n}\n","// F042 — where did the data actually go?\n//\n// The obvious implementation of this file is a table keyed on provider name, and it\n// would LIE for three of our adapters in the direction that matters. vertex, azure and\n// bfl are EU by default and by intent — that is why they exist — but each takes an\n// override (a GCP region, an Azure region, a base URL), so a consumer can point them\n// outside the EU while the provider name stays the same. A residency field that is\n// right by default and wrong precisely when someone changed something is worse than no\n// field at all, because it gets trusted.\n//\n// So the rule here is: the region is a property of the ENDPOINT WE CALLED. For the\n// adapters whose host is fixed in code, that derivation collapses to a constant (this\n// file). For the three that vary, the adapter passes the locator it actually used.\n\n/** Coarse data-residency of the endpoint a call went to.\n *\n * - `\"eu\"` — EU/EEA. **The only positive residency claim.** Nothing else is folded\n * in: an adequacy decision is not EU residency, so the UK, Switzerland\n * and Canada are deliberately NOT `\"eu\"` here.\n * - `\"us\"` — United States.\n * - `\"cn\"` — China.\n * - `\"unknown\"` — we genuinely cannot say: an aggregator that picks its own upstream,\n * or a region string we do not recognise.\n *\n * **`\"unknown\"` is NOT a synonym for safe.** `region !== \"us\"` is not an EU check —\n * it passes every OpenRouter call. Only `region === \"eu\"` may be treated as EU-resident.\n */\nexport type Region = \"eu\" | \"us\" | \"cn\" | \"unknown\";\n\n/** Region by HOST — the primary derivation, because it reads the thing that actually\n * decides: the URL we are about to call.\n *\n * The first version of this module keyed on provider NAME and carved out three\n * adapters as \"the configurable ones\". That carve-out was wrong: `mistralAdapter`\n * and `deeplAdapter` also take a `baseUrl`, so pointing Mistral — our designated\n * personal-data route — at a non-EU gateway still reported `region: \"eu\"`. A false\n * EU claim, in the module written to prevent false EU claims. Found in review of\n * F042 itself, which is the honest place to record it.\n *\n * An unlisted host is \"unknown\", never a guess: a custom gateway is exactly the case\n * where we cannot know, and the whole contract is that only \"eu\" is a claim. */\nconst HOST_REGION: Record<string, Region> = {\n \"api.mistral.ai\": \"eu\",\n \"api.deepl.com\": \"eu\",\n \"api-free.deepl.com\": \"eu\",\n \"api.eu.bfl.ai\": \"eu\",\n \"api.openai.com\": \"us\",\n \"api.anthropic.com\": \"us\",\n \"api.deepinfra.com\": \"us\",\n \"generativelanguage.googleapis.com\": \"us\",\n \"api.elevenlabs.io\": \"us\",\n \"fal.run\": \"us\",\n \"queue.fal.run\": \"us\",\n \"api.deepseek.com\": \"cn\",\n // Aggregators: the host is theirs, the upstream is not ours to know.\n \"openrouter.ai\": \"unknown\",\n \"router.requesty.ai\": \"unknown\",\n};\n\n/** Region of the endpoint a call will actually hit. Never throws — a residency\n * reading must not be able to break a call that already succeeded. */\nexport function regionOfHost(hostOrUrl: string | undefined): Region {\n if (!hostOrUrl) return \"unknown\";\n // A BARE HOSTNAME IS VALID INPUT. The first version required a full URL, so\n // regionOfHost(\"api.mistral.ai\") — the most natural thing to hand a function with\n // that name — answered \"unknown\", and a fail-closed guard built on it rejected\n // EVERYTHING including the one EU route. Found by components immediately after we\n // shipped the warning about the same trap in regionOfProvider: we fixed the\n // name-keyed function and left the host-keyed one with the identical shape.\n const trimmed = hostOrUrl.trim();\n if (!trimmed) return \"unknown\";\n let host = \"\";\n try {\n host = new URL(trimmed).host;\n } catch {\n /* not a URL — handled below */\n }\n // A SUCCESSFUL PARSE IS NOT A USABLE HOST. new URL(\"api.mistral.ai:443\") does NOT\n // throw: it reads \"api.mistral.ai:\" as a SCHEME and \"443\" as the path, and hands back\n // host === \"\". So the catch never ran and the answer was \"unknown\" — a call that\n // succeeded and told us nothing, which is the shape this whole module keeps removing.\n // Falling through on an empty host is the difference between \"parsed\" and \"answered\".\n if (!host) {\n // Read it as a host: take only the authority, so \"api.mistral.ai/v1\" and\n // \"api.mistral.ai:443\" both resolve, and drop any credentials before the @.\n host = trimmed.split(\"/\")[0]!.split(\"@\").pop()!.split(\":\")[0]!;\n }\n host = host.toLowerCase();\n // Exact match only — never a suffix test. \"api.mistral.ai.evil.com\" must not inherit\n // Mistral's EU claim, and an endsWith() check is how that would happen.\n return Object.hasOwn(HOST_REGION, host) ? (HOST_REGION[host] as Region) : \"unknown\";\n}\n\n/** Adapters whose endpoint is FIXED in code — there is no config that moves them, so\n * the provider name IS the region. Anything absent here must pass its region\n * explicitly; the fallback is `\"unknown\"`, never a guess in the reassuring direction. */\nconst FIXED_PROVIDER_REGION: Record<string, Region> = {\n // NB: mistral and deepl are deliberately ABSENT — both take a config.baseUrl, so\n // their region is a property of the URL, not of the name. They derive via\n // regionOfHost. Anything left here genuinely cannot be moved by config.\n openai: \"us\",\n anthropic: \"us\",\n // generativelanguage.googleapis.com is Google's GLOBAL endpoint, not a US-pinned one.\n // We report \"us\" rather than \"unknown\" because it is certainly not EU-resident, and\n // the honest error direction for a residency field is away from an EU claim. Vertex\n // (below, region-pinned) is the route to use when EU residency is required.\n gemini: \"us\",\n deepinfra: \"us\",\n fal: \"us\",\n elevenlabs: \"us\",\n // api.deepseek.com — People's Republic of China. No EU adequacy decision at all,\n // which is a materially different position from the US, hence its own value.\n deepseek: \"cn\",\n // Aggregators: they choose the upstream provider per request, so the region is not\n // ours to know. Reporting anything else here would be inventing a fact.\n openrouter: \"unknown\",\n requesty: \"unknown\",\n};\n\n/** GCP + Azure region names we recognise as EU/EEA. Norway is EEA and counts.\n * Switzerland and the UK are deliberately absent — adequate, but not EU/EEA. */\nconst EU_REGION_NAMES = new Set([\n // Azure\n \"westeurope\",\n \"northeurope\",\n \"swedencentral\",\n \"francecentral\",\n \"francesouth\",\n \"germanywestcentral\",\n \"germanynorth\",\n \"norwayeast\",\n \"norwaywest\",\n \"polandcentral\",\n \"italynorth\",\n \"spaincentral\",\n]);\n\nconst US_REGION_NAMES = new Set([\n // Azure\n \"eastus\",\n \"eastus2\",\n \"westus\",\n \"westus2\",\n \"westus3\",\n \"centralus\",\n \"northcentralus\",\n \"southcentralus\",\n \"westcentralus\",\n]);\n\n/** Classify a provider REGION STRING — a Vertex/GCP location like `europe-west1`, or\n * an Azure region like `westeurope`. Anything unrecognised is `\"unknown\"`: a region\n * name we have never seen is exactly the case where guessing is most tempting and\n * least defensible. Never throws — a residency reading must not be able to break a\n * call that already succeeded. */\nexport function classifyRegionName(name: string | undefined): Region {\n if (!name) return \"unknown\";\n const n = name.trim().toLowerCase();\n if (!n) return \"unknown\";\n // A Region value passed straight back in. \"eu\" is what this function RETURNS and\n // what a consumer compares against, so handing it in is the obvious mistake — and\n // answering \"unknown\" to \"eu\" is the kind of confident wrong answer this module\n // keeps having to remove. Identity is the honest reply.\n if (n === \"eu\" || n === \"us\" || n === \"cn\" || n === \"unknown\") return n as Region;\n // GCP-style: europe-west1, europe-north1, us-central1, …\n if (n.startsWith(\"europe-\")) return \"eu\";\n if (n.startsWith(\"us-\")) return \"us\";\n if (EU_REGION_NAMES.has(n)) return \"eu\";\n if (US_REGION_NAMES.has(n)) return \"us\";\n return \"unknown\";\n}\n\n/** Region for an adapter whose endpoint is fixed. Unknown provider → `\"unknown\"`.\n *\n * **DO NOT BUILD A RESIDENCY GUARD ON THIS.** Use {@link regionOfHost} on the base URL\n * the call will actually use. Found by a consumer building exactly that guard (super,\n * 2026-08-30): `regionOfProvider(\"mistral\")` is `\"unknown\"` — correct, because Mistral\n * takes a `baseUrl` and a name cannot answer for residency — but a guard written as\n * `regionOfProvider(p) === \"eu\"` therefore REJECTS Mistral, which is the only EU route\n * we have. It fails closed and is useless: it filters out the thing it exists to allow.\n *\n * The trap is invisible from the signature, which is why it is written here rather than\n * only in the docs. This function answers \"is this provider's endpoint fixed, and where\n * is it?\" — a narrower question than \"where will my call go?\". */\nexport function regionOfProvider(provider: string): Region {\n // Object.hasOwn, NOT a bare lookup + ??. A plain object inherits from\n // Object.prototype, so FIXED_PROVIDER_REGION[\"constructor\"] returns a FUNCTION and\n // the ?? fallback never fires — putting a function where a Region belongs. It fails\n // safe against `region === \"eu\"`, but it serialises to nothing, so a cost sink would\n // record a Usage with no region at all: a missing value that does not look like one,\n // in the very feature built to stop that. Not reachable today (every caller passes a\n // hardcoded adapter name) — fixed because \"not reachable yet\" is not a property we\n // control from here.\n return Object.hasOwn(FIXED_PROVIDER_REGION, provider)\n ? (FIXED_PROVIDER_REGION[provider] as Region)\n : \"unknown\";\n}\n","// Usage construction + cost computation. Real adapters (F4) build their Usage via\n// freshUsage() and fill costUsd from computeCost(). The pricing table lives in\n// ./pricing.ts (F3.6); until a model is priced, computeCost returns 0 so calls\n// still complete (cost just shows $0 rather than throwing).\nimport { getPrice } from \"./pricing.js\";\nimport { regionOfProvider, type Region } from \"./region.js\";\nimport type { Usage, Transport, Capability } from \"../types.js\";\n\n/**\n * Cost in USD for a call. cache-read/creation tokens are priced separately when\n * the pricing entry defines rates for them; otherwise they fall back to the\n * input rate (read) / are ignored (creation). Unknown model → 0.\n */\nexport function computeCost(\n provider: string,\n model: string,\n inputTokens: number,\n outputTokens: number,\n cacheReadTokens = 0,\n cacheCreationTokens = 0,\n): number {\n const price = getPrice(provider, model);\n if (!price) return 0;\n const perToken = (per1M: number) => per1M / 1_000_000;\n const inRate = perToken(price.inputPer1M);\n const outRate = perToken(price.outputPer1M);\n const cacheReadRate =\n price.cacheReadPer1M !== undefined ? perToken(price.cacheReadPer1M) : inRate;\n const cacheWriteRate =\n price.cacheWritePer1M !== undefined ? perToken(price.cacheWritePer1M) : inRate;\n return (\n inputTokens * inRate +\n outputTokens * outRate +\n cacheReadTokens * cacheReadRate +\n cacheCreationTokens * cacheWriteRate\n );\n}\n\n/** Build a Usage with cost computed from the pricing table. Adapters call this\n * after a successful provider call; latencyMs/ts/capability are stamped by the\n * client (call-context owner), so they default to 0/\"\"/the passed capability. */\nexport function freshUsage(args: {\n provider: string;\n model: string;\n transport: Transport;\n capability: Capability;\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens?: number;\n cacheCreationTokens?: number;\n /** Data residency of the endpoint this call ACTUALLY used (F042). Pass it from any\n * adapter whose region a consumer can change — vertex, azure, bfl. Omitting it\n * falls back to the fixed provider table, which does not list those three, so a\n * forgetful adapter degrades to \"unknown\" rather than to a false \"eu\". */\n region?: Region;\n subprocess?: boolean;\n}): Usage {\n const cacheReadTokens = args.cacheReadTokens ?? 0;\n const cacheCreationTokens = args.cacheCreationTokens ?? 0;\n // Subprocess (Max plan) is never a metered charge to us — cost is always 0.\n const costUsd = args.subprocess\n ? 0\n : computeCost(\n args.provider,\n args.model,\n args.inputTokens,\n args.outputTokens,\n cacheReadTokens,\n cacheCreationTokens,\n );\n const usage: Usage = {\n provider: args.provider,\n model: args.model,\n region: args.region ?? regionOfProvider(args.provider),\n transport: args.transport,\n inputTokens: args.inputTokens,\n outputTokens: args.outputTokens,\n cacheReadTokens,\n cacheCreationTokens,\n costUsd,\n latencyMs: 0,\n capability: args.capability,\n ts: \"\",\n };\n if (args.subprocess) usage.subprocess = true;\n return usage;\n}\n","// Anthropic adapter (F4.6) — the real one (F2.5 shipped only a stub). Two\n// transports: http (api.anthropic.com/v1/messages) and subprocess (claude -p,\n// Max plan, costUsd 0). Critical for the xrt81 vision pilot. Tools normalized\n// via F4.5. No @anthropic-ai/sdk package — plain fetch through httpTransport.\nimport { httpTransport, errorBody } from \"../transport/http.js\";\nimport { subprocessTransport } from \"../transport/subprocess.js\";\nimport { streamTransport } from \"../transport/stream.js\";\nimport { toolCallArgs, toProviderTools, fromProviderToolCall } from \"./tools.js\";\nimport { freshUsage } from \"../cost/usage.js\";\nimport type {\n ProviderAdapter,\n ChatRequest,\n ChatResult,\n ChatStreamEvent,\n Message,\n ContentPart,\n ToolCall,\n} from \"../types.js\";\n\ninterface AnthropicBlock {\n type: string;\n text?: string;\n id?: string;\n name?: string;\n input?: Record<string, unknown>;\n}\ninterface AnthropicResponse {\n content?: AnthropicBlock[];\n usage?: {\n input_tokens?: number;\n output_tokens?: number;\n cache_read_input_tokens?: number;\n cache_creation_input_tokens?: number;\n };\n error?: unknown;\n}\n\nfunction contentBlocks(content: string | ContentPart[]): unknown {\n if (typeof content === \"string\") return content;\n return content.map((p) => {\n if (p.type === \"text\") return { type: \"text\", text: p.text };\n // Anthropic has no native video input — route video via a video-capable\n // provider (Gemini, F019) instead.\n if (p.type === \"video\") {\n throw new Error(\"anthropic adapter: video input is not supported — use a video provider (e.g. gemini)\");\n }\n if (typeof p.image === \"string\" && /^https?:\\/\\//.test(p.image)) {\n return { type: \"image\", source: { type: \"url\", url: p.image } };\n }\n const data =\n typeof p.image === \"string\"\n ? p.image.replace(/^data:[^;]+;base64,/, \"\")\n : Buffer.from(p.image).toString(\"base64\");\n return {\n type: \"image\",\n source: { type: \"base64\", media_type: p.mimeType ?? \"image/png\", data },\n };\n });\n}\n\n/** Flatten messages to a single prompt for the subprocess (claude -p) path. */\nfunction flattenForSubprocess(messages: Message[]): { prompt: string; system?: string } {\n const sys: string[] = [];\n const turns: string[] = [];\n for (const m of messages) {\n const text =\n typeof m.content === \"string\"\n ? m.content\n : m.content.map((p) => (p.type === \"text\" ? p.text : \"[image]\")).join(\" \");\n if (m.role === \"system\") sys.push(text);\n else turns.push(`${m.role}: ${text}`);\n }\n return { prompt: turns.join(\"\\n\\n\"), system: sys.length ? sys.join(\"\\n\") : undefined };\n}\n\nexport function anthropicAdapter(\n config: { apiKey?: string; baseUrl?: string; anthropicVersion?: string; fetch?: typeof fetch } = {},\n): ProviderAdapter {\n const baseUrl = config.baseUrl ?? \"https://api.anthropic.com\";\n const version = config.anthropicVersion ?? \"2023-06-01\";\n\n /** Build the /v1/messages body (shared by the http + stream paths). */\n function buildBody(req: ChatRequest): Record<string, unknown> {\n const system: string[] = [];\n const messages: { role: string; content: unknown }[] = [];\n for (const m of req.messages as Message[]) {\n if (m.role === \"system\") {\n system.push(typeof m.content === \"string\" ? m.content : \"\");\n continue;\n }\n // tool-result turn → a user message carrying a tool_result block (F8.7).\n if (m.role === \"tool\") {\n messages.push({\n role: \"user\",\n content: [\n {\n type: \"tool_result\",\n tool_use_id: m.toolCallId ?? \"\",\n content: typeof m.content === \"string\" ? m.content : \"\",\n },\n ],\n });\n continue;\n }\n // assistant turn that called tools → text blocks + tool_use blocks (F8.7).\n if (m.role === \"assistant\" && m.toolCalls && m.toolCalls.length > 0) {\n const blocks: unknown[] = [];\n if (typeof m.content === \"string\") {\n if (m.content.length > 0) blocks.push({ type: \"text\", text: m.content });\n } else {\n blocks.push(...(contentBlocks(m.content) as unknown[]));\n }\n for (const tc of m.toolCalls) {\n blocks.push({ type: \"tool_use\", id: tc.id, name: tc.name, input: toolCallArgs(tc) });\n }\n messages.push({ role: \"assistant\", content: blocks });\n continue;\n }\n messages.push({ role: m.role === \"assistant\" ? \"assistant\" : \"user\", content: contentBlocks(m.content) });\n }\n const body: Record<string, unknown> = {\n model: req.spec.model,\n max_tokens: req.maxTokens ?? 1024, // Anthropic requires max_tokens\n messages,\n };\n if (system.length > 0) body.system = system.join(\"\\n\");\n if (req.tools) body.tools = toProviderTools(req.tools, \"anthropic\");\n if (req.temperature !== undefined) body.temperature = req.temperature;\n return body;\n }\n\n function apiKeyOrThrow(): string {\n const apiKey = config.apiKey ?? process.env.ANTHROPIC_API_KEY;\n if (!apiKey) throw new Error(\"anthropic adapter: API key not set (env ANTHROPIC_API_KEY)\");\n return apiKey;\n }\n\n async function chatHttp(req: ChatRequest): Promise<ChatResult> {\n const apiKey = apiKeyOrThrow();\n const body = buildBody(req);\n\n const res = await httpTransport({\n spec: req.spec,\n http: {\n url: `${baseUrl}/v1/messages`,\n headers: {\n \"content-type\": \"application/json\",\n \"x-api-key\": apiKey,\n \"anthropic-version\": version,\n },\n body,\n },\n });\n if (!res.ok) throw new Error(`anthropic ${res.status}: ${errorBody(res.json, res.text)}`);\n\n const data = res.json as AnthropicResponse;\n const blocks = data.content ?? [];\n const text = blocks\n .filter((b) => b.type === \"text\" && typeof b.text === \"string\")\n .map((b) => b.text)\n .join(\"\");\n const toolCalls: ToolCall[] = blocks\n .filter((b) => b.type === \"tool_use\")\n .map((b) => fromProviderToolCall(b, \"anthropic\"));\n\n const usage = freshUsage({\n provider: \"anthropic\",\n model: req.spec.model,\n transport: \"http\",\n capability: \"chat\",\n inputTokens: data.usage?.input_tokens ?? 0,\n outputTokens: data.usage?.output_tokens ?? 0,\n cacheReadTokens: data.usage?.cache_read_input_tokens ?? 0,\n cacheCreationTokens: data.usage?.cache_creation_input_tokens ?? 0,\n });\n const result: ChatResult = { text, usage };\n if (toolCalls.length > 0) result.toolCalls = toolCalls;\n return result;\n }\n\n async function chatSubprocess(req: ChatRequest): Promise<ChatResult> {\n const { prompt, system } = flattenForSubprocess(req.messages as Message[]);\n const r = await subprocessTransport({ spec: req.spec, subprocess: { prompt, systemPrompt: system } });\n const usage = freshUsage({\n provider: \"anthropic\",\n model: req.spec.model,\n transport: \"subprocess\",\n capability: \"chat\",\n inputTokens: r.inputTokens,\n outputTokens: r.outputTokens,\n cacheReadTokens: r.cacheReadTokens,\n cacheCreationTokens: r.cacheCreationTokens,\n subprocess: true,\n });\n return { text: r.text, usage };\n }\n\n async function chat(req: ChatRequest): Promise<ChatResult> {\n return req.spec.transport === \"subprocess\" ? chatSubprocess(req) : chatHttp(req);\n }\n\n // Streaming chat (F8.4) over the native /v1/messages SSE. Maps\n // content_block_delta(text_delta) → text events, accumulates tool_use blocks\n // (id/name from content_block_start, input from input_json_delta) → complete\n // tool_call events, and reads usage from message_start + message_delta. Only\n // the http transport streams — `claude -p` subprocess is one-shot.\n async function* chatStream(req: ChatRequest): AsyncIterable<ChatStreamEvent> {\n if (req.spec.transport === \"subprocess\") {\n throw new Error(\"anthropic adapter: streaming is not supported over the subprocess transport\");\n }\n const apiKey = apiKeyOrThrow();\n const body = { ...buildBody(req), stream: true };\n const stream = streamTransport({\n spec: req.spec,\n fetch: config.fetch,\n http: {\n url: `${baseUrl}/v1/messages`,\n headers: {\n \"content-type\": \"application/json\",\n \"x-api-key\": apiKey,\n \"anthropic-version\": version,\n },\n body,\n },\n });\n\n let inputTokens = 0;\n let outputTokens = 0;\n let cacheReadTokens = 0;\n let cacheCreationTokens = 0;\n let stopReason: string | null = null;\n // index → accumulated tool_use block (input_json_delta fragments concatenated).\n const toolBlocks = new Map<number, { id: string; name: string; json: string }>();\n\n for await (const data of stream) {\n let ev: AnthropicStreamEvent;\n try {\n ev = JSON.parse(data) as AnthropicStreamEvent;\n } catch {\n continue;\n }\n switch (ev.type) {\n case \"message_start\": {\n const u = ev.message?.usage;\n inputTokens = u?.input_tokens ?? 0;\n cacheReadTokens = u?.cache_read_input_tokens ?? 0;\n cacheCreationTokens = u?.cache_creation_input_tokens ?? 0;\n break;\n }\n case \"content_block_start\": {\n if (ev.content_block?.type === \"tool_use\" && ev.index !== undefined) {\n toolBlocks.set(ev.index, {\n id: ev.content_block.id ?? \"\",\n name: ev.content_block.name ?? \"\",\n json: \"\",\n });\n }\n break;\n }\n case \"content_block_delta\": {\n const d = ev.delta;\n if (d?.type === \"text_delta\" && d.text) {\n yield { type: \"text\", delta: d.text };\n } else if (d?.type === \"input_json_delta\" && d.partial_json && ev.index !== undefined) {\n const b = toolBlocks.get(ev.index);\n if (b) b.json += d.partial_json;\n }\n break;\n }\n case \"message_delta\": {\n if (ev.delta?.stop_reason) stopReason = ev.delta.stop_reason;\n if (ev.usage?.output_tokens !== undefined) outputTokens = ev.usage.output_tokens;\n break;\n }\n default:\n break; // content_block_stop / message_stop / ping\n }\n }\n\n for (const [, b] of [...toolBlocks.entries()].sort((a, c) => a[0] - c[0])) {\n let args: Record<string, unknown> = {};\n try {\n args = b.json ? (JSON.parse(b.json) as Record<string, unknown>) : {};\n } catch {\n args = {};\n }\n yield { type: \"tool_call\", id: b.id, name: b.name, args };\n }\n const usage = freshUsage({\n provider: \"anthropic\",\n model: req.spec.model,\n transport: \"http\",\n capability: \"chat\",\n inputTokens,\n outputTokens,\n cacheReadTokens,\n cacheCreationTokens,\n });\n yield { type: \"usage\", costUsd: usage.costUsd, model: usage.model, usage };\n yield { type: \"finish\", reason: mapAnthropicStop(stopReason) };\n }\n\n return { name: \"anthropic\", chat, chatStream, vision: chat };\n}\n\n/** Anthropic Messages SSE event (only the fields we read). */\ninterface AnthropicStreamEvent {\n type: string;\n index?: number;\n message?: {\n usage?: {\n input_tokens?: number;\n cache_read_input_tokens?: number;\n cache_creation_input_tokens?: number;\n };\n };\n content_block?: { type?: string; id?: string; name?: string };\n delta?: { type?: string; text?: string; partial_json?: string; stop_reason?: string };\n usage?: { output_tokens?: number };\n}\n\n/** Map Anthropic stop_reason → the SDK's ChatStreamEvent finish reason. */\nfunction mapAnthropicStop(reason: string | null): \"end_turn\" | \"tool_calls\" | \"length\" | \"stop\" {\n switch (reason) {\n case \"tool_use\":\n return \"tool_calls\";\n case \"max_tokens\":\n return \"length\";\n case \"stop_sequence\":\n return \"stop\";\n default:\n return \"end_turn\";\n }\n}\n","// Shared core for OpenAI-compatible chat APIs. OpenAI (F4.1), DeepInfra (F4.3)\n// and OpenRouter (F4.4) all speak this wire format — only base URL, key and a\n// couple of headers differ. The adapter uses httpTransport (F2.4) for the wire\n// I/O and the F4.5 tool contract for tool round-tripping.\nimport { httpTransport, errorBody } from \"../transport/http.js\";\nimport { streamTransport } from \"../transport/stream.js\";\nimport { toolCallArgs, toProviderTools, fromProviderToolCall } from \"./tools.js\";\nimport { freshUsage } from \"../cost/usage.js\";\nimport { regionOfHost } from \"../cost/region.js\";\nimport type {\n ProviderAdapter,\n ChatRequest,\n ChatResult,\n ChatStreamEvent,\n Message,\n ToolCall,\n} from \"../types.js\";\n\nexport interface OpenAICompatibleConfig {\n /** Provider name recorded on Usage (e.g. \"openai\", \"deepinfra\", \"openrouter\"). */\n name: string;\n /** Chat completions base, e.g. \"https://api.openai.com/v1\". */\n baseUrl: string;\n /** Resolved at call time if omitted (env var per provider). */\n apiKey?: string;\n /** Extra headers (e.g. OpenRouter's HTTP-Referer / X-Title). */\n extraHeaders?: Record<string, string>;\n /** Injectable fetch for the streaming path (tests). */\n fetch?: typeof fetch;\n /** OpenRouter ground-truth cost (F010): send `usage:{include:true}` and use the\n * response's `usage.cost` (USD) as costUsd, falling back to the pricing table.\n * Only OpenRouter returns this field — openai/deepinfra leave it false. */\n costFromResponseField?: boolean;\n /** F039.2 — this provider accepts `prompt_cache_key` and caches a shared prefix\n * on it. Mistral only, deliberately: an unknown field is ignored by some\n * OpenAI-compatible servers and rejected with a 400 by others, so sending it\n * everywhere would trade a saving for an outage. Providers that cache\n * AUTOMATICALLY (openai, deepseek, gemini) need no key — they only need their\n * cached counts read back, which happens for every provider below. */\n supportsPromptCacheKey?: boolean;\n}\n\n/** A stable cache key derived from the fixed part of the prompt (F039.2).\n *\n * Content-derived on purpose. The key is a shared-prefix identity, so a key\n * collision must never mean two callers with DIFFERENT content share a bucket —\n * deriving it from the content makes a collision imply the content was identical,\n * and identical content cannot leak anything the other party did not already send.\n * (An id-derived default — \"conversation 42\" — would collide across tenants with\n * different content. That is the trap components flagged.)\n *\n * Only the leading system message is hashed: it is the part that repeats verbatim\n * across every call in an app, which is exactly what caching pays for. */\nfunction autoCacheKey(messages: { role: string; content: unknown }[]): string | undefined {\n const system = messages.find((m) => m.role === \"system\");\n if (!system || typeof system.content !== \"string\" || system.content.length < 200) return undefined;\n let h = 0x811c9dc5;\n for (let i = 0; i < system.content.length; i++) {\n h ^= system.content.charCodeAt(i);\n h = Math.imul(h, 0x01000193) >>> 0;\n }\n return `ai-sdk-auto-${h.toString(16)}-${system.content.length}`;\n}\n\ninterface OAToolCall {\n id?: string;\n function?: { name?: string; arguments?: string };\n}\ninterface OAResponse {\n choices?: { message?: { content?: string | null; tool_calls?: OAToolCall[] } }[];\n usage?: {\n prompt_tokens?: number;\n completion_tokens?: number;\n cost?: number;\n /** Mistral (F039): how many prompt tokens were served from cache. Note that\n * prompt_tokens INCLUDES these, so they must be subtracted before billing —\n * computeCost adds cacheReadTokens ON TOP of inputTokens. */\n prompt_tokens_details?: { cached_tokens?: number };\n };\n error?: unknown;\n}\n\n/** SDK message → OpenAI message (string content, or multimodal parts for vision).\n * Threads the normalized tool form to the wire: a `tool`-role message's\n * `toolCallId` → `tool_call_id`, and an assistant message's `toolCalls` →\n * `tool_calls:[{id,type:'function',function:{name,arguments}}]` (F8.3) so a\n * multi-turn tool conversation round-trips. Exported for serialization tests. */\nexport function toOpenAIMessage(m: Message): Record<string, unknown> {\n if (typeof m.content === \"string\") {\n const base: Record<string, unknown> = { role: m.role, content: m.content };\n if (m.toolCallId) base.tool_call_id = m.toolCallId;\n if (m.toolCalls && m.toolCalls.length > 0) {\n base.tool_calls = m.toolCalls.map((tc) => ({\n id: tc.id,\n type: \"function\",\n function: { name: tc.name, arguments: JSON.stringify(toolCallArgs(tc)) },\n }));\n }\n return base;\n }\n const content = m.content.map((p) => {\n if (p.type === \"text\") return { type: \"text\", text: p.text };\n if (p.type === \"video\") {\n // F019.3 — OpenRouter video models. `video_url` mirrors `image_url`;\n // VERIFIED live 2026-06-04 against gemma-4 + nvidia-nemotron (both described\n // a real 2MB clip sent inline as a base64 data-URL).\n const url =\n typeof p.video === \"string\"\n ? p.video\n : `data:${p.mimeType ?? \"video/mp4\"};base64,${Buffer.from(p.video).toString(\"base64\")}`;\n return { type: \"video_url\", video_url: { url } };\n }\n const url =\n typeof p.image === \"string\"\n ? p.image\n : `data:${p.mimeType ?? \"image/png\"};base64,${Buffer.from(p.image).toString(\"base64\")}`;\n return { type: \"image_url\", image_url: { url } };\n });\n return { role: m.role, content };\n}\n\n/** THE ONE PLACE a chat body is built (F043).\n *\n * chat() and chatStream() used to construct this separately, and the prompt-cache\n * key was added to only one of them — so every streamed call paid full price for a\n * system prompt it had already sent, silently, behind a type that says the two take\n * the same request. components (#24153) and sanne (#24154) each measured it in the\n * published 0.34.0 tarball before we noticed.\n *\n * Keeping one builder is the actual fix. Copying the missing lines across would have\n * closed this instance and left the next added field free to drift the same way.\n * chatStream adds only `stream` + `stream_options` on top of what comes back here. */\nfunction buildChatBody(\n req: ChatRequest,\n config: Pick<OpenAICompatibleConfig, \"supportsPromptCacheKey\" | \"costFromResponseField\">,\n): Record<string, unknown> {\n const body: Record<string, unknown> = {\n model: req.spec.model,\n messages: req.messages.map(toOpenAIMessage),\n };\n if (req.tools) body.tools = toProviderTools(req.tools, \"openai\");\n if (req.maxTokens !== undefined) body.max_tokens = req.maxTokens;\n if (req.temperature !== undefined) body.temperature = req.temperature;\n if (req.responseFormat === \"json\") body.response_format = { type: \"json_object\" };\n // F039: Mistral caches a shared prefix at 10% of the input rate, but ONLY when the\n // request carries a cache key. Measured 2026-08-27: without it, an identical\n // 8,810-token prefix reported cached_tokens 0 at every size up to 57k; with it, the\n // second call reported 8,784. Dropping this field was our bug, not a vendor limit.\n // ON BY DEFAULT (F039.2). Opt-in was the wrong default: it only saves money for\n // callers who read a changelog, and this repo already learned that lesson once —\n // ~91% of Mistral spend was invisible because per-repo cost-sink wiring drifted.\n // `promptCache: false` turns it off; an explicit promptCacheKey always wins.\n if (config.supportsPromptCacheKey && req.promptCache !== false) {\n const k = req.promptCacheKey ?? autoCacheKey(req.messages);\n if (k !== undefined) body.prompt_cache_key = k;\n }\n if (config.costFromResponseField) body.usage = { include: true };\n return body;\n}\n\nexport function makeOpenAICompatibleAdapter(config: OpenAICompatibleConfig): ProviderAdapter {\n async function chat(req: ChatRequest): Promise<ChatResult> {\n const apiKey = config.apiKey ?? process.env[`${config.name.toUpperCase()}_API_KEY`];\n if (!apiKey) {\n throw new Error(`${config.name} adapter: API key not set (env ${config.name.toUpperCase()}_API_KEY)`);\n }\n const body = buildChatBody(req, config);\n\n const res = await httpTransport({\n spec: req.spec,\n http: {\n url: `${config.baseUrl}/chat/completions`,\n headers: {\n \"content-type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n ...config.extraHeaders,\n },\n body,\n },\n });\n if (!res.ok) {\n throw new Error(`${config.name} ${res.status}: ${errorBody(res.json, res.text)}`);\n }\n const data = res.json as OAResponse;\n const msg = data.choices?.[0]?.message;\n // Reasoning/multimodal models can return `content` as an array of blocks (or\n // null) instead of a plain string — coerce so callers always get a string\n // (was: `?? \"\"`, which left an array through → consumer `text.replace` crash).\n const text = contentToText(msg?.content);\n const toolCalls: ToolCall[] | undefined = msg?.tool_calls?.map((tc) =>\n fromProviderToolCall(tc, \"openai\"),\n );\n const cachedIn = data.usage?.prompt_tokens_details?.cached_tokens;\n const usage = freshUsage({\n provider: config.name,\n model: req.spec.model,\n // From the URL we actually called, not from config.name — mistral and deepseek\n // both take a baseUrl, and a custom gateway must not inherit their EU/CN claim.\n region: regionOfHost(config.baseUrl),\n transport: \"http\",\n capability: \"chat\",\n // prompt_tokens INCLUDES the cached ones; computeCost adds cacheReadTokens on\n // top of inputTokens, so billing the raw figure would charge the cached prefix\n // twice — at full rate AND at the cache rate.\n inputTokens: (data.usage?.prompt_tokens ?? 0) - (cachedIn ?? 0),\n outputTokens: data.usage?.completion_tokens ?? 0,\n // Absent field stays undefined: \"not reported\" is not the same as \"zero cached\".\n ...(cachedIn === undefined ? {} : { cacheReadTokens: cachedIn }),\n });\n if (config.costFromResponseField && typeof data.usage?.cost === \"number\") {\n usage.costUsd = data.usage.cost; // OpenRouter ground-truth beats the estimate\n }\n const result: ChatResult = { text, usage };\n if (toolCalls && toolCalls.length > 0) result.toolCalls = toolCalls;\n return result;\n }\n\n // Streaming chat (F8.2). Parses the OpenAI chat.completions SSE: content\n // deltas → text events, tool_calls deltas accumulated (index-keyed, arguments\n // string concatenated) → complete tool_call events at end, the include_usage\n // chunk → a usage event, finish_reason → the terminal finish (emitted last so\n // tool_calls + usage precede it).\n async function* chatStream(req: ChatRequest): AsyncIterable<ChatStreamEvent> {\n const apiKey = config.apiKey ?? process.env[`${config.name.toUpperCase()}_API_KEY`];\n if (!apiKey) {\n throw new Error(`${config.name} adapter: API key not set (env ${config.name.toUpperCase()}_API_KEY)`);\n }\n const body: Record<string, unknown> = {\n ...buildChatBody(req, config),\n stream: true,\n stream_options: { include_usage: true },\n };\n\n const stream = streamTransport({\n spec: req.spec,\n fetch: config.fetch,\n http: {\n url: `${config.baseUrl}/chat/completions`,\n headers: {\n \"content-type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n ...config.extraHeaders,\n },\n body,\n },\n });\n\n // index → accumulated tool call (id/name set once, arguments concatenated).\n const toolAcc = new Map<number, { id: string; name: string; args: string }>();\n let finishReason: string | null = null;\n\n for await (const data of stream) {\n let chunk: OAStreamChunk;\n try {\n chunk = JSON.parse(data) as OAStreamChunk;\n } catch {\n continue; // ignore unparseable keep-alive noise\n }\n const choice = chunk.choices?.[0];\n if (choice) {\n const delta = choice.delta ?? {};\n if (typeof delta.content === \"string\" && delta.content.length > 0) {\n yield { type: \"text\", delta: delta.content };\n }\n for (const tc of delta.tool_calls ?? []) {\n const idx = tc.index ?? 0;\n const cur = toolAcc.get(idx) ?? { id: \"\", name: \"\", args: \"\" };\n if (tc.id) cur.id = tc.id;\n if (tc.function?.name) cur.name = tc.function.name;\n if (tc.function?.arguments) cur.args += tc.function.arguments;\n toolAcc.set(idx, cur);\n }\n if (choice.finish_reason) finishReason = choice.finish_reason;\n }\n if (chunk.usage) {\n const usage = freshUsage({\n provider: config.name,\n model: req.spec.model,\n region: regionOfHost(config.baseUrl),\n transport: \"http\",\n capability: \"chat\",\n inputTokens: chunk.usage.prompt_tokens ?? 0,\n outputTokens: chunk.usage.completion_tokens ?? 0,\n });\n if (config.costFromResponseField && typeof chunk.usage.cost === \"number\") {\n usage.costUsd = chunk.usage.cost; // OpenRouter ground-truth\n }\n yield { type: \"usage\", costUsd: usage.costUsd, model: usage.model, usage };\n }\n }\n\n // Flush accumulated tool calls (complete), then the terminal finish.\n for (const [, t] of [...toolAcc.entries()].sort((a, b) => a[0] - b[0])) {\n let args: Record<string, unknown> = {};\n try {\n args = t.args ? (JSON.parse(t.args) as Record<string, unknown>) : {};\n } catch {\n args = {};\n }\n yield { type: \"tool_call\", id: t.id, name: t.name, args };\n }\n yield { type: \"finish\", reason: mapFinishReason(finishReason) };\n }\n\n return {\n name: config.name,\n chat,\n chatStream,\n // gpt-4o-class models are multimodal — vision shares the chat path.\n vision: chat,\n };\n}\n\n/** OpenAI streaming chunk shape (only the fields we read). */\ninterface OAStreamChunk {\n choices?: {\n delta?: {\n content?: string | null;\n tool_calls?: { index?: number; id?: string; function?: { name?: string; arguments?: string } }[];\n };\n finish_reason?: string | null;\n }[];\n usage?: {\n prompt_tokens?: number;\n completion_tokens?: number;\n cost?: number;\n /** Mistral (F039): how many prompt tokens were served from cache. Note that\n * prompt_tokens INCLUDES these, so they must be subtracted before billing —\n * computeCost adds cacheReadTokens ON TOP of inputTokens. */\n prompt_tokens_details?: { cached_tokens?: number };\n };\n}\n\n/** Coerce an OpenAI `message.content` to a string. Most providers return a string,\n * but reasoning/multimodal models can return an array of content blocks (or null). */\nfunction contentToText(content: unknown): string {\n if (typeof content === \"string\") return content;\n if (Array.isArray(content)) {\n return content\n .map((p) => {\n if (typeof p === \"string\") return p;\n const t = (p as { text?: unknown } | null)?.text;\n return typeof t === \"string\" ? t : \"\";\n })\n .join(\"\");\n }\n return \"\";\n}\n\n/** Map OpenAI finish_reason → the SDK's ChatStreamEvent finish reason. */\nfunction mapFinishReason(reason: string | null): \"end_turn\" | \"tool_calls\" | \"length\" | \"stop\" {\n switch (reason) {\n case \"tool_calls\":\n return \"tool_calls\";\n case \"length\":\n return \"length\";\n case \"stop\":\n return \"stop\";\n default:\n return \"end_turn\";\n }\n}\n","// OpenAI adapter (F4.1 chat/vision + F5.4 embedding). Chat/vision come from the\n// shared OpenAI-compatible core; embedding uses the /embeddings endpoint. No\n// openai npm package — plain fetch through httpTransport.\nimport { makeOpenAICompatibleAdapter } from \"./openai-compatible.js\";\nimport { httpTransport, errorBody } from \"../transport/http.js\";\nimport { freshUsage } from \"../cost/usage.js\";\nimport type {\n ProviderAdapter,\n EmbeddingRequest,\n EmbeddingResult,\n TranscribeRequest,\n TranscribeResult,\n} from \"../types.js\";\n\n/** Whisper-family per-minute USD prices (audio is not token-priced). */\nconst WHISPER_PRICE_PER_MIN: Record<string, number> = {\n \"whisper-1\": 0.006,\n};\n\nexport function openaiAdapter(\n config: { apiKey?: string; baseUrl?: string; fetch?: typeof fetch } = {},\n): ProviderAdapter {\n const baseUrl = config.baseUrl ?? \"https://api.openai.com/v1\";\n const base = makeOpenAICompatibleAdapter({ name: \"openai\", baseUrl, apiKey: config.apiKey });\n\n async function embedding(req: EmbeddingRequest): Promise<EmbeddingResult> {\n const apiKey = config.apiKey ?? process.env.OPENAI_API_KEY;\n if (!apiKey) throw new Error(\"openai adapter: API key not set (env OPENAI_API_KEY)\");\n const res = await httpTransport({\n spec: req.spec,\n http: {\n url: `${baseUrl}/embeddings`,\n headers: { \"content-type\": \"application/json\", Authorization: `Bearer ${apiKey}` },\n body: { model: req.spec.model, input: req.input },\n },\n });\n if (!res.ok) {\n throw new Error(`openai ${res.status}: ${errorBody(res.json, res.text)}`);\n }\n const data = res.json as {\n data?: { embedding: number[] }[];\n usage?: { prompt_tokens?: number };\n };\n const vectors = (data.data ?? []).map((d) => d.embedding);\n const usage = freshUsage({\n provider: \"openai\",\n model: req.spec.model,\n transport: \"http\",\n capability: \"embedding\",\n inputTokens: data.usage?.prompt_tokens ?? 0,\n outputTokens: 0,\n });\n return { vectors, usage };\n }\n\n async function transcribe(req: TranscribeRequest): Promise<TranscribeResult> {\n const apiKey = config.apiKey ?? process.env.OPENAI_API_KEY;\n if (!apiKey) throw new Error(\"openai adapter: API key not set (env OPENAI_API_KEY)\");\n // Whisper is multipart/form-data — bypass httpTransport (JSON-only). Don't set\n // content-type; fetch adds the multipart boundary.\n const form = new FormData();\n form.append(\"file\", new Blob([req.audio]), \"audio\");\n form.append(\"model\", req.spec.model);\n if (req.language) form.append(\"language\", req.language);\n // Timestamps (F036): Whisper needs verbose_json, plus a granularity per\n // requested level. verbose_json returns `segments` inherently; `words` only\n // when \"word\" granularity is asked for.\n if (req.timestamps && req.timestamps.length > 0) {\n form.append(\"response_format\", \"verbose_json\");\n for (const g of req.timestamps) form.append(\"timestamp_granularities[]\", g);\n }\n const fetchImpl = config.fetch ?? fetch;\n const res = await fetchImpl(`${baseUrl}/audio/transcriptions`, {\n method: \"POST\",\n headers: { Authorization: `Bearer ${apiKey}` },\n body: form,\n });\n if (!res.ok) {\n throw new Error(`openai ${res.status}: ${(await res.text().catch(() => \"\")).slice(0, 200)}`);\n }\n const data = (await res.json()) as {\n text?: string;\n words?: { word: string; start: number; end: number }[];\n segments?: { text: string; start: number; end: number }[];\n };\n const usage = freshUsage({\n provider: \"openai\",\n model: req.spec.model,\n transport: \"http\",\n capability: \"transcribe\",\n inputTokens: 0,\n outputTokens: 0, // Whisper is per-minute, not token-priced.\n });\n // Per-minute cost when the caller supplies the audio duration (API returns none).\n if (req.durationSec !== undefined) {\n const perMinute = WHISPER_PRICE_PER_MIN[req.spec.model] ?? 0;\n usage.costUsd = (req.durationSec / 60) * perMinute;\n }\n const result: TranscribeResult = { text: data.text ?? \"\", usage };\n // \"word\" granularity → words[]; any timestamps → segments[] (verbose_json emits them).\n if (req.timestamps?.includes(\"word\") && data.words) {\n result.words = data.words.map((w) => ({ word: w.word, start: w.start, end: w.end }));\n }\n if (req.timestamps && req.timestamps.length > 0 && data.segments) {\n result.segments = data.segments.map((s) => ({ text: s.text, start: s.start, end: s.end }));\n }\n return result;\n }\n\n return { ...base, embedding, transcribe };\n}\n","// Shared image-input helpers (F031). Extracted from gemini.ts once a second\n// provider (vertex.ts) needed the exact same URL/bytes/data-URI → inline\n// base64+mime resolution for Veo's `image:{bytesBase64Encoded, mimeType}` field.\n\n/** Resolve an image input to { data(base64), mimeType } — a URL is fetched to bytes. */\nexport async function toInlineImage(\n image: string | Uint8Array,\n fetchImpl: typeof fetch,\n): Promise<{ data: string; mimeType: string }> {\n if (typeof image !== \"string\") {\n return { data: Buffer.from(image).toString(\"base64\"), mimeType: sniffMime(image) };\n }\n if (/^https?:\\/\\//i.test(image)) {\n const res = await fetchImpl(image);\n if (!res.ok) throw new Error(`toInlineImage: failed to fetch image (${res.status})`);\n const bytes = new Uint8Array(await res.arrayBuffer());\n const mimeType = res.headers.get(\"content-type\") ?? sniffMime(bytes);\n return { data: Buffer.from(bytes).toString(\"base64\"), mimeType };\n }\n // A data: URI or bare base64.\n const comma = image.startsWith(\"data:\") ? image.indexOf(\",\") : -1;\n const b64 = comma >= 0 ? image.slice(comma + 1) : image;\n const mimeType = image.startsWith(\"data:\") ? image.slice(5, image.indexOf(\";\")) : \"image/png\";\n return { data: b64, mimeType };\n}\n\nexport function sniffMime(b: Uint8Array): string {\n if (b[0] === 0x89 && b[1] === 0x50) return \"image/png\";\n if (b[0] === 0x47 && b[1] === 0x49) return \"image/gif\";\n if (b[0] === 0x52 && b[1] === 0x49 && b[8] === 0x57) return \"image/webp\";\n return \"image/jpeg\";\n}\n","// Google Gemini adapter (F4.2). generateContent REST API; API key in the query\n// param (?key=), not a header. System turns map to systemInstruction; assistant\n// maps to role \"model\". Token counts come from usageMetadata. Tools normalized\n// via F4.5. No @google/generative-ai package — plain fetch through httpTransport.\nimport { httpTransport, errorBody } from \"../transport/http.js\";\nimport { streamTransport } from \"../transport/stream.js\";\nimport { toProviderTools, fromProviderToolCall } from \"./tools.js\";\nimport { freshUsage } from \"../cost/usage.js\";\nimport { toInlineImage } from \"./media.js\";\nimport type {\n ProviderAdapter,\n ChatRequest,\n ChatResult,\n ChatStreamEvent,\n ImageRequest,\n ImageResult,\n AnimateRequest,\n AnimateResult,\n Message,\n ContentPart,\n ToolCall,\n} from \"../types.js\";\n\n/** Per-image USD price for Gemini image-gen models (generateContent image output\n * is billed per image). Official ai.google.dev/gemini-api/docs/pricing, standard\n * paid tier, at the 1K/1024px output size (Google's per-image price rises with\n * resolution — 2K/4K cost more; we record the common 1K default). Overridable\n * per call via geminiAdapter config.pricePerImage. */\nconst GEMINI_IMAGE_PRICE_PER_IMAGE: Record<string, number> = {\n \"gemini-2.5-flash-image\": 0.039, // \"nano-banana\" — 1024px = 1290 tok\n \"gemini-3.1-flash-image\": 0.067, // 1K=$0.067, 2K=$0.101, 4K=$0.151\n \"gemini-3.1-flash-image-preview\": 0.067,\n \"gemini-3-pro-image\": 0.134, // premium — 1K/2K=$0.134, 4K=$0.24\n \"gemini-3-pro-image-preview\": 0.134, // was $0.039 — wrong (that's the flash price); pro is $0.134\n};\n\nexport interface GeminiPart {\n text?: string;\n functionCall?: { name: string; args: Record<string, unknown> };\n inlineData?: { mimeType: string; data: string };\n}\ninterface GeminiResponse {\n candidates?: { content?: { parts?: GeminiPart[] } }[];\n usageMetadata?: { promptTokenCount?: number; candidatesTokenCount?: number; cachedContentTokenCount?: number };\n error?: unknown;\n}\n\n/** Split Gemini's promptTokenCount into billable and cached halves (F040).\n *\n * MEASURED 2026-08-27, not assumed: an 11,408-token repeated prefix reported\n * `promptTokenCount: 11408` alongside `cachedContentTokenCount: 11242` — so the\n * prompt count INCLUDES the cached tokens and they must be subtracted, because\n * computeCost adds cacheReadTokens ON TOP of inputTokens. Getting this direction\n * wrong double-bills the cached prefix.\n *\n * Gemini's implicit caching needs no opt-in and no key, but it does need a few\n * calls to warm: one run first hit on call 3, another on call 5. So a single\n * cold call reporting nothing cached is not evidence that caching is off. */\nfunction splitCached(meta: { promptTokenCount?: number; cachedContentTokenCount?: number } | undefined): {\n inputTokens: number;\n cacheReadTokens?: number;\n} {\n const prompt = meta?.promptTokenCount ?? 0;\n const cached = meta?.cachedContentTokenCount;\n if (cached === undefined) return { inputTokens: prompt };\n return { inputTokens: Math.max(0, prompt - cached), cacheReadTokens: cached };\n}\n\n/** Exported so the Vertex adapter (F038) reuses this exact mapping — Vertex and the\n * Gemini API share the generateContent content format, and two copies of it would\n * drift. */\nexport { splitCached };\n\nexport function partsFrom(content: string | ContentPart[]): GeminiPart[] {\n if (typeof content === \"string\") return [{ text: content }];\n return content.map((p): GeminiPart => {\n if (p.type === \"text\") return { text: p.text };\n // Video (F019) and image both go inline as base64 — Gemini accepts video mime\n // types natively. (Clips over ~20MB need the Files API — not handled here.)\n if (p.type === \"video\") {\n const data =\n typeof p.video === \"string\"\n ? p.video.replace(/^data:[^;]+;base64,/, \"\")\n : Buffer.from(p.video).toString(\"base64\");\n return { inlineData: { mimeType: p.mimeType ?? \"video/mp4\", data } };\n }\n const data =\n typeof p.image === \"string\"\n ? p.image.replace(/^data:[^;]+;base64,/, \"\")\n : Buffer.from(p.image).toString(\"base64\");\n return { inlineData: { mimeType: p.mimeType ?? \"image/png\", data } };\n });\n}\n\n/** Per-SECOND USD for Veo video models (F024). Official ai.google.dev/gemini-api/\n * docs/pricing (2026-06, \"video with audio\", 720p/1080p default; 4K costs more).\n * Override per call via config.pricePerSecond. Unknown model → 0 (never fabricated). */\nconst VEO_PRICE_PER_SEC: Record<string, number> = {\n \"veo-3.1-generate-preview\": 0.4, // standard; 4K = 0.60\n \"veo-3.1-fast-generate-preview\": 0.1, // 720p; 1080p = 0.12, 4K = 0.30\n \"veo-3.1-lite-generate-preview\": 0.05, // 720p; 1080p = 0.08\n \"veo-3.0-generate-001\": 0.4,\n \"veo-3.0-fast-generate-001\": 0.1,\n};\n\nexport function geminiAdapter(\n config: {\n apiKey?: string;\n baseUrl?: string;\n fetch?: typeof fetch;\n pricePerImage?: number;\n /** Override the per-SECOND Veo video price (else estimate per model, 0 if unknown). */\n pricePerSecond?: number;\n /** Poll interval for Veo long-running operations (default 5s). */\n pollIntervalMs?: number;\n /** Deadline for a Veo job (default 300000 = 5 min). */\n videoTimeoutMs?: number;\n } = {},\n): ProviderAdapter {\n const baseUrl = config.baseUrl ?? \"https://generativelanguage.googleapis.com/v1beta\";\n\n function resolveKey(): string {\n const apiKey = config.apiKey ?? process.env.GOOGLE_API_KEY ?? process.env.GEMINI_API_KEY;\n if (!apiKey) throw new Error(\"gemini adapter: API key not set (env GOOGLE_API_KEY or GEMINI_API_KEY)\");\n return apiKey;\n }\n\n /** Build the generateContent body (shared by the http + stream paths). */\n function buildBody(req: ChatRequest): Record<string, unknown> {\n const systemParts: GeminiPart[] = [];\n const contents: { role: string; parts: GeminiPart[] }[] = [];\n for (const m of req.messages as Message[]) {\n if (m.role === \"system\") {\n systemParts.push(...partsFrom(m.content));\n } else {\n contents.push({\n role: m.role === \"assistant\" ? \"model\" : \"user\",\n parts: partsFrom(m.content),\n });\n }\n }\n const body: Record<string, unknown> = { contents };\n if (systemParts.length > 0) body.systemInstruction = { parts: systemParts };\n if (req.tools) body.tools = toProviderTools(req.tools, \"gemini\");\n const genConfig: Record<string, unknown> = {};\n if (req.maxTokens !== undefined) genConfig.maxOutputTokens = req.maxTokens;\n if (req.temperature !== undefined) genConfig.temperature = req.temperature;\n if (Object.keys(genConfig).length > 0) body.generationConfig = genConfig;\n return body;\n }\n\n async function chat(req: ChatRequest): Promise<ChatResult> {\n const apiKey = resolveKey();\n const body = buildBody(req);\n\n const res = await httpTransport({\n spec: req.spec,\n http: {\n url: `${baseUrl}/models/${req.spec.model}:generateContent?key=${encodeURIComponent(apiKey)}`,\n headers: { \"content-type\": \"application/json\" },\n body,\n },\n });\n if (!res.ok) {\n throw new Error(`gemini ${res.status}: ${errorBody(res.json, res.text)}`);\n }\n const data = res.json as GeminiResponse;\n const parts = data.candidates?.[0]?.content?.parts ?? [];\n const text = parts\n .filter((p) => typeof p.text === \"string\")\n .map((p) => p.text)\n .join(\"\");\n const toolCalls: ToolCall[] = parts\n .filter((p) => p.functionCall)\n .map((p) => fromProviderToolCall({ functionCall: p.functionCall }, \"gemini\"));\n\n const usage = freshUsage({\n provider: \"gemini\",\n model: req.spec.model,\n transport: \"http\",\n capability: \"chat\",\n ...splitCached(data.usageMetadata),\n outputTokens: data.usageMetadata?.candidatesTokenCount ?? 0,\n });\n const result: ChatResult = { text, usage };\n if (toolCalls.length > 0) result.toolCalls = toolCalls;\n return result;\n }\n\n // Streaming chat (F8.6) over streamGenerateContent?alt=sse. Each SSE chunk is\n // a partial GenerateContentResponse: parts[].text → text events, parts[].\n // functionCall → complete tool_call events (gemini sends each call whole), and\n // the final usageMetadata → a usage event. finishReason maps the terminal.\n async function* chatStream(req: ChatRequest): AsyncIterable<ChatStreamEvent> {\n const apiKey = resolveKey();\n const body = buildBody(req);\n const stream = streamTransport({\n spec: req.spec,\n fetch: config.fetch,\n http: {\n url: `${baseUrl}/models/${req.spec.model}:streamGenerateContent?alt=sse&key=${encodeURIComponent(apiKey)}`,\n headers: { \"content-type\": \"application/json\" },\n body,\n },\n });\n\n const toolCalls: ToolCall[] = [];\n let inputTokens = 0;\n let outputTokens = 0;\n let cacheReadTokens: number | undefined;\n let finishReason: string | null = null;\n\n for await (const data of stream) {\n let chunk: GeminiResponse & { candidates?: { finishReason?: string }[] };\n try {\n chunk = JSON.parse(data) as typeof chunk;\n } catch {\n continue;\n }\n const candidate = chunk.candidates?.[0];\n for (const p of candidate?.content?.parts ?? []) {\n if (typeof p.text === \"string\" && p.text.length > 0) {\n yield { type: \"text\", delta: p.text };\n } else if (p.functionCall) {\n toolCalls.push(fromProviderToolCall({ functionCall: p.functionCall }, \"gemini\"));\n }\n }\n if (candidate?.finishReason) finishReason = candidate.finishReason;\n if (chunk.usageMetadata) {\n const split = splitCached(chunk.usageMetadata);\n inputTokens = chunk.usageMetadata.promptTokenCount === undefined ? inputTokens : split.inputTokens;\n if (split.cacheReadTokens !== undefined) cacheReadTokens = split.cacheReadTokens;\n outputTokens = chunk.usageMetadata.candidatesTokenCount ?? outputTokens;\n }\n }\n\n for (const tc of toolCalls) {\n yield { type: \"tool_call\", id: tc.id, name: tc.name, args: tc.arguments };\n }\n const usage = freshUsage({\n provider: \"gemini\",\n model: req.spec.model,\n transport: \"http\",\n capability: \"chat\",\n inputTokens,\n outputTokens,\n ...(cacheReadTokens === undefined ? {} : { cacheReadTokens }),\n });\n yield { type: \"usage\", costUsd: usage.costUsd, model: usage.model, usage };\n yield {\n type: \"finish\",\n reason: toolCalls.length > 0 ? \"tool_calls\" : mapGeminiFinish(finishReason),\n };\n }\n\n // Image generation (F013) via generateContent with IMAGE response modality.\n // Gemini returns the image inline as base64 (not a hosted URL like fal), so we\n // hand it back as a data: URL. Built to match cms's nano-banana request.\n async function image(req: ImageRequest): Promise<ImageResult> {\n const apiKey = resolveKey();\n // Direct fetch (injectable for tests) — generateContent is JSON in/out but\n // we read inline image bytes, so we don't route through httpTransport here.\n const fetchImpl = config.fetch ?? fetch;\n const res = await fetchImpl(`${baseUrl}/models/${req.spec.model}:generateContent?key=${encodeURIComponent(apiKey)}`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({\n contents: [{ role: \"user\", parts: [{ text: req.prompt }] }],\n // The multimodal image model can return text + image; ask for both.\n generationConfig: { responseModalities: [\"TEXT\", \"IMAGE\"] },\n }),\n });\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`gemini image ${res.status}: ${body.slice(0, 300)}`);\n }\n const data = (await res.json()) as GeminiResponse & {\n candidates?: { content?: { parts?: GeminiImagePart[] } }[];\n promptFeedback?: { blockReason?: string };\n };\n if (data.promptFeedback?.blockReason) {\n throw new Error(`gemini image blocked: ${data.promptFeedback.blockReason}`);\n }\n let url: string | undefined;\n for (const p of data.candidates?.[0]?.content?.parts ?? []) {\n // Some responses use camelCase inlineData, others snake_case inline_data.\n const inline = p.inlineData ?? p.inline_data;\n const mime = inline?.mimeType ?? inline?.mime_type;\n const b64 = inline?.data;\n if (mime && b64) {\n url = `data:${mime};base64,${b64}`;\n break;\n }\n }\n if (!url) throw new Error(\"gemini image: response contained no inline image data\");\n const usage = freshUsage({\n provider: \"gemini\",\n model: req.spec.model,\n transport: \"http\",\n capability: \"image\",\n ...splitCached(data.usageMetadata),\n outputTokens: data.usageMetadata?.candidatesTokenCount ?? 0,\n });\n usage.costUsd = config.pricePerImage ?? GEMINI_IMAGE_PRICE_PER_IMAGE[req.spec.model] ?? 0;\n return { url, usage };\n }\n\n // Image-to-video (F024) via Veo on the Gemini API — :predictLongRunning. Submit\n // returns an operation; poll until done; the result is an auth-gated file URI, so\n // we download the bytes with the key and hand them back (the URI alone needs auth).\n async function animate(req: AnimateRequest): Promise<AnimateResult> {\n const apiKey = resolveKey();\n const fetchImpl = config.fetch ?? fetch;\n const pollIntervalMs = config.pollIntervalMs ?? 5000;\n const deadline = Date.now() + (config.videoTimeoutMs ?? 300000);\n\n // Input image → inline base64 + mime (URL is fetched to bytes first).\n const { data, mimeType } = await toInlineImage(req.image, fetchImpl);\n const parameters: Record<string, unknown> = {};\n // durationSeconds must be a NUMBER (the API rejects a string, despite some docs).\n if (req.durationSec !== undefined) parameters.durationSeconds = req.durationSec;\n if (req.resolution !== undefined) parameters.resolution = req.resolution;\n // Veo's predict image field is bytesBase64Encoded + mimeType (NOT generateContent's\n // inlineData — the API rejects that: \"inlineData isn't supported by this model\").\n const body = {\n instances: [{ prompt: req.prompt ?? \"\", image: { bytesBase64Encoded: data, mimeType } }],\n ...(Object.keys(parameters).length ? { parameters } : {}),\n };\n\n const submit = await fetchImpl(\n `${baseUrl}/models/${req.spec.model}:predictLongRunning?key=${encodeURIComponent(apiKey)}`,\n { method: \"POST\", headers: { \"content-type\": \"application/json\" }, body: JSON.stringify(body) },\n );\n if (!submit.ok) {\n throw new Error(`gemini animate ${submit.status}: ${(await submit.text().catch(() => \"\")).slice(0, 300)}`);\n }\n const op = (await submit.json()) as { name?: string };\n if (!op.name) throw new Error(\"gemini animate: no operation name in submit response\");\n\n // Poll the operation until done.\n let videoUri: string | undefined;\n for (;;) {\n const poll = await fetchImpl(`${baseUrl}/${op.name}?key=${encodeURIComponent(apiKey)}`, {\n headers: { \"content-type\": \"application/json\" },\n });\n if (!poll.ok) throw new Error(`gemini animate poll ${poll.status}`);\n const opData = (await poll.json()) as VeoOperation;\n if (opData.error) throw new Error(`gemini animate: ${opData.error.message ?? \"operation error\"}`);\n if (opData.done) {\n videoUri = opData.response?.generateVideoResponse?.generatedSamples?.[0]?.video?.uri;\n if (!videoUri) throw new Error(`gemini animate: done but no video uri: ${errorBody(opData.response)}`);\n break;\n }\n if (Date.now() >= deadline) throw new Error(\"gemini animate: timed out\");\n await new Promise((r) => setTimeout(r, pollIntervalMs));\n }\n\n // Download the bytes (the URI is auth-gated + short-lived).\n const dl = await fetchImpl(videoUri.includes(\"key=\") ? videoUri : `${videoUri}${videoUri.includes(\"?\") ? \"&\" : \"?\"}key=${encodeURIComponent(apiKey)}`);\n if (!dl.ok) throw new Error(`gemini animate download ${dl.status}`);\n const bytes = new Uint8Array(await dl.arrayBuffer());\n\n const usage = freshUsage({\n provider: \"gemini\",\n model: req.spec.model,\n transport: \"http\",\n capability: \"animate\",\n inputTokens: 0,\n outputTokens: 0,\n });\n const perSec = config.pricePerSecond ?? VEO_PRICE_PER_SEC[req.spec.model] ?? 0;\n usage.costUsd = perSec * (req.durationSec ?? 8);\n return { url: videoUri, bytes, mimeType: \"video/mp4\", usage };\n }\n\n return { name: \"gemini\", chat, chatStream, image, animate, vision: chat };\n}\n\n/** A Veo predictLongRunning operation result shape. */\ninterface VeoOperation {\n done?: boolean;\n error?: { message?: string };\n response?: {\n generateVideoResponse?: {\n generatedSamples?: { video?: { uri?: string } }[];\n };\n };\n}\n\n/** Image part shape on a generateContent response (camel + snake aliases). */\ninterface GeminiInline {\n mimeType?: string;\n mime_type?: string;\n data?: string;\n}\ninterface GeminiImagePart {\n text?: string;\n inlineData?: GeminiInline;\n inline_data?: GeminiInline;\n}\n\n/** Map Gemini finishReason → the SDK's ChatStreamEvent finish reason. */\nfunction mapGeminiFinish(reason: string | null): \"end_turn\" | \"tool_calls\" | \"length\" | \"stop\" {\n switch (reason) {\n case \"MAX_TOKENS\":\n return \"length\";\n case \"STOP\":\n return \"end_turn\";\n default:\n return reason ? \"stop\" : \"end_turn\";\n }\n}\n","// DeepInfra adapter (F4.3). DeepInfra exposes an OpenAI-compatible endpoint, so\n// this is the shared core pointed at DeepInfra's base URL + key. No extra deps.\nimport { makeOpenAICompatibleAdapter } from \"./openai-compatible.js\";\nimport type { ProviderAdapter } from \"../types.js\";\n\nexport function deepinfraAdapter(\n config: { apiKey?: string; baseUrl?: string } = {},\n): ProviderAdapter {\n return makeOpenAICompatibleAdapter({\n name: \"deepinfra\",\n baseUrl: config.baseUrl ?? \"https://api.deepinfra.com/v1/openai\",\n apiKey: config.apiKey,\n });\n}\n","// OpenRouter adapter (F4.4). Meta-router with an OpenAI-compatible API — reuses\n// the shared core + OpenRouter's attribution headers. Any upstream model is\n// reachable by its slug, e.g. \"minimax/minimax-m2.7\", \"google/gemini-2.5-flash\".\nimport { makeOpenAICompatibleAdapter } from \"./openai-compatible.js\";\nimport { freshUsage } from \"../cost/usage.js\";\nimport type { ProviderAdapter, ImageRequest, ImageResult } from \"../types.js\";\n\n// F033.1 — OpenRouter's unified Image API (POST /images, distinct from\n// /chat/completions) returns base64 image data under data[].b64_json, plus a\n// ground-truth usage.cost (USD) like chat does. Vector/SVG output is the same\n// shape with data[].media_type = \"image/svg+xml\". A model/policy error can come\n// back as HTTP 200 with an empty data[] and a structured `error` — surfaced so\n// the caller sees the real cause, not a generic \"no image data\".\ninterface OpenRouterImageResponse {\n data?: { b64_json?: string; media_type?: string }[];\n usage?: { cost?: number };\n error?: { message?: string } | string;\n}\n\n// Per-image USD ESTIMATES — fallback for when OpenRouter's response omits\n// usage.cost. Verified 2026-07-03 against openrouter.ai/recraft/recraft-v4.1*\n// (override via config.pricePerImage).\nconst OPENROUTER_IMAGE_PRICE_ESTIMATE: Record<string, number> = {\n \"recraft/recraft-v4.1\": 0.035,\n \"recraft/recraft-v4.1-vector\": 0.08,\n};\n\nexport interface OpenRouterAdapterConfig {\n apiKey?: string;\n baseUrl?: string;\n referer?: string;\n title?: string;\n fetch?: typeof fetch;\n /** Override the per-image USD price (else OPENROUTER_IMAGE_PRICE_ESTIMATE, else 0). */\n pricePerImage?: number;\n}\n\nexport function openrouterAdapter(config: OpenRouterAdapterConfig = {}): ProviderAdapter {\n const baseUrl = config.baseUrl ?? \"https://openrouter.ai/api/v1\";\n const headers = {\n \"HTTP-Referer\": config.referer ?? \"https://broberg.ai\",\n \"X-Title\": config.title ?? \"@broberg/ai-sdk\",\n };\n const base = makeOpenAICompatibleAdapter({\n name: \"openrouter\",\n baseUrl,\n apiKey: config.apiKey,\n extraHeaders: headers,\n // Forward the injectable fetch so an override applies uniformly to\n // chat/chatStream/vision as well as the image() path below.\n fetch: config.fetch,\n // OpenRouter returns ground-truth usage.cost (USD) when usage:{include:true}\n // is set — use it over the local pricing-table estimate (F010).\n costFromResponseField: true,\n });\n\n async function image(req: ImageRequest): Promise<ImageResult> {\n const apiKey = config.apiKey ?? process.env.OPENROUTER_API_KEY;\n if (!apiKey) throw new Error(\"openrouter adapter: OPENROUTER_API_KEY not set\");\n const doFetch = config.fetch ?? fetch;\n\n const body: Record<string, unknown> = { model: req.spec.model, prompt: req.prompt };\n if (req.width !== undefined && req.height !== undefined) {\n body.size = `${req.width}x${req.height}`;\n }\n // OpenRouter's Image API takes top-level `seed` (reproducibility) and\n // `output_format` (png/jpeg/webp) — forward the ImageRequest fields the\n // rest of the SDK exposes (matches bfl.ts) instead of silently dropping them.\n if (req.seed !== undefined) body.seed = req.seed;\n if (req.outputFormat !== undefined) body.output_format = req.outputFormat;\n\n const res = await doFetch(`${baseUrl}/images`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n ...headers,\n },\n body: JSON.stringify(body),\n });\n if (!res.ok) {\n throw new Error(`openrouter images ${res.status}: ${(await res.text().catch(() => \"\")).slice(0, 300)}`);\n }\n const data = (await res.json()) as OpenRouterImageResponse;\n const first = data.data?.[0];\n if (!first?.b64_json) {\n // A flagged/failed generation can arrive as 200 + empty data + an error\n // payload — surface it so a moderation block reads differently than a glitch.\n const errMsg = typeof data.error === \"string\" ? data.error : data.error?.message;\n throw new Error(`openrouter images: ${errMsg ?? \"no image data in response\"}`);\n }\n\n const usage = freshUsage({\n provider: \"openrouter\",\n model: req.spec.model,\n transport: \"http\",\n capability: \"image\",\n inputTokens: 0,\n outputTokens: 0,\n });\n usage.costUsd =\n data.usage?.cost ?? config.pricePerImage ?? OPENROUTER_IMAGE_PRICE_ESTIMATE[req.spec.model] ?? 0;\n return { url: `data:${first.media_type ?? \"image/png\"};base64,${first.b64_json}`, usage };\n }\n\n return { ...base, image };\n}\n","// Requesty adapter (F028). An OpenAI-compatible AI gateway (400+ models, 30+\n// providers) — a drop-in alternative to the `openrouter` upstream. Reuses the\n// shared OpenAI-compatible core; only the base URL + key differ. Requesty returns\n// ground-truth `usage.cost`, so cost is exact (not a table estimate). Key from\n// REQUESTY_API_KEY. EU data-residency endpoint via `eu:true`.\n//\n// GDPR note: the EU endpoint keeps only Requesty's GATEWAY in the EU (Frankfurt).\n// End-to-end EU residency still requires an EU-region MODEL slug (Bedrock\n// `@eu-central-1`, Vertex `@eu`, Azure `@swedencentral`, Mistral EU-default) — a\n// global slug routes inference outside the EU despite the EU endpoint.\nimport { makeOpenAICompatibleAdapter } from \"./openai-compatible.js\";\nimport type { ProviderAdapter } from \"../types.js\";\n\nconst US_BASE = \"https://router.requesty.ai/v1\";\nconst EU_BASE = \"https://router.eu.requesty.ai/v1\";\n\nexport function requestyAdapter(\n config: { apiKey?: string; baseUrl?: string; eu?: boolean; referer?: string; title?: string } = {},\n): ProviderAdapter {\n return makeOpenAICompatibleAdapter({\n name: \"requesty\",\n baseUrl: config.baseUrl ?? (config.eu ? EU_BASE : US_BASE),\n apiKey: config.apiKey,\n extraHeaders: {\n \"HTTP-Referer\": config.referer ?? \"https://broberg.ai\",\n \"X-Title\": config.title ?? \"@broberg/ai-sdk\",\n },\n // Requesty returns ground-truth usage.cost (USD) by default — use it over the\n // local pricing-table estimate (same as OpenRouter, F010).\n costFromResponseField: true,\n });\n}\n","// DeepSeek adapter (F030) — the opt-in NON-PII secondary route for the Anthropic\n// phase-out. DeepSeek's direct API is OpenAI-compatible, so this reuses the shared\n// core; only base URL + key differ. Reached via `override:{ provider:\"deepseek\",\n// model:\"…\" }` — never a default tier. Key from DEEPSEEK_API_KEY.\n//\n// GDPR: DeepSeek is CN-hosted → NOT GDPR-safe. Use ONLY for non-PII workloads\n// (e.g. public web/article scanning). Personal data stays on Mistral EU.\n//\n// Models (direct api.deepseek.com): `deepseek-chat` (non-thinking) and\n// `deepseek-reasoner` (thinking) — both DEPRECATE 2026-07-24 and map to\n// `deepseek-v4-flash`. Prefer `deepseek-v4-flash` going forward (same model, not\n// sunset). The direct API does NOT return a cost field → cost comes from the\n// pricing table (verify rates against a real key; see src/cost/pricing.ts).\nimport { makeOpenAICompatibleAdapter } from \"./openai-compatible.js\";\nimport type { ProviderAdapter } from \"../types.js\";\n\nexport function deepseekAdapter(\n config: { apiKey?: string; baseUrl?: string } = {},\n): ProviderAdapter {\n return makeOpenAICompatibleAdapter({\n name: \"deepseek\", // → key DEEPSEEK_API_KEY\n baseUrl: config.baseUrl ?? \"https://api.deepseek.com/v1\",\n apiKey: config.apiKey,\n // Direct API returns no usage.cost → price from the table (not response).\n costFromResponseField: false,\n });\n}\n","// Mistral adapter. Mistral's La Plateforme exposes an OpenAI-compatible chat\n// endpoint (the shared core), plus two specialty endpoints we add here:\n// /ocr (F016.2, per-page) and /moderations (F016.4, per-token). Key resolved\n// from MISTRAL_API_KEY when not passed.\nimport { makeOpenAICompatibleAdapter } from \"./openai-compatible.js\";\nimport { freshUsage } from \"../cost/usage.js\";\nimport { regionOfHost } from \"../cost/region.js\";\nimport type {\n ProviderAdapter,\n OcrRequest,\n OcrResult,\n OcrPage,\n ModerationRequest,\n ModerationResult,\n ModerationItem,\n EmbeddingRequest,\n EmbeddingResult,\n TranscribeRequest,\n TranscribeResult,\n BatchRequestItem,\n BatchJob,\n BatchResultItem,\n TierSpec,\n} from \"../types.js\";\n\n/** Per-page USD for Mistral OCR ($2 / 1000 pages). Overridable via config. */\nconst MISTRAL_OCR_PRICE_PER_PAGE = 0.002;\n\n/** Per-minute USD for Voxtral transcription models (F016.3). */\nconst VOXTRAL_PRICE_PER_MIN: Record<string, number> = {\n \"voxtral-mini-latest\": 0.002,\n \"voxtral-mini-2507\": 0.002,\n \"voxtral-mini-2602\": 0.002,\n};\n\nexport function mistralAdapter(\n config: { apiKey?: string; baseUrl?: string; fetch?: typeof fetch; pricePerPage?: number } = {},\n): ProviderAdapter {\n const baseUrl = config.baseUrl ?? \"https://api.mistral.ai/v1\";\n const base = makeOpenAICompatibleAdapter({ name: \"mistral\", baseUrl, apiKey: config.apiKey, supportsPromptCacheKey: true });\n\n function key(): string {\n const k = config.apiKey ?? process.env.MISTRAL_API_KEY;\n if (!k) throw new Error(\"mistral adapter: API key not set (env MISTRAL_API_KEY)\");\n return k;\n }\n const fetchImpl = config.fetch ?? fetch;\n\n // OCR (F016.2) — POST /ocr. document is a URL/data-URL; image/* routes as an\n // image, anything else as a document (PDF etc.). Billed per page processed.\n async function ocr(req: OcrRequest): Promise<OcrResult> {\n const isImage = (req.mimeType ?? \"\").startsWith(\"image/\");\n const url =\n typeof req.document === \"string\"\n ? req.document\n : `data:${req.mimeType ?? \"application/pdf\"};base64,${Buffer.from(req.document).toString(\"base64\")}`;\n const document = isImage\n ? { type: \"image_url\", image_url: url }\n : { type: \"document_url\", document_url: url };\n\n const res = await fetchImpl(`${baseUrl}/ocr`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", authorization: `Bearer ${key()}` },\n body: JSON.stringify({ model: req.spec.model, document }),\n });\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`mistral ocr ${res.status}: ${body.slice(0, 300)}`);\n }\n const data = (await res.json()) as {\n pages?: { index?: number; markdown?: string }[];\n usage_info?: { pages_processed?: number };\n };\n const pages: OcrPage[] = (data.pages ?? []).map((p, i) => ({\n index: p.index ?? i,\n markdown: p.markdown ?? \"\",\n }));\n const pagesProcessed = data.usage_info?.pages_processed ?? pages.length;\n const usage = freshUsage({\n provider: \"mistral\",\n // From the URL we actually called. mistral is deliberately ABSENT from the\n // provider-name table (config.baseUrl can move it), so omitting this here made\n // these four report \"unknown\" instead of \"eu\" — a regression shipped in 0.36.0\n // that broke the very enforcement we told consumers to write.\n region: regionOfHost(baseUrl),\n model: req.spec.model,\n transport: \"http\",\n capability: \"ocr\",\n inputTokens: 0,\n outputTokens: 0,\n });\n usage.costUsd = pagesProcessed * (config.pricePerPage ?? MISTRAL_OCR_PRICE_PER_PAGE);\n return { pages, usage };\n }\n\n // Moderation (F016.4) — POST /moderations. Returns per-input category booleans\n // + scores; `flagged` = any category true. Billed per input token (estimated\n // from input length when the API omits a usage count).\n async function moderate(req: ModerationRequest): Promise<ModerationResult> {\n const res = await fetchImpl(`${baseUrl}/moderations`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", authorization: `Bearer ${key()}` },\n body: JSON.stringify({ model: req.spec.model, input: req.input }),\n });\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`mistral moderation ${res.status}: ${body.slice(0, 300)}`);\n }\n const data = (await res.json()) as {\n results?: { categories?: Record<string, boolean>; category_scores?: Record<string, number> }[];\n usage?: { prompt_tokens?: number };\n };\n const results: ModerationItem[] = (data.results ?? []).map((r) => {\n const categories = r.categories ?? {};\n return {\n flagged: Object.values(categories).some(Boolean),\n categories,\n categoryScores: r.category_scores ?? {},\n };\n });\n // The moderation endpoint usually omits token counts → estimate from input.\n const estIn = req.input.reduce((n, s) => n + Math.ceil(s.length / 4), 0);\n const usage = freshUsage({\n provider: \"mistral\",\n // From the URL we actually called. mistral is deliberately ABSENT from the\n // provider-name table (config.baseUrl can move it), so omitting this here made\n // these four report \"unknown\" instead of \"eu\" — a regression shipped in 0.36.0\n // that broke the very enforcement we told consumers to write.\n region: regionOfHost(baseUrl),\n model: req.spec.model,\n transport: \"http\",\n capability: \"moderation\",\n inputTokens: data.usage?.prompt_tokens ?? estIn,\n outputTokens: 0,\n });\n return { results, usage };\n }\n\n // Embeddings (F016.5) — POST /embeddings (OpenAI-compatible). Per-token input.\n async function embedding(req: EmbeddingRequest): Promise<EmbeddingResult> {\n const res = await fetchImpl(`${baseUrl}/embeddings`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", authorization: `Bearer ${key()}` },\n body: JSON.stringify({ model: req.spec.model, input: req.input }),\n });\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`mistral embeddings ${res.status}: ${body.slice(0, 300)}`);\n }\n const data = (await res.json()) as {\n data?: { embedding: number[] }[];\n usage?: { prompt_tokens?: number; total_tokens?: number };\n };\n const vectors = (data.data ?? []).map((d) => d.embedding);\n const usage = freshUsage({\n provider: \"mistral\",\n // From the URL we actually called. mistral is deliberately ABSENT from the\n // provider-name table (config.baseUrl can move it), so omitting this here made\n // these four report \"unknown\" instead of \"eu\" — a regression shipped in 0.36.0\n // that broke the very enforcement we told consumers to write.\n region: regionOfHost(baseUrl),\n model: req.spec.model,\n transport: \"http\",\n capability: \"embedding\",\n inputTokens: data.usage?.prompt_tokens ?? data.usage?.total_tokens ?? 0,\n outputTokens: 0,\n });\n return { vectors, usage };\n }\n\n // Transcribe (F016.3) — Voxtral via OpenAI-compatible /audio/transcriptions\n // (multipart). Per-minute cost when durationSec is supplied.\n async function transcribe(req: TranscribeRequest): Promise<TranscribeResult> {\n const form = new FormData();\n form.append(\"file\", new Blob([req.audio]), \"audio\");\n form.append(\"model\", req.spec.model);\n if (req.language) form.append(\"language\", req.language);\n const res = await fetchImpl(`${baseUrl}/audio/transcriptions`, {\n method: \"POST\",\n headers: { authorization: `Bearer ${key()}` },\n body: form,\n });\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`mistral transcribe ${res.status}: ${body.slice(0, 300)}`);\n }\n const data = (await res.json()) as { text?: string };\n const usage = freshUsage({\n provider: \"mistral\",\n // From the URL we actually called. mistral is deliberately ABSENT from the\n // provider-name table (config.baseUrl can move it), so omitting this here made\n // these four report \"unknown\" instead of \"eu\" — a regression shipped in 0.36.0\n // that broke the very enforcement we told consumers to write.\n region: regionOfHost(baseUrl),\n model: req.spec.model,\n transport: \"http\",\n capability: \"transcribe\",\n inputTokens: 0,\n outputTokens: 0,\n });\n if (req.durationSec !== undefined) {\n usage.costUsd = (req.durationSec / 60) * (VOXTRAL_PRICE_PER_MIN[req.spec.model] ?? 0);\n }\n return { text: data.text ?? \"\", usage };\n }\n\n // Batch (F016.1) — async chat at 50% cost. Upload a JSONL of requests → create\n // a job → poll status → download results. Each line: {custom_id, body:{model,messages}}.\n async function batchSubmit(req: { items: BatchRequestItem[]; spec: TierSpec }): Promise<BatchJob> {\n const jsonl = req.items\n .map((it) =>\n JSON.stringify({\n custom_id: it.customId,\n body: { model: req.spec.model, messages: [{ role: \"user\", content: it.prompt }] },\n }),\n )\n .join(\"\\n\");\n // Upload the input file (multipart, purpose=batch).\n const form = new FormData();\n form.append(\"purpose\", \"batch\");\n form.append(\"file\", new Blob([jsonl], { type: \"application/jsonl\" }), \"batch.jsonl\");\n const up = await fetchImpl(`${baseUrl}/files`, {\n method: \"POST\",\n headers: { authorization: `Bearer ${key()}` },\n body: form,\n });\n if (!up.ok) throw new Error(`mistral batch upload ${up.status}: ${(await up.text().catch(() => \"\")).slice(0, 200)}`);\n const fileId = ((await up.json()) as { id?: string }).id;\n // Create the batch job.\n const job = await fetchImpl(`${baseUrl}/batch/jobs`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", authorization: `Bearer ${key()}` },\n body: JSON.stringify({ input_files: [fileId], model: req.spec.model, endpoint: \"/v1/chat/completions\" }),\n });\n if (!job.ok) throw new Error(`mistral batch job ${job.status}: ${(await job.text().catch(() => \"\")).slice(0, 200)}`);\n const data = (await job.json()) as { id?: string; status?: string; total_requests?: number };\n return { jobId: data.id ?? \"\", status: data.status ?? \"queued\", total: data.total_requests };\n }\n\n async function batchStatus(req: { jobId: string; spec: TierSpec }): Promise<BatchJob> {\n const res = await fetchImpl(`${baseUrl}/batch/jobs/${req.jobId}`, { headers: { authorization: `Bearer ${key()}` } });\n if (!res.ok) throw new Error(`mistral batch status ${res.status}`);\n const d = (await res.json()) as { id?: string; status?: string; total_requests?: number; succeeded_requests?: number };\n return { jobId: d.id ?? req.jobId, status: d.status ?? \"unknown\", total: d.total_requests, completed: d.succeeded_requests };\n }\n\n async function batchResults(req: { jobId: string; spec: TierSpec }): Promise<BatchResultItem[]> {\n const job = await fetchImpl(`${baseUrl}/batch/jobs/${req.jobId}`, { headers: { authorization: `Bearer ${key()}` } });\n if (!job.ok) throw new Error(`mistral batch results ${job.status}`);\n const outputFile = ((await job.json()) as { output_file?: string }).output_file;\n if (!outputFile) throw new Error(\"mistral batch: job has no output_file yet (not finished)\");\n const content = await fetchImpl(`${baseUrl}/files/${outputFile}/content`, { headers: { authorization: `Bearer ${key()}` } });\n if (!content.ok) throw new Error(`mistral batch download ${content.status}`);\n const lines = (await content.text()).trim().split(\"\\n\").filter(Boolean);\n return lines.map((line) => {\n const row = JSON.parse(line) as { custom_id?: string; response?: { body?: { choices?: { message?: { content?: string } }[] } } };\n return { customId: row.custom_id ?? \"\", text: row.response?.body?.choices?.[0]?.message?.content ?? \"\" };\n });\n }\n\n return { ...base, ocr, moderate, embedding, transcribe, batchSubmit, batchStatus, batchResults };\n}\n","// ElevenLabs adapter (F020). Text-to-Dialogue (eleven_v3) turns a manuscript of\n// {text, voice_id} turns into ONE cohesive multi-voice audio episode — the\n// \"instant podcast\" primitive. Also single-voice TTS + voice listing. Audio out\n// is MP3 bytes; billed per character. Key from ELEVENLABS_API_KEY.\nimport { freshUsage } from \"../cost/usage.js\";\nimport type { ProviderAdapter, DialogueRequest, TtsRequest, PodcastResult } from \"../types.js\";\n\n/** USD per 1000 characters (ElevenLabs bills per char; API overage ≈ $0.10–0.18/1k). */\nconst ELEVENLABS_PRICE_PER_1K_CHARS = 0.15;\n\n/** Curated Danish voices (F020.3) — friendly name → ElevenLabs voiceId. Apps can\n * pass these names to `ai.podcast`/`ai.tts` instead of raw IDs. */\nexport const ELEVENLABS_DANISH_VOICES: Record<string, string> = {\n soren: \"xj6X4BCUsv9oxohm1E8o\",\n jesper: \"Bl1YwS3uJac5zEOSNESn\",\n mads: \"BIWC0507fYMfhPcAEIRP\",\n noam: \"V34B5u5UbLdNJVEkcgXp\",\n camilla: \"4RklGmuxoAskAbGXplXN\",\n};\n\n/** Resolve a curated voice name to its voiceId; pass a raw voiceId through unchanged. */\nexport function resolveVoice(nameOrId: string): string {\n return ELEVENLABS_DANISH_VOICES[nameOrId] ?? nameOrId;\n}\n\nexport interface ElevenLabsVoice {\n voiceId: string;\n name: string;\n language?: string;\n}\n\nexport function elevenlabsAdapter(\n config: { apiKey?: string; baseUrl?: string; fetch?: typeof fetch; pricePer1kChars?: number } = {},\n): ProviderAdapter & {\n listVoices(): Promise<ElevenLabsVoice[]>;\n} {\n const baseUrl = config.baseUrl ?? \"https://api.elevenlabs.io/v1\";\n const fetchImpl = config.fetch ?? fetch;\n\n function key(): string {\n const k = config.apiKey ?? process.env.ELEVENLABS_API_KEY;\n if (!k) throw new Error(\"elevenlabs adapter: API key not set (env ELEVENLABS_API_KEY)\");\n return k;\n }\n\n function priceFor(chars: number, model: string): ReturnType<typeof freshUsage> {\n const usage = freshUsage({\n provider: \"elevenlabs\",\n model,\n transport: \"http\",\n capability: \"podcast\",\n inputTokens: 0,\n outputTokens: 0,\n });\n usage.costUsd = (chars / 1000) * (config.pricePer1kChars ?? ELEVENLABS_PRICE_PER_1K_CHARS);\n return usage;\n }\n\n // Multi-voice dialogue → one episode. POST /text-to-dialogue.\n async function dialogue(req: DialogueRequest): Promise<PodcastResult> {\n const res = await fetchImpl(`${baseUrl}/text-to-dialogue`, {\n method: \"POST\",\n headers: { \"xi-api-key\": key(), \"content-type\": \"application/json\", accept: \"audio/mpeg\" },\n body: JSON.stringify({\n model_id: req.spec.model,\n inputs: req.inputs.map((t) => ({ text: t.text, voice_id: t.voiceId })),\n ...(req.format ? { output_format: req.format } : {}),\n }),\n });\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`elevenlabs dialogue ${res.status}: ${body.slice(0, 300)}`);\n }\n const audio = new Uint8Array(await res.arrayBuffer());\n const chars = req.inputs.reduce((n, t) => n + t.text.length, 0);\n return { audio, mimeType: \"audio/mpeg\", usage: priceFor(chars, req.spec.model) };\n }\n\n // Single-voice TTS. POST /text-to-speech/{voice_id}.\n async function tts(req: TtsRequest): Promise<PodcastResult> {\n const model = req.spec.model;\n const res = await fetchImpl(`${baseUrl}/text-to-speech/${req.voiceId}`, {\n method: \"POST\",\n headers: { \"xi-api-key\": key(), \"content-type\": \"application/json\", accept: \"audio/mpeg\" },\n body: JSON.stringify({ text: req.text, model_id: model }),\n });\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`elevenlabs tts ${res.status}: ${body.slice(0, 300)}`);\n }\n const audio = new Uint8Array(await res.arrayBuffer());\n return { audio, mimeType: \"audio/mpeg\", usage: priceFor(req.text.length, model) };\n }\n\n async function listVoices(): Promise<ElevenLabsVoice[]> {\n const res = await fetchImpl(`${baseUrl}/voices`, { headers: { \"xi-api-key\": key() } });\n if (!res.ok) throw new Error(`elevenlabs voices ${res.status}`);\n const data = (await res.json()) as { voices?: { voice_id: string; name: string; labels?: { language?: string } }[] };\n return (data.voices ?? []).map((v) => ({ voiceId: v.voice_id, name: v.name, language: v.labels?.language }));\n }\n\n return { name: \"elevenlabs\", dialogue, tts, listVoices };\n}\n","// Azure Speech (Cognitive Services) TTS adapter (F026). Natural EU-resident\n// neural Danish read-aloud behind the existing `ai.tts` capability. Azure Speech\n// is NOT reachable via OpenRouter (that proxies LLM chat/completions only) — this\n// is a direct SSML REST call, region-pinned to an EU host. Audio out is MP3 bytes;\n// billed per character. Key + region from AZURE_SPEECH_KEY / AZURE_SPEECH_REGION.\nimport { freshUsage } from \"../cost/usage.js\";\nimport { classifyRegionName, type Region } from \"../cost/region.js\";\nimport type { ProviderAdapter, TtsRequest, PodcastResult, TranscribeRequest, TranscribeResult } from \"../types.js\";\n\n/** USD per 1000 characters. ≈ Azure neural standard ($16 / 1M chars) — verify on\n * azure.microsoft.com/pricing; override via config.pricePer1kChars. */\nconst AZURE_TTS_PRICE_PER_1K_CHARS = 0.016;\n\n/** USD per audio-minute for speech-to-text. ≈ Azure standard STT ($1 / audio-hour\n * = $0.0167/min) — verify the fast-transcription rate on azure.microsoft.com/pricing;\n * override via config.sttPricePerMin. */\nconst AZURE_STT_PRICE_PER_MIN = 0.0167;\n\n/** Fast-transcription REST api-version. 2025-10-15 is required for the `phraseList`\n * biasing field (2024-11-15 rejects it as \"Invalid JSON\"); both serve plain\n * transcription. Override via config.sttApiVersion. (Live-verified F029.) */\nconst DEFAULT_STT_API_VERSION = \"2025-10-15\";\n\n/** Default region — EU/GDPR-clean. Override via config.region / AZURE_SPEECH_REGION. */\nconst DEFAULT_REGION = \"westeurope\";\n\n/** Default MP3 output (Azure's X-Microsoft-OutputFormat). */\nconst DEFAULT_FORMAT = \"audio-24khz-48kbitrate-mono-mp3\";\n\n/** Short language code → Azure STT locale. A full locale (\"da-DK\") passes through;\n * omitted language defaults to da-DK (the EU-Danish use-case this was built for). */\nconst AZURE_LOCALE_MAP: Record<string, string> = {\n da: \"da-DK\", en: \"en-US\", de: \"de-DE\", sv: \"sv-SE\", nb: \"nb-NO\", no: \"nb-NO\",\n fi: \"fi-FI\", nl: \"nl-NL\", fr: \"fr-FR\", es: \"es-ES\", it: \"it-IT\", pt: \"pt-PT\",\n};\nfunction toAzureLocale(lang?: string): string {\n if (!lang) return \"da-DK\";\n if (lang.includes(\"-\")) return lang;\n return AZURE_LOCALE_MAP[lang.toLowerCase()] ?? lang;\n}\n\n/** A curated Danish-speaking Azure voice, exposed so a consuming app can render a\n * picker. `native` = a true da-DK voice (most natural); otherwise a multilingual\n * voice that also speaks Danish (Azure has only 2 native da-DK voices). */\nexport interface AzureVoiceInfo {\n /** Friendly name a caller passes as `voice` (e.g. \"christel\"). */\n name: string;\n /** Full Azure voice name (e.g. \"da-DK-ChristelNeural\"). */\n voiceId: string;\n gender: \"female\" | \"male\";\n /** Display label for a UI picker. */\n display: string;\n /** True for the 2 native da-DK voices; false for multilingual voices speaking Danish. */\n native: boolean;\n /** Per-voice default speaking rate, applied when a call passes no explicit `rate`\n * (e.g. Christel reads a touch fast, so her natural default is 0.85). Omitted = 1 (normal). */\n defaultRate?: number;\n}\n\n/** Curated da-DK roster (F026) — 2 native + 4 multilingual, 3 of each gender.\n * Verified against Azure's voices/list (only Christel + Jeppe are native da-DK). */\nexport const AZURE_DANISH_VOICE_LIST: AzureVoiceInfo[] = [\n { name: \"christel\", voiceId: \"da-DK-ChristelNeural\", gender: \"female\", display: \"Christel\", native: true, defaultRate: 0.85 },\n { name: \"seraphina\", voiceId: \"de-DE-SeraphinaMultilingualNeural\", gender: \"female\", display: \"Seraphina\", native: false },\n { name: \"ava\", voiceId: \"en-US-AvaMultilingualNeural\", gender: \"female\", display: \"Ava\", native: false },\n { name: \"jeppe\", voiceId: \"da-DK-JeppeNeural\", gender: \"male\", display: \"Jeppe\", native: true },\n { name: \"florian\", voiceId: \"de-DE-FlorianMultilingualNeural\", gender: \"male\", display: \"Florian\", native: false },\n { name: \"andrew\", voiceId: \"en-US-AndrewMultilingualNeural\", gender: \"male\", display: \"Andrew\", native: false },\n];\n\n/** Friendly name → full Azure voice name. Distinct from ELEVENLABS_DANISH_VOICES so\n * the client's resolveVoice passes these through unchanged to this adapter. */\nexport const AZURE_DANISH_VOICES: Record<string, string> = Object.fromEntries(\n AZURE_DANISH_VOICE_LIST.map((v) => [v.name, v.voiceId]),\n);\n\n/** The curated Danish voice roster, for a consuming app to present in a picker. */\nexport function listAzureDanishVoices(): AzureVoiceInfo[] {\n return AZURE_DANISH_VOICE_LIST;\n}\n\n/** Resolve a curated friendly name to its full Azure voice; pass a full voice name\n * (e.g. \"da-DK-ChristelNeural\") through unchanged. */\nexport function resolveAzureVoice(nameOrVoice: string): string {\n return AZURE_DANISH_VOICES[nameOrVoice] ?? nameOrVoice;\n}\n\n/** XML-escape so a `&`/`<` in the text can't break the SSML envelope. */\nfunction xmlEscape(s: string): string {\n return s\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n\n/** Derive the BCP-47 locale from a voice name: \"da-DK-ChristelNeural\" → \"da-DK\".\n * Exported so the F037 voice registry derives locales from this one implementation\n * instead of keeping a second copy of the rule. */\nexport function localeOf(voice: string): string {\n const parts = voice.split(\"-\");\n return parts.length >= 2 ? `${parts[0]}-${parts[1]}` : \"en-US\";\n}\n\nexport function azureAdapter(\n config: {\n apiKey?: string;\n region?: string;\n fetch?: typeof fetch;\n pricePer1kChars?: number;\n /** USD per audio-minute for transcribe (overrides AZURE_STT_PRICE_PER_MIN). */\n sttPricePerMin?: number;\n /** STT base URL override (e.g. a resource custom domain). */\n sttBaseUrl?: string;\n /** Resource name → custom-domain STT host `{resource}.cognitiveservices.azure.com`\n * (or env AZURE_SPEECH_RESOURCE). Without it, STT uses the regional host. */\n resource?: string;\n /** Fast-transcription api-version (overrides the GA default). */\n sttApiVersion?: string;\n /** phraseList biasing weight (0–2) applied when a call passes `phrases`. Default 1.5. */\n sttBiasingWeight?: number;\n } = {},\n): ProviderAdapter {\n const fetchImpl = config.fetch ?? fetch;\n\n function key(): string {\n const k = config.apiKey ?? process.env.AZURE_SPEECH_KEY;\n if (!k) throw new Error(\"azure adapter: API key not set (env AZURE_SPEECH_KEY)\");\n return k;\n }\n function region(): string {\n return config.region ?? process.env.AZURE_SPEECH_REGION ?? DEFAULT_REGION;\n }\n /** STT host. Default = regional cognitive host; a resource name (config/env) →\n * the custom-domain host (some resources require it). Live-verified per resource. */\n /** Residency of the STT host we will ACTUALLY call. sttBaseUrl() may come from a\n * custom URL or a resource name, neither of which derives from region() — so\n * reading region() here reported \"eu\" for a call to a US resource whenever\n * AZURE_SPEECH_REGION was left at its default. Exactly the failure F042 exists to\n * prevent, found in review of F042. A resource host carries no region in its name,\n * so it is honestly \"unknown\" unless an explicit region says otherwise. */\n function sttRegion(): Region {\n if (config.sttBaseUrl || config.resource || process.env.AZURE_SPEECH_RESOURCE) {\n // An explicitly-set region still wins — the caller told us where the resource is.\n return config.region ?? process.env.AZURE_SPEECH_REGION\n ? classifyRegionName(region())\n : \"unknown\";\n }\n return classifyRegionName(region());\n }\n\n function sttBaseUrl(): string {\n if (config.sttBaseUrl) return config.sttBaseUrl.replace(/\\/$/, \"\");\n const resource = config.resource ?? process.env.AZURE_SPEECH_RESOURCE;\n if (resource) return `https://${resource}.cognitiveservices.azure.com`;\n return `https://${region()}.api.cognitive.microsoft.com`;\n }\n\n function priceFor(chars: number, model: string): ReturnType<typeof freshUsage> {\n const usage = freshUsage({\n provider: \"azure\",\n model,\n // Same region() that picked the host. westeurope by default, but\n // config.region / AZURE_SPEECH_REGION can point this at eastus.\n region: classifyRegionName(region()),\n transport: \"http\",\n capability: \"tts\",\n inputTokens: 0,\n outputTokens: 0,\n });\n usage.costUsd = (chars / 1000) * (config.pricePer1kChars ?? AZURE_TTS_PRICE_PER_1K_CHARS);\n return usage;\n }\n\n // Single-voice TTS. POST .../cognitiveservices/v1 with an SSML body.\n async function tts(req: TtsRequest): Promise<PodcastResult> {\n const voice = resolveAzureVoice(req.voiceId);\n const lang = req.lang ?? localeOf(voice);\n const format = req.format ?? DEFAULT_FORMAT;\n // Speaking rate via SSML <prosody>: a multiplier of the default (1 = normal,\n // 0.9 = 10% slower, 1.1 = 10% faster). An explicit req.rate wins; otherwise the\n // voice's own defaultRate (e.g. Christel = 0.85) applies; else no wrapper.\n const escaped = xmlEscape(req.text);\n const effRate = req.rate ?? AZURE_DANISH_VOICE_LIST.find((v) => v.voiceId === voice)?.defaultRate;\n const inner =\n effRate != null && effRate !== 1 ? `<prosody rate='${effRate}'>${escaped}</prosody>` : escaped;\n const ssml =\n `<speak version='1.0' xml:lang='${lang}'>` +\n `<voice name='${voice}'>${inner}</voice></speak>`;\n const res = await fetchImpl(\n `https://${region()}.tts.speech.microsoft.com/cognitiveservices/v1`,\n {\n method: \"POST\",\n headers: {\n \"Ocp-Apim-Subscription-Key\": key(),\n \"Content-Type\": \"application/ssml+xml\",\n \"X-Microsoft-OutputFormat\": format,\n },\n body: ssml,\n },\n );\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`azure tts ${res.status}: ${body.slice(0, 300)}`);\n }\n const audio = new Uint8Array(await res.arrayBuffer());\n return { audio, mimeType: \"audio/mpeg\", usage: priceFor(req.text.length, req.spec.model) };\n }\n\n // Speech-to-text (F029) via Azure fast transcription. Synchronous multipart POST\n // → { combinedPhrases:[{text}], durationMilliseconds }. da-DK forced (Voxtral can't).\n // Cost is per audio-minute from the response's real duration. EU-resident.\n async function transcribe(req: TranscribeRequest): Promise<TranscribeResult> {\n const locale = toAzureLocale(req.language);\n const definition: Record<string, unknown> = { locales: [locale] };\n // Bias toward known brand/jargon terms (F029.3) — lifts accuracy on names the\n // model wouldn't otherwise know (e.g. \"cardmem\", \"Pins\"). Other STTs ignore phrases.\n if (req.phrases && req.phrases.length > 0) {\n definition.phraseList = { phrases: req.phrases, biasingWeight: config.sttBiasingWeight ?? 1.5 };\n }\n const form = new FormData();\n form.append(\"audio\", new Blob([req.audio]), \"audio\");\n form.append(\"definition\", JSON.stringify(definition));\n const url = `${sttBaseUrl()}/speechtotext/transcriptions:transcribe?api-version=${config.sttApiVersion ?? DEFAULT_STT_API_VERSION}`;\n const res = await fetchImpl(url, {\n method: \"POST\",\n headers: { \"Ocp-Apim-Subscription-Key\": key() },\n body: form,\n });\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`azure transcribe ${res.status}: ${body.slice(0, 300)}`);\n }\n const data = (await res.json()) as {\n combinedPhrases?: { text?: string }[];\n durationMilliseconds?: number;\n // Fast-transcription phrases carry ms offsets + per-word timing (F036.1).\n phrases?: {\n text?: string;\n offsetMilliseconds?: number;\n durationMilliseconds?: number;\n words?: { text?: string; offsetMilliseconds?: number; durationMilliseconds?: number }[];\n }[];\n };\n const text = data.combinedPhrases?.[0]?.text ?? \"\";\n // Prefer the API's real duration; fall back to a caller-supplied durationSec.\n const minutes =\n data.durationMilliseconds != null\n ? data.durationMilliseconds / 60000\n : (req.durationSec ?? 0) / 60;\n const usage = freshUsage({\n provider: \"azure\",\n model: req.spec.model,\n region: sttRegion(),\n transport: \"http\",\n capability: \"transcribe\",\n inputTokens: 0,\n outputTokens: 0,\n });\n usage.costUsd = minutes * (config.sttPricePerMin ?? AZURE_STT_PRICE_PER_MIN);\n const result: TranscribeResult = { text, usage };\n // Timestamps (F036.1) — Azure fast-transcription already returns phrases+words\n // with ms offsets; surface them on the same TranscribeResult shape as Whisper.\n // \"word\" granularity → words[]; any timestamps request → segments[].\n if (req.timestamps && req.timestamps.length > 0 && data.phrases) {\n const toSec = (ms?: number) => (ms ?? 0) / 1000;\n if (req.timestamps.includes(\"word\")) {\n const words = data.phrases.flatMap((p) => p.words ?? []);\n if (words.length > 0) {\n result.words = words.map((w) => ({\n word: w.text ?? \"\",\n start: toSec(w.offsetMilliseconds),\n end: toSec((w.offsetMilliseconds ?? 0) + (w.durationMilliseconds ?? 0)),\n }));\n }\n }\n result.segments = data.phrases.map((p) => ({\n text: p.text ?? \"\",\n start: toSec(p.offsetMilliseconds),\n end: toSec((p.offsetMilliseconds ?? 0) + (p.durationMilliseconds ?? 0)),\n }));\n }\n return result;\n }\n\n return { name: \"azure\", tts, transcribe };\n}\n","// Google Cloud Vertex AI adapter (F031) — EU-resident `ai.animate` (Veo). Reuses\n// the exact Veo request/poll/download shape proven live in gemini.ts (F024), but\n// swaps: (a) endpoint → a region-pinned Vertex host (default europe-west1, the\n// whole reason this adapter exists), (b) auth → a GCP service-account OAuth2\n// Bearer token, self-minted via node:crypto (zero extra deps), not an API key.\n//\n// UNVERIFIED SHAPE NOTE: the inline-bytes response parsing below (`response.\n// videos[].bytesBase64Encoded`) is our best-effort read of Vertex's public Veo\n// docs — it has not yet been proven against a real Vertex response (F031.3's\n// live smoke does that). A `gcsUri`-shaped response throws a clear error rather\n// than silently mis-parsing.\nimport { createSign } from \"node:crypto\";\nimport { readFileSync } from \"node:fs\";\nimport { toInlineImage } from \"./media.js\";\nimport { partsFrom, type GeminiPart, splitCached } from \"./gemini.js\";\nimport { freshUsage, computeCost } from \"../cost/usage.js\";\nimport { classifyRegionName } from \"../cost/region.js\";\nimport { errorBody } from \"../transport/http.js\";\nimport type {\n ProviderAdapter,\n AnimateRequest,\n AnimateResult,\n ChatRequest,\n ChatResult,\n Message,\n} from \"../types.js\";\n\nconst TOKEN_ENDPOINT = \"https://oauth2.googleapis.com/token\";\nconst DEFAULT_REGION = \"europe-west1\";\nconst CLOUD_PLATFORM_SCOPE = \"https://www.googleapis.com/auth/cloud-platform\";\n\n/** Per-SECOND USD for Veo on Vertex — same model family/pricing as the consumer\n * Gemini API (F024's VEO_PRICE_PER_SEC). Override per call via config.pricePerSecond. */\nconst VERTEX_VEO_PRICE_PER_SEC: Record<string, number> = {\n \"veo-3.1-generate-preview\": 0.4,\n \"veo-3.1-fast-generate-preview\": 0.1,\n \"veo-3.1-lite-generate-preview\": 0.05,\n \"veo-3.0-generate-001\": 0.4,\n \"veo-3.0-fast-generate-001\": 0.1,\n};\n\ninterface ServiceAccountCredentials {\n client_email: string;\n private_key: string;\n /** Present in a real service-account key; used as the project fallback (F038). */\n project_id?: string;\n}\n\ninterface VertexOperation {\n done?: boolean;\n error?: { message?: string };\n response?: {\n videos?: { bytesBase64Encoded?: string; gcsUri?: string; mimeType?: string }[];\n };\n}\n\nfunction base64url(input: Buffer | string): string {\n const buf = typeof input === \"string\" ? Buffer.from(input) : input;\n return buf.toString(\"base64\").replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n}\n\nfunction resolveCredentials(config: { credentials?: string }): ServiceAccountCredentials {\n const inline = config.credentials ?? process.env.GOOGLE_VERTEX_CREDENTIALS;\n if (inline) {\n try {\n return JSON.parse(inline) as ServiceAccountCredentials;\n } catch {\n throw new Error(\"vertex adapter: GOOGLE_VERTEX_CREDENTIALS is not valid JSON\");\n }\n }\n const path = process.env.GOOGLE_APPLICATION_CREDENTIALS;\n if (path) {\n let raw: string;\n try {\n raw = readFileSync(path, \"utf8\");\n } catch (err) {\n throw new Error(`vertex adapter: failed to read GOOGLE_APPLICATION_CREDENTIALS file: ${(err as Error).message}`);\n }\n return JSON.parse(raw) as ServiceAccountCredentials;\n }\n throw new Error(\n \"vertex adapter: service-account credentials not set (env GOOGLE_VERTEX_CREDENTIALS inline JSON, or GOOGLE_APPLICATION_CREDENTIALS file path)\",\n );\n}\n\n/** Self-sign a JWT and exchange it for a Bearer access token — no google-auth-library dep. */\nasync function mintAccessToken(\n creds: ServiceAccountCredentials,\n fetchImpl: typeof fetch,\n): Promise<{ token: string; expiresAt: number }> {\n const now = Math.floor(Date.now() / 1000);\n const header = { alg: \"RS256\", typ: \"JWT\" };\n const claims = {\n iss: creds.client_email,\n scope: CLOUD_PLATFORM_SCOPE,\n aud: TOKEN_ENDPOINT,\n iat: now,\n exp: now + 3600,\n };\n const unsigned = `${base64url(JSON.stringify(header))}.${base64url(JSON.stringify(claims))}`;\n const signature = createSign(\"RSA-SHA256\").update(unsigned).sign(creds.private_key);\n const jwt = `${unsigned}.${base64url(signature)}`;\n\n const res = await fetchImpl(TOKEN_ENDPOINT, {\n method: \"POST\",\n headers: { \"content-type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({\n grant_type: \"urn:ietf:params:oauth:grant-type:jwt-bearer\",\n assertion: jwt,\n }).toString(),\n });\n if (!res.ok) {\n throw new Error(`vertex adapter: token exchange failed ${res.status}: ${(await res.text().catch(() => \"\")).slice(0, 300)}`);\n }\n const data = (await res.json()) as { access_token?: string; expires_in?: number };\n if (!data.access_token) throw new Error(\"vertex adapter: token exchange returned no access_token\");\n return { token: data.access_token, expiresAt: Date.now() + (data.expires_in ?? 3600) * 1000 };\n}\n\nexport function vertexAdapter(\n config: {\n /** Inline service-account JSON; else env GOOGLE_VERTEX_CREDENTIALS or GOOGLE_APPLICATION_CREDENTIALS (file path). */\n credentials?: string;\n /** GCP project id; else env GOOGLE_VERTEX_PROJECT. Required — never guessed. */\n project?: string;\n /** Vertex region; default \"europe-west1\" (EU by default — this adapter's reason to exist). */\n region?: string;\n fetch?: typeof fetch;\n pricePerSecond?: number;\n pollIntervalMs?: number;\n videoTimeoutMs?: number;\n } = {},\n): ProviderAdapter {\n const fetchImpl = config.fetch ?? fetch;\n let cached: { token: string; expiresAt: number } | null = null;\n\n function region(): string {\n return config.region ?? process.env.GOOGLE_VERTEX_REGION ?? DEFAULT_REGION;\n }\n function project(): string {\n // The service-account JSON already carries project_id, so falling back to it\n // spares every consumer a second env var whose value is sitting in the first\n // one — and spares them a \"project not set\" error that looks like a bug.\n const p =\n config.project ?? process.env.GOOGLE_VERTEX_PROJECT ?? resolveCredentials(config).project_id;\n if (!p) throw new Error(\"vertex adapter: project not set (config.project, env GOOGLE_VERTEX_PROJECT, or project_id in the credentials)\");\n return p;\n }\n async function accessToken(): Promise<string> {\n if (cached && cached.expiresAt - 60_000 > Date.now()) return cached.token;\n const creds = resolveCredentials(config);\n cached = await mintAccessToken(creds, fetchImpl);\n return cached.token;\n }\n\n async function animate(req: AnimateRequest): Promise<AnimateResult> {\n const token = await accessToken();\n const proj = project();\n const reg = region();\n const pollIntervalMs = config.pollIntervalMs ?? 5000;\n const deadline = Date.now() + (config.videoTimeoutMs ?? 300000);\n const baseUrl = `https://${reg}-aiplatform.googleapis.com/v1`;\n\n const { data, mimeType } = await toInlineImage(req.image, fetchImpl);\n const parameters: Record<string, unknown> = {};\n if (req.durationSec !== undefined) parameters.durationSeconds = req.durationSec;\n if (req.resolution !== undefined) parameters.resolution = req.resolution;\n const body = {\n instances: [{ prompt: req.prompt ?? \"\", image: { bytesBase64Encoded: data, mimeType } }],\n ...(Object.keys(parameters).length ? { parameters } : {}),\n };\n\n const submit = await fetchImpl(\n `${baseUrl}/projects/${proj}/locations/${reg}/publishers/google/models/${req.spec.model}:predictLongRunning`,\n {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", authorization: `Bearer ${token}` },\n body: JSON.stringify(body),\n },\n );\n if (!submit.ok) {\n throw new Error(`vertex animate ${submit.status}: ${(await submit.text().catch(() => \"\")).slice(0, 300)}`);\n }\n const op = (await submit.json()) as { name?: string };\n if (!op.name) throw new Error(\"vertex animate: no operation name in submit response\");\n\n let videoB64: string | undefined;\n let videoMime = \"video/mp4\";\n for (;;) {\n const poll = await fetchImpl(`${baseUrl}/${op.name}`, { headers: { authorization: `Bearer ${token}` } });\n if (!poll.ok) throw new Error(`vertex animate poll ${poll.status}`);\n const opData = (await poll.json()) as VertexOperation;\n if (opData.error) throw new Error(`vertex animate: ${opData.error.message ?? \"operation error\"}`);\n if (opData.done) {\n const video = opData.response?.videos?.[0];\n if (!video) {\n throw new Error(`vertex animate: done but no video in response: ${errorBody(opData.response)}`);\n }\n if (!video.bytesBase64Encoded) {\n if (video.gcsUri) {\n throw new Error(\n `vertex animate: response returned a gcsUri (\"${video.gcsUri}\") — GCS download not yet supported (F031.x); this build only handles inline bytes`,\n );\n }\n throw new Error(`vertex animate: done but no bytesBase64Encoded in response: ${errorBody(opData.response)}`);\n }\n videoB64 = video.bytesBase64Encoded;\n videoMime = video.mimeType ?? \"video/mp4\";\n break;\n }\n if (Date.now() >= deadline) throw new Error(\"vertex animate: timed out\");\n await new Promise((r) => setTimeout(r, pollIntervalMs));\n }\n\n const usage = freshUsage({\n provider: \"vertex\",\n model: req.spec.model,\n // Read from the SAME region() that built the URL above — this adapter is EU by\n // default, but config.region / GOOGLE_VERTEX_REGION can move it, and a residency\n // field that ignores the override is worse than none.\n region: classifyRegionName(region()),\n transport: \"http\",\n capability: \"animate\",\n inputTokens: 0,\n outputTokens: 0,\n });\n const perSec = config.pricePerSecond ?? VERTEX_VEO_PRICE_PER_SEC[req.spec.model] ?? 0;\n usage.costUsd = perSec * (req.durationSec ?? 8);\n return { url: `vertex://${op.name}`, bytes: Buffer.from(videoB64, \"base64\"), mimeType: videoMime, usage };\n }\n\n // EU-resident image + VIDEO analysis (F038). Vertex speaks the same\n // generateContent shape as the Gemini API, so the message→parts mapping is\n // imported rather than copied. The URL is region-pinned exactly like animate:\n // personal data (faces, EXIF geo) must not leave the EU, and there is NO\n // fallback to another region — an EU error propagates to the caller.\n async function vision(req: ChatRequest): Promise<ChatResult> {\n const token = await accessToken();\n const proj = project();\n const reg = region();\n\n const systemParts: GeminiPart[] = [];\n const contents: { role: string; parts: GeminiPart[] }[] = [];\n for (const m of req.messages as Message[]) {\n if (m.role === \"system\") systemParts.push(...partsFrom(m.content));\n else contents.push({ role: m.role === \"assistant\" ? \"model\" : \"user\", parts: partsFrom(m.content) });\n }\n const body: Record<string, unknown> = { contents };\n if (systemParts.length > 0) body.systemInstruction = { parts: systemParts };\n const genConfig: Record<string, unknown> = {};\n if (req.maxTokens !== undefined) genConfig.maxOutputTokens = req.maxTokens;\n if (req.temperature !== undefined) genConfig.temperature = req.temperature;\n if (Object.keys(genConfig).length > 0) body.generationConfig = genConfig;\n\n const url =\n `https://${reg}-aiplatform.googleapis.com/v1/projects/${proj}` +\n `/locations/${reg}/publishers/google/models/${req.spec.model}:generateContent`;\n const res = await fetchImpl(url, {\n method: \"POST\",\n headers: { authorization: `Bearer ${token}`, \"content-type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n if (!res.ok) {\n throw new Error(`vertex vision ${res.status}: ${(await res.text().catch(() => \"\")).slice(0, 300)}`);\n }\n const data = (await res.json()) as {\n candidates?: { content?: { parts?: GeminiPart[] } }[];\n usageMetadata?: { promptTokenCount?: number; candidatesTokenCount?: number; cachedContentTokenCount?: number };\n };\n const text = (data.candidates?.[0]?.content?.parts ?? [])\n .map((p) => p.text ?? \"\")\n .join(\"\")\n .trim();\n\n // F040: Vertex serves the same Gemini models and the same usageMetadata shape,\n // so it reuses gemini.ts's splitter rather than keeping a second copy of the\n // subtraction rule. promptTokenCount INCLUDES cachedContentTokenCount.\n const { inputTokens, cacheReadTokens } = splitCached(data.usageMetadata);\n const outputTokens = data.usageMetadata?.candidatesTokenCount ?? 0;\n const usage = freshUsage({\n provider: \"vertex\",\n model: req.spec.model,\n // Read from the SAME region() that built the URL above — this adapter is EU by\n // default, but config.region / GOOGLE_VERTEX_REGION can move it, and a residency\n // field that ignores the override is worse than none.\n region: classifyRegionName(region()),\n transport: \"http\",\n capability: \"vision\",\n inputTokens,\n outputTokens,\n ...(cacheReadTokens === undefined ? {} : { cacheReadTokens }),\n });\n usage.costUsd = computeCost(\"vertex\", req.spec.model, inputTokens, outputTokens, cacheReadTokens ?? 0);\n return { text, usage };\n }\n\n return { name: \"vertex\", animate, vision };\n}\n","// DeepL translation adapter (F032) — a dedicated MT engine, not a chat model.\n// Implements ProviderAdapter.translate directly (no chat prompt-contract).\n// EU-hosted (Falun, Sweden per deepl.com). Opt-in via override:{provider:\"deepl\"};\n// the LLM-prompt-based ai.translate stays the default for every other provider.\n//\n// CONTRACT NOTE: DeepL requires real language codes (\"DA\", \"EN-US\", \"DE\", …) in\n// `to`/`from` — NOT the free-form names the chat-based route accepts (\"Danish\").\n// This adapter does not translate names to codes; pass DeepL's own codes.\nimport { freshUsage } from \"../cost/usage.js\";\nimport { regionOfHost } from \"../cost/region.js\";\nimport type { ProviderAdapter, TranslateRequest, TranslateResult } from \"../types.js\";\n\n/** USD per 1000 characters. UNVERIFIED ESTIMATE — DeepL's own pricing pages\n * resisted automated fetch (JS-rendered / bot-protected) as of 2026-06-20;\n * third-party sources converge loosely around €20/1M chars for the Pro API,\n * but conflicting subscription-tier reports exist. Verify against\n * deepl.com/pro-api directly before relying on this for a budget decision.\n * Override via config.pricePer1kChars. Free-tier (\":fx\" key, within quota) is\n * genuinely $0 — this rate only matters for Pro usage past the free allowance. */\nconst DEEPL_PRICE_PER_1K_CHARS_ESTIMATE = 0.0217;\n\nexport function deeplAdapter(\n config: { apiKey?: string; baseUrl?: string; fetch?: typeof fetch; pricePer1kChars?: number } = {},\n): ProviderAdapter {\n const fetchImpl = config.fetch ?? fetch;\n\n function key(): string {\n const k = config.apiKey ?? process.env.DEEPL_API_KEY;\n if (!k) throw new Error(\"deepl adapter: API key not set (env DEEPL_API_KEY)\");\n return k;\n }\n\n // DeepL Free API keys always end in \":fx\" — a documented DeepL convention —\n // and must hit the free-tier host, not the Pro one.\n function baseUrl(apiKey: string): string {\n return config.baseUrl ?? (apiKey.endsWith(\":fx\") ? \"https://api-free.deepl.com\" : \"https://api.deepl.com\");\n }\n\n async function translate(req: TranslateRequest): Promise<TranslateResult> {\n const apiKey = key();\n const body: Record<string, unknown> = { text: [req.text], target_lang: req.to.toUpperCase() };\n if (req.from) body.source_lang = req.from.toUpperCase();\n\n const res = await fetchImpl(`${baseUrl(apiKey)}/v2/translate`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", authorization: `DeepL-Auth-Key ${apiKey}` },\n body: JSON.stringify(body),\n });\n if (!res.ok) {\n const errBody = await res.text().catch(() => \"\");\n throw new Error(`deepl translate ${res.status}: ${errBody.slice(0, 300)}`);\n }\n const data = (await res.json()) as { translations?: { text?: string; detected_source_language?: string }[] };\n const text = data.translations?.[0]?.text;\n if (text === undefined) throw new Error(\"deepl translate: response contained no translation\");\n\n const usage = freshUsage({\n provider: \"deepl\",\n region: regionOfHost(baseUrl(apiKey)),\n model: req.spec.model,\n transport: \"http\",\n capability: \"translate\",\n inputTokens: 0,\n outputTokens: 0,\n });\n usage.costUsd = (req.text.length / 1000) * (config.pricePer1kChars ?? DEEPL_PRICE_PER_1K_CHARS_ESTIMATE);\n return { text, usage };\n }\n\n return { name: \"deepl\", translate };\n}\n","// fal.ai adapter (F5.3 + F021). Image modes, both observed in the F1 inventory:\n// - sync : POST https://fal.run/{model}, image URL straight back (sanneandersen)\n// - queue : POST https://queue.fal.run/{model} → poll status → fetch result\n// F021 adds LoRA style-training (trainStyle) + LoRA inference (image loras).\n// Auth header `Authorization: Key <FAL_KEY>`. No @fal-ai/client — plain fetch.\nimport { deflateRawSync, crc32 } from \"node:zlib\";\nimport { freshUsage } from \"../cost/usage.js\";\nimport type {\n ProviderAdapter,\n ImageRequest,\n ImageResult,\n AnimateRequest,\n AnimateResult,\n TrainStyleRequest,\n TrainStyleResult,\n} from \"../types.js\";\n\ninterface FalImagesResponse {\n images?: { url?: string }[];\n has_nsfw_concepts?: boolean[];\n error?: unknown;\n}\ninterface FalTrainResponse {\n diffusers_lora_file?: { url?: string };\n config_file?: { url?: string };\n}\ninterface FalQueueSubmit {\n request_id?: string;\n status_url?: string;\n response_url?: string;\n}\ninterface FalQueueStatus {\n status?: \"IN_QUEUE\" | \"IN_PROGRESS\" | \"COMPLETED\" | \"FAILED\";\n}\n\nexport interface FalAdapterConfig {\n apiKey?: string;\n /** \"sync\" (default — fal.run, fast models) or \"queue\" (queue.fal.run, polled). */\n mode?: \"sync\" | \"queue\";\n syncBaseUrl?: string;\n queueBaseUrl?: string;\n pollIntervalMs?: number;\n timeoutMs?: number;\n /** Deadline for training jobs — they take minutes (default 600000 = 10 min). */\n trainTimeoutMs?: number;\n /** Deadline for video jobs — they take minutes (default 600000 = 10 min). */\n videoTimeoutMs?: number;\n fetch?: typeof fetch;\n /** Override the per-image USD price (else a built-in estimate per model, 0 if unknown). */\n pricePerImage?: number;\n /** Override the flat per-training USD price (else ~$2 estimate). */\n pricePerTraining?: number;\n /** Override the per-SECOND video USD price (else a built-in estimate per model, 0 if unknown). */\n pricePerSecond?: number;\n}\n\n// Per-image USD ESTIMATES (fal prices by megapixel/model and changes often —\n// verify before relying on these; override via config.pricePerImage). fal does\n// not return a price, so this is the SDK's best-effort cost for `usage.costUsd`.\nconst FAL_IMAGE_PRICE_ESTIMATE: Record<string, number> = {\n \"fal-ai/flux/schnell\": 0.003,\n \"fal-ai/flux/dev\": 0.025,\n \"fal-ai/flux-lora\": 0.025,\n \"fal-ai/flux-pro\": 0.05,\n \"fal-ai/flux-pro/v1.1\": 0.04,\n};\n// Flat training estimate (fal-ai/flux-lora-fast-training, ~$2; override via config).\nconst FAL_TRAIN_PRICE_ESTIMATE = 2.0;\n\n// Per-SECOND USD estimates for video models (F024). fal does not return a price,\n// and rates vary by model/resolution — entries are fal's OFFICIAL published\n// per-second rate (fal.ai/models/<id> pricing), not guessed; override via\n// config.pricePerSecond. Unknown model → 0 (cost surfaced via a live smoke,\n// not a fabricated number).\nconst FAL_VIDEO_PRICE_PER_SEC: Record<string, number> = {\n // Kling 2.5 Turbo Pro i2v — the blessed FAL_KEY-only image→video route (F014\n // contentpush spike). $0.35 for the first 5 s + $0.07/additional s = a flat\n // $0.07/s (1080p); per-second-billed, commercial-use, not deprecated.\n \"fal-ai/kling-video/v2.5-turbo/pro/image-to-video\": 0.07,\n};\n// Default clip length to bill when the caller doesn't pass durationSec (Veo ≈ 8s).\nconst FAL_VIDEO_DEFAULT_SEC = 8;\n\nconst sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));\n\nexport function falAdapter(config: FalAdapterConfig = {}): ProviderAdapter {\n const doFetch = config.fetch ?? fetch;\n const syncBase = config.syncBaseUrl ?? \"https://fal.run\";\n const queueBase = config.queueBaseUrl ?? \"https://queue.fal.run\";\n const pollIntervalMs = config.pollIntervalMs ?? 2000;\n const timeoutMs = config.timeoutMs ?? 60000;\n\n // sa flagged the gotcha: their env is FAL_API_KEY, the older convention is FAL_KEY.\n // Accept either so no repo has to alias one to the other.\n const resolveKey = () => config.apiKey ?? process.env.FAL_KEY ?? process.env.FAL_API_KEY;\n const authHeaders = (apiKey: string) => ({\n \"content-type\": \"application/json\",\n Authorization: `Key ${apiKey}`,\n });\n\n async function image(req: ImageRequest): Promise<ImageResult> {\n const apiKey = resolveKey();\n if (!apiKey) throw new Error(\"fal adapter: API key not set (env FAL_KEY or FAL_API_KEY)\");\n const headers = authHeaders(apiKey);\n\n const body: Record<string, unknown> = { prompt: req.prompt };\n if (req.width !== undefined && req.height !== undefined) {\n body.image_size = { width: req.width, height: req.height };\n }\n if (req.loras && req.loras.length > 0) {\n body.loras = req.loras.map((l) => ({ path: l.path, scale: l.scale ?? 1 }));\n }\n\n const mode = config.mode ?? \"sync\";\n const run = (b: Record<string, unknown>) =>\n mode === \"sync\" ? runSync(req.spec.model, headers, b) : runQueue(req.spec.model, headers, b);\n\n let calls = 1;\n let { url, flagged } = await run(body);\n // F021.4 — fal's NSFW safety-checker occasionally false-positives on clean\n // LoRA output and returns a fully BLACK image (has_nsfw_concepts[0]=true).\n // When retryOnBlack is set, re-roll ONCE with a fresh seed.\n if (flagged && req.retryOnBlack) {\n calls++;\n ({ url, flagged } = await run({ ...body, seed: Math.floor(Math.random() * 1e9) }));\n }\n\n // fal returns no price; estimate per-image so usage.costUsd isn't silently 0.\n // A re-roll is a second billed generation → multiply by the call count.\n const usage = freshUsage({\n provider: \"fal\",\n model: req.spec.model,\n transport: \"http\",\n capability: \"image\",\n inputTokens: 0,\n outputTokens: 0,\n });\n usage.costUsd = (config.pricePerImage ?? FAL_IMAGE_PRICE_ESTIMATE[req.spec.model] ?? 0) * calls;\n return { url, usage };\n }\n\n async function animate(req: AnimateRequest): Promise<AnimateResult> {\n const apiKey = resolveKey();\n if (!apiKey) throw new Error(\"fal adapter: API key not set (env FAL_KEY or FAL_API_KEY)\");\n const headers = authHeaders(apiKey);\n\n // Input image: a URL passes through; raw bytes are uploaded to fal storage\n // (fal needs a fetchable URL, not a data: URI — same gotcha as trainStyle).\n const imageUrl =\n typeof req.image === \"string\" && /^https?:\\/\\//i.test(req.image)\n ? req.image\n : await uploadToFalStorage(toBytes(req.image), sniffImageType(req.image), \"input\", apiKey);\n\n const body: Record<string, unknown> = { image_url: imageUrl };\n if (req.prompt !== undefined) body.prompt = req.prompt;\n if (req.durationSec !== undefined) body.duration = req.durationSec;\n if (req.resolution !== undefined) body.resolution = req.resolution;\n\n // Video is long-running → always the queue, with the longer deadline.\n const result = await queueResult(req.spec.model, headers, body, config.videoTimeoutMs ?? 600000);\n const url = extractVideoUrl(result);\n if (!url) {\n throw new Error(\n `fal animate: no video url in result — keys [${Object.keys(\n (result as Record<string, unknown>) ?? {},\n ).join(\", \")}]: ${JSON.stringify(result).slice(0, 500)}`,\n );\n }\n\n const usage = freshUsage({\n provider: \"fal\",\n model: req.spec.model,\n transport: \"http\",\n capability: \"animate\",\n inputTokens: 0,\n outputTokens: 0,\n });\n // fal returns no price → per-second estimate × duration (override config.pricePerSecond).\n const perSec = config.pricePerSecond ?? FAL_VIDEO_PRICE_PER_SEC[req.spec.model] ?? 0;\n usage.costUsd = perSec * (req.durationSec ?? FAL_VIDEO_DEFAULT_SEC);\n return { url, usage };\n }\n\n async function trainStyle(req: TrainStyleRequest): Promise<TrainStyleResult> {\n const apiKey = resolveKey();\n if (!apiKey) throw new Error(\"fal adapter: API key not set (env FAL_KEY or FAL_API_KEY)\");\n const headers = authHeaders(apiKey);\n\n const body: Record<string, unknown> = {\n images_data_url: await resolveImagesUrl(req.images, apiKey),\n is_style: req.isStyle ?? true,\n };\n if (req.triggerWord !== undefined) body.trigger_word = req.triggerWord;\n if (req.steps !== undefined) body.steps = req.steps;\n if (req.createMasks !== undefined) body.create_masks = req.createMasks;\n\n // Training runs on the queue and takes minutes — use the longer deadline.\n const result = (await queueResult(\n req.spec.model,\n headers,\n body,\n config.trainTimeoutMs ?? 600000,\n )) as FalTrainResponse;\n // fal's LoRA trainers vary in output shape (field renames, wrappers, multiple\n // trainer endpoints). Extract defensively across known/likely locations, then\n // fall back to scanning for any *.safetensors url. If still nothing, surface the\n // RAW response so a shape mismatch is diagnosable without a key on this side.\n const { loraUrl, configUrl } = extractTrainedFiles(result);\n if (!loraUrl) {\n throw new Error(\n `fal trainStyle: no LoRA file url in result — fal returned keys [${Object.keys(\n (result as Record<string, unknown>) ?? {},\n ).join(\", \")}]: ${JSON.stringify(result).slice(0, 800)}`,\n );\n }\n\n const usage = freshUsage({\n provider: \"fal\",\n model: req.spec.model,\n transport: \"http\",\n capability: \"trainStyle\",\n inputTokens: 0,\n outputTokens: 0,\n });\n usage.costUsd = config.pricePerTraining ?? FAL_TRAIN_PRICE_ESTIMATE;\n return { loraUrl, configUrl: configUrl ?? \"\", usage };\n }\n\n /** A hosted archive URL passes straight through; an array of image URLs is fetched,\n * zipped in-memory, and uploaded to fal storage. fal REJECTS data: URIs here\n * (\"Invalid URL: URL too long\") — images_data_url must be a real http URL it can\n * fetch, so we upload the zip and pass the returned file_url. */\n async function resolveImagesUrl(images: string | string[], apiKey: string): Promise<string> {\n if (typeof images === \"string\") return images;\n const files = await Promise.all(\n images.map(async (url, i) => {\n const res = await doFetch(url);\n if (!res.ok) throw new Error(`fal trainStyle: failed to fetch image ${url} (${res.status})`);\n return { name: fileNameFromUrl(url, i), data: new Uint8Array(await res.arrayBuffer()) };\n }),\n );\n return uploadToFalStorage(buildZip(files), \"application/zip\", \"styleset.zip\", apiKey);\n }\n\n /** Upload bytes to fal storage: initiate (auth'd) → PUT to the returned signed url\n * → return the public file_url. fal CDN serves it back, fetchable by the trainer. */\n async function uploadToFalStorage(\n bytes: Uint8Array,\n contentType: string,\n fileName: string,\n apiKey: string,\n ): Promise<string> {\n const initiate = await doFetch(\"https://rest.alpha.fal.ai/storage/upload/initiate\", {\n method: \"POST\",\n headers: { Authorization: `Key ${apiKey}`, \"content-type\": \"application/json\" },\n body: JSON.stringify({ content_type: contentType, file_name: fileName }),\n });\n if (!initiate.ok) {\n throw new Error(\n `fal storage initiate ${initiate.status}: ${(await initiate.text().catch(() => \"\")).slice(0, 200)}`,\n );\n }\n const { upload_url, file_url } = (await initiate.json()) as { upload_url: string; file_url: string };\n const put = await doFetch(upload_url, {\n method: \"PUT\",\n headers: { \"content-type\": contentType },\n body: bytes,\n });\n if (!put.ok) throw new Error(`fal storage upload PUT ${put.status}`);\n return file_url;\n }\n\n /** Returns the image url + whether fal's safety-checker flagged it (→ black image). */\n async function runSync(\n model: string,\n headers: Record<string, string>,\n body: unknown,\n ): Promise<{ url: string; flagged: boolean }> {\n const res = await doFetch(`${syncBase}/${model}`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n });\n if (!res.ok) {\n throw new Error(`fal ${res.status}: ${(await res.text().catch(() => \"\")).slice(0, 200)}`);\n }\n const data = (await res.json()) as FalImagesResponse;\n const out = data.images?.[0]?.url;\n if (!out) throw new Error(`fal: no image url in response`);\n return { url: out, flagged: data.has_nsfw_concepts?.[0] === true };\n }\n\n async function runQueue(\n model: string,\n headers: Record<string, string>,\n body: unknown,\n ): Promise<{ url: string; flagged: boolean }> {\n const result = (await queueResult(model, headers, body, timeoutMs)) as FalImagesResponse;\n const out = result.images?.[0]?.url;\n if (!out) throw new Error(\"fal queue: no image url in result\");\n return { url: out, flagged: result.has_nsfw_concepts?.[0] === true };\n }\n\n /** Generic fal queue runner: submit → poll status → fetch+return the raw result JSON. */\n async function queueResult(\n model: string,\n headers: Record<string, string>,\n body: unknown,\n deadlineMs: number,\n ): Promise<unknown> {\n const submitRes = await doFetch(`${queueBase}/${model}`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n });\n if (!submitRes.ok) {\n throw new Error(\n `fal queue submit ${submitRes.status}: ${(await submitRes.text().catch(() => \"\")).slice(0, 200)}`,\n );\n }\n const submit = (await submitRes.json()) as FalQueueSubmit;\n const statusUrl = submit.status_url;\n const responseUrl = submit.response_url;\n if (!statusUrl || !responseUrl) throw new Error(\"fal queue: missing status/response url\");\n\n const deadline = Date.now() + deadlineMs;\n for (;;) {\n const statusRes = await doFetch(statusUrl, { headers });\n const status = (await statusRes.json()) as FalQueueStatus;\n if (status.status === \"COMPLETED\") break;\n if (status.status === \"FAILED\") throw new Error(\"fal queue: job FAILED\");\n if (Date.now() >= deadline) throw new Error(`fal queue: timed out after ${deadlineMs}ms`);\n await sleep(pollIntervalMs);\n }\n\n const resultRes = await doFetch(responseUrl, { headers });\n if (!resultRes.ok) {\n throw new Error(\n `fal queue result ${resultRes.status}: ${(await resultRes.text().catch(() => \"\")).slice(0, 300)}`,\n );\n }\n return resultRes.json();\n }\n\n return { name: \"fal\", image, animate, trainStyle };\n}\n\n/** Coerce an image input to bytes (a non-http string is treated as base64/data-URI). */\nfunction toBytes(img: string | Uint8Array): Uint8Array {\n if (typeof img !== \"string\") return img;\n const b64 = img.startsWith(\"data:\") ? img.slice(img.indexOf(\",\") + 1) : img;\n return new Uint8Array(Buffer.from(b64, \"base64\"));\n}\n\n/** Sniff a content-type from the bytes' magic (PNG/WebP/GIF), default JPEG. */\nfunction sniffImageType(img: string | Uint8Array): string {\n const b = toBytes(img);\n if (b[0] === 0x89 && b[1] === 0x50) return \"image/png\";\n if (b[0] === 0x47 && b[1] === 0x49) return \"image/gif\";\n if (b[0] === 0x52 && b[1] === 0x49 && b[8] === 0x57) return \"image/webp\";\n return \"image/jpeg\";\n}\n\n/** Find the result video URL across fal's video-output shapes (video.url, a wrapper,\n * or any *.mp4/.webm url anywhere in the response). */\nexport function extractVideoUrl(result: unknown): string | undefined {\n const r = result as Record<string, unknown> | null | undefined;\n const root = (r?.data ?? r?.response ?? r?.output ?? r) as Record<string, unknown> | null | undefined;\n return (\n urlOf(root?.video) ??\n urlOf((root?.videos as unknown[] | undefined)?.[0]) ??\n deepFindUrl(root, (u) => /\\.(mp4|webm|mov)(\\?|$)/i.test(u))\n );\n}\n\n// ── fal trained-file extraction (defensive against output-shape variance) ────\n\nfunction urlOf(v: unknown): string | undefined {\n if (typeof v === \"string\") return v;\n if (v && typeof v === \"object\" && typeof (v as { url?: unknown }).url === \"string\") {\n return (v as { url: string }).url;\n }\n return undefined;\n}\n\n/** BFS the response for the first {url}/string url matching `match`. */\nfunction deepFindUrl(obj: unknown, match: (url: string) => boolean): string | undefined {\n const stack: unknown[] = [obj];\n while (stack.length) {\n const cur = stack.pop();\n if (typeof cur === \"string\") {\n if (match(cur)) return cur;\n continue;\n }\n if (cur && typeof cur === \"object\") {\n const u = (cur as { url?: unknown }).url;\n if (typeof u === \"string\" && match(u)) return u;\n for (const v of Object.values(cur as Record<string, unknown>)) stack.push(v);\n }\n }\n return undefined;\n}\n\n/** Find the LoRA + config urls across known field names, an optional data/response/\n * output wrapper, and — as a last resort — any *.safetensors / config *.json url\n * anywhere in the response. fal's LoRA trainers vary in output shape. */\nexport function extractTrainedFiles(result: unknown): { loraUrl?: string; configUrl?: string } {\n const r = result as Record<string, unknown> | null | undefined;\n const root = (r?.data ?? r?.response ?? r?.output ?? r) as\n | Record<string, unknown>\n | null\n | undefined;\n const loraUrl =\n urlOf(root?.diffusers_lora_file) ??\n urlOf(root?.lora_file) ??\n urlOf(root?.safetensors) ??\n urlOf(root?.lora) ??\n deepFindUrl(root, (u) => /\\.safetensors(\\?|$)/i.test(u));\n const configUrl =\n urlOf(root?.config_file) ??\n urlOf(root?.config) ??\n deepFindUrl(root, (u) => /config[^/]*\\.json(\\?|$)/i.test(u));\n return { loraUrl, configUrl };\n}\n\n// ── In-memory ZIP (store via DEFLATE, node:zlib — zero new deps) ──────────────\n\nfunction fileNameFromUrl(url: string, i: number): string {\n const base = url.split(\"?\")[0]!.split(\"/\").pop() || \"\";\n return /\\.[a-z0-9]+$/i.test(base) ? base : `image_${i}.png`;\n}\n\n/** Build a spec-compliant ZIP (DEFLATE method) from named byte entries. */\nfunction buildZip(files: { name: string; data: Uint8Array }[]): Uint8Array {\n const parts: Buffer[] = [];\n const central: Buffer[] = [];\n let offset = 0;\n for (const f of files) {\n const nameBuf = Buffer.from(f.name, \"utf8\");\n const data = Buffer.from(f.data);\n const comp = deflateRawSync(data);\n const crc = crc32(data) >>> 0;\n\n const lfh = Buffer.alloc(30);\n lfh.writeUInt32LE(0x04034b50, 0); // local file header signature\n lfh.writeUInt16LE(20, 4); // version needed\n lfh.writeUInt16LE(0, 6); // flags\n lfh.writeUInt16LE(8, 8); // method = deflate\n lfh.writeUInt16LE(0, 10); // mod time\n lfh.writeUInt16LE(0x21, 12); // mod date (1980-01-01)\n lfh.writeUInt32LE(crc, 14);\n lfh.writeUInt32LE(comp.length, 18); // compressed size\n lfh.writeUInt32LE(data.length, 22); // uncompressed size\n lfh.writeUInt16LE(nameBuf.length, 26);\n lfh.writeUInt16LE(0, 28); // extra len\n parts.push(lfh, nameBuf, comp);\n\n const cdh = Buffer.alloc(46);\n cdh.writeUInt32LE(0x02014b50, 0); // central directory header signature\n cdh.writeUInt16LE(20, 4); // version made by\n cdh.writeUInt16LE(20, 6); // version needed\n cdh.writeUInt16LE(0, 8); // flags\n cdh.writeUInt16LE(8, 10); // method\n cdh.writeUInt16LE(0, 12); // mod time\n cdh.writeUInt16LE(0x21, 14); // mod date\n cdh.writeUInt32LE(crc, 16);\n cdh.writeUInt32LE(comp.length, 20);\n cdh.writeUInt32LE(data.length, 24);\n cdh.writeUInt16LE(nameBuf.length, 28);\n cdh.writeUInt16LE(0, 30); // extra len\n cdh.writeUInt16LE(0, 32); // comment len\n cdh.writeUInt16LE(0, 34); // disk number start\n cdh.writeUInt16LE(0, 36); // internal attrs\n cdh.writeUInt32LE(0, 38); // external attrs\n cdh.writeUInt32LE(offset, 42); // local header offset\n central.push(cdh, nameBuf);\n\n offset += lfh.length + nameBuf.length + comp.length;\n }\n const cd = Buffer.concat(central);\n const eocd = Buffer.alloc(22);\n eocd.writeUInt32LE(0x06054b50, 0); // end of central directory signature\n eocd.writeUInt16LE(0, 4); // disk number\n eocd.writeUInt16LE(0, 6); // cd start disk\n eocd.writeUInt16LE(files.length, 8); // entries this disk\n eocd.writeUInt16LE(files.length, 10); // total entries\n eocd.writeUInt32LE(cd.length, 12); // cd size\n eocd.writeUInt32LE(offset, 16); // cd offset\n eocd.writeUInt16LE(0, 20); // comment len\n return Buffer.concat([...parts, cd, eocd]);\n}\n","// Black Forest Labs (FLUX) adapter — F023 / F023.5. EU-RESIDENT image generation.\n//\n// GDPR CRUX (non-negotiable): this adapter hard-pins https://api.eu.bfl.ai — the\n// dedicated EU endpoint — NEVER the global api.bfl.ai (which auto-failovers to the\n// US and could route a face out of the EEA). A face = biometric personal data, so\n// EU residency is what makes this compliant; \"German company\" alone is not enough.\n// The default base is asserted in bfl.test.ts.\n//\n// Two EU-resident likeness modes (route by what ai.image is given):\n// • referenceImages (F023.5) → FLUX 2 multi-reference: 1–8 photos in the generate\n// call, NO training step. Default model flux-2-max ($0.25/img); pass\n// override:{ model:\"flux-2-pro\" } for ~half price ($0.12/img). Bytes are\n// base64-inlined into the EU call (no cross-region fetch); URLs pass through.\n// • finetune (F023) → flux-pro-1.1-ultra-finetuned, a subject trained ONCE in the\n// BFL dashboard (finetune-CREATE was retired from the public API — live-verified\n// 2026-06-16: POST /v1/finetune 404s on every region; legacy eu1/us1 hosts dead).\n// See the dashboard SOP in docs/features/F023-bfl-eu-portrait-lora.md.\n//\n// Auth header `x-key`. Request→poll: POST returns {id, polling_url, cost}; we poll the\n// EU get_result by id (deliberately NOT the returned polling_url) so a response carrying\n// a face never transits a non-EU host. BFL returns the real `cost` in credits\n// (1 credit = $0.01, official) → usage.costUsd is exact, not estimated.\nimport { freshUsage } from \"../cost/usage.js\";\nimport type { Region } from \"../cost/region.js\";\nimport type { ProviderAdapter, ImageRequest, ImageResult } from \"../types.js\";\n\nconst EU_BASE = \"https://api.eu.bfl.ai\";\n/** BFL bills in credits; 1 credit = $0.01 USD (official, bfl.ai/pricing). */\nconst BFL_CREDIT_USD = 0.01;\n\ninterface BflSubmitResponse {\n id?: string;\n polling_url?: string;\n /** BFL's billed cost for this request, in credits. */\n cost?: number;\n}\ninterface BflResultResponse {\n id?: string;\n /** \"Ready\" | \"Pending\" | \"Error\" | \"Request Moderated\" | \"Content Moderated\" | \"Task not found\" */\n status?: string;\n result?: { sample?: string } | null;\n progress?: number | null;\n}\n\nexport interface BflAdapterConfig {\n apiKey?: string;\n /** EU-resident base. Do NOT point this at api.bfl.ai (global, US-failover) — see header. */\n baseUrl?: string;\n pollIntervalMs?: number;\n timeoutMs?: number;\n fetch?: typeof fetch;\n /** Override the per-image USD price (else the built-in finetuned-inference estimate). */\n pricePerImage?: number;\n}\n\n// flux-pro-1.1-ultra-finetuned per-image USD. BFL bills per generated image; verify\n// against bfl.ai/pricing before relying on this (override via config.pricePerImage).\nconst BFL_IMAGE_PRICE = 0.06;\n\nconst sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));\n\nfunction gcd(a: number, b: number): number {\n return b === 0 ? a : gcd(b, a % b);\n}\n\n/** Remaining BFL account credits + their USD value (1 credit = $0.01). */\nexport interface BflCredits {\n credits: number;\n usd: number;\n}\n\n/** F023.6 — check the BFL account's remaining credit balance (`GET /v1/credits`).\n * Account-level (region-independent); EU-pinned by default for consistency. Use it\n * for budget-gating before a generate call: `if ((await bflCredits()).usd < 1) …`. */\nexport async function bflCredits(\n opts: { apiKey?: string; baseUrl?: string; fetch?: typeof fetch } = {},\n): Promise<BflCredits> {\n const apiKey = opts.apiKey ?? process.env.BFL_API_KEY;\n if (!apiKey) throw new Error(\"bflCredits: BFL_API_KEY not set\");\n const doFetch = opts.fetch ?? fetch;\n const res = await doFetch(`${opts.baseUrl ?? EU_BASE}/v1/credits`, { headers: { \"x-key\": apiKey } });\n if (!res.ok) {\n throw new Error(`bflCredits ${res.status}: ${(await res.text().catch(() => \"\")).slice(0, 200)}`);\n }\n const data = (await res.json()) as { credits?: number };\n const credits = typeof data.credits === \"number\" ? data.credits : 0;\n return { credits, usd: credits * BFL_CREDIT_USD };\n}\n\n/** Residency of a BFL base URL (F042). Only the dedicated EU host is an EU claim;\n * the global api.bfl.ai auto-failovers to the US, so where a call landed is not\n * something we can observe from here — \"unknown\" is the truthful answer, and it is\n * deliberately not \"us\" (a failover MAY have stayed in the EU; we just cannot say). */\nfunction bflRegion(base: string): Region {\n try {\n return new URL(base).host.toLowerCase() === \"api.eu.bfl.ai\" ? \"eu\" : \"unknown\";\n } catch {\n return \"unknown\";\n }\n}\n\nexport function bflAdapter(config: BflAdapterConfig = {}): ProviderAdapter {\n const doFetch = config.fetch ?? fetch;\n const base = config.baseUrl ?? EU_BASE;\n const pollIntervalMs = config.pollIntervalMs ?? 1500;\n const timeoutMs = config.timeoutMs ?? 120000;\n\n const resolveKey = () => config.apiKey ?? process.env.BFL_API_KEY;\n\n async function image(req: ImageRequest): Promise<ImageResult> {\n const apiKey = resolveKey();\n if (!apiKey) throw new Error(\"bfl adapter: BFL_API_KEY not set\");\n const headers = { \"content-type\": \"application/json\", \"x-key\": apiKey };\n\n const body: Record<string, unknown> = { prompt: req.prompt };\n if (req.referenceImages?.length) {\n // F023.5 — FLUX 2 multi-reference: input_image, input_image_2 … input_image_8.\n req.referenceImages.forEach((img, i) => {\n body[i === 0 ? \"input_image\" : `input_image_${i + 1}`] = toBflImage(img);\n });\n if (req.width) body.width = req.width;\n if (req.height) body.height = req.height;\n if (req.seed !== undefined) body.seed = req.seed;\n body.output_format = req.outputFormat ?? \"jpeg\";\n body.safety_tolerance = req.safetyTolerance ?? 2;\n } else if (req.finetune) {\n // F023 — finetuned subject (trained once in the BFL dashboard).\n body.finetune_id = req.finetune;\n if (req.finetuneStrength !== undefined) body.finetune_strength = req.finetuneStrength;\n // flux-pro-1.1-ultra takes aspect_ratio, not width/height — derive it when both given.\n if (req.width && req.height) {\n const g = gcd(req.width, req.height) || 1;\n body.aspect_ratio = `${req.width / g}:${req.height / g}`;\n }\n } else {\n throw new Error(\n \"bfl adapter: requires referenceImages (FLUX 2 multi-reference) or a finetune id. \" +\n \"ai.image({ referenceImages: [...] }) needs no training; ai.image({ finetune }) uses a subject \" +\n \"trained once in the BFL dashboard (dashboard.bfl.ai — finetune-create is not in the public API).\",\n );\n }\n\n const submitRes = await doFetch(`${base}/v1/${req.spec.model}`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n });\n if (!submitRes.ok) {\n throw new Error(`bfl ${submitRes.status}: ${(await submitRes.text().catch(() => \"\")).slice(0, 200)}`);\n }\n const submit = (await submitRes.json()) as BflSubmitResponse;\n if (!submit.id) throw new Error(\"bfl: no task id in submit response\");\n\n const sample = await poll(submit.id, apiKey);\n\n const usage = freshUsage({\n provider: \"bfl\",\n model: req.spec.model,\n region: bflRegion(base),\n transport: \"http\",\n capability: \"image\",\n inputTokens: 0,\n outputTokens: 0,\n });\n // BFL returns the real billed cost (credits) — use it; fall back to the estimate.\n usage.costUsd =\n typeof submit.cost === \"number\"\n ? submit.cost * BFL_CREDIT_USD\n : (config.pricePerImage ?? BFL_IMAGE_PRICE);\n return { url: sample, usage };\n }\n\n /** A URL passes through; raw bytes / a data: URI become a plain base64 string\n * (BFL's input_image wants base64, not a data: URI — verified live). */\n function toBflImage(img: string | Uint8Array): string {\n if (typeof img !== \"string\") return Buffer.from(img).toString(\"base64\");\n if (/^https?:\\/\\//i.test(img)) return img;\n const comma = img.startsWith(\"data:\") ? img.indexOf(\",\") : -1;\n return comma >= 0 ? img.slice(comma + 1) : img;\n }\n\n /** Poll the EU get_result by id until Ready (or a terminal/moderated status). */\n async function poll(id: string, apiKey: string): Promise<string> {\n const headers = { \"x-key\": apiKey };\n const deadline = Date.now() + timeoutMs;\n for (;;) {\n const res = await doFetch(`${base}/v1/get_result?id=${encodeURIComponent(id)}`, { headers });\n if (!res.ok) throw new Error(`bfl get_result ${res.status}`);\n const data = (await res.json()) as BflResultResponse;\n const status = data.status ?? \"\";\n if (status === \"Ready\") {\n const sample = data.result?.sample;\n if (!sample) throw new Error(\"bfl: status Ready but no result.sample url\");\n return sample;\n }\n if (status === \"Error\" || status === \"Failed\" || status === \"Task not found\") {\n throw new Error(`bfl: generation ${status}`);\n }\n if (status.includes(\"Moderated\")) {\n throw new Error(`bfl: ${status} — prompt or output flagged by BFL safety`);\n }\n if (Date.now() >= deadline) throw new Error(`bfl: timed out after ${timeoutMs}ms`);\n await sleep(pollIntervalMs);\n }\n }\n\n return { name: \"bfl\", image };\n}\n","// Default provider registry — the live adapters wired when AiConfig.providers is\n// absent. A bare createAI() makes real calls (keys from env). fal stays a stub\n// until F5.3 ships the real fal.ai image adapter.\nimport { anthropicAdapter } from \"./anthropic.js\";\nimport { openaiAdapter } from \"./openai.js\";\nimport { geminiAdapter } from \"./gemini.js\";\nimport { deepinfraAdapter } from \"./deepinfra.js\";\nimport { openrouterAdapter } from \"./openrouter.js\";\nimport { requestyAdapter } from \"./requesty.js\";\nimport { deepseekAdapter } from \"./deepseek.js\";\nimport { mistralAdapter } from \"./mistral.js\";\nimport { elevenlabsAdapter } from \"./elevenlabs.js\";\nimport { azureAdapter } from \"./azure.js\";\nimport { vertexAdapter } from \"./vertex.js\";\nimport { deeplAdapter } from \"./deepl.js\";\nimport { falAdapter } from \"./fal.js\";\nimport { bflAdapter } from \"./bfl.js\";\nimport type { ProviderAdapter } from \"../types.js\";\n\nexport const defaultProviders: Record<string, ProviderAdapter> = {\n anthropic: anthropicAdapter(),\n openai: openaiAdapter(),\n gemini: geminiAdapter(),\n deepinfra: deepinfraAdapter(),\n openrouter: openrouterAdapter(),\n requesty: requestyAdapter(),\n deepseek: deepseekAdapter(),\n mistral: mistralAdapter(),\n elevenlabs: elevenlabsAdapter(),\n azure: azureAdapter(),\n vertex: vertexAdapter(),\n deepl: deeplAdapter(),\n fal: falAdapter(),\n bfl: bflAdapter(),\n};\n","// Pre-flight budget guard. check() runs BEFORE the transport fires, so a call\n// that would breach a ceiling never reaches the provider. record() folds the\n// actual cost into the running total after a successful call.\nimport type { BudgetConfig, BudgetStore } from \"../types.js\";\n\n/** Default rolling-total store: in-memory, per BudgetGuard instance. */\nclass InMemoryBudgetStore implements BudgetStore {\n private spentUsd = 0;\n getSpent(): number {\n return this.spentUsd;\n }\n addSpent(usd: number): void {\n this.spentUsd += usd;\n }\n}\n\nexport class BudgetExceededError extends Error {\n readonly kind: \"per-call\" | \"rolling\";\n readonly limit: number;\n readonly spent: number;\n readonly requested: number;\n\n constructor(\n kind: \"per-call\" | \"rolling\",\n limit: number,\n spent: number,\n requested: number,\n ) {\n super(\n `Budget exceeded (${kind}): this call's estimated $${requested.toFixed(6)} ` +\n (kind === \"rolling\"\n ? `+ $${spent.toFixed(6)} already spent exceeds the $${limit.toFixed(6)} rolling ceiling`\n : `exceeds the $${limit.toFixed(6)} per-call ceiling`),\n );\n this.name = \"BudgetExceededError\";\n this.kind = kind;\n this.limit = limit;\n this.spent = spent;\n this.requested = requested;\n }\n}\n\nexport class BudgetGuard {\n private readonly store: BudgetStore;\n\n constructor(private readonly config: BudgetConfig) {\n this.store = config.store ?? new InMemoryBudgetStore();\n }\n\n /** Throws BudgetExceededError if `requested` would breach the per-call ceiling\n * or push the rolling total past its ceiling. Call before firing the request.\n * Async because a persistent store may be I/O-backed. */\n async check(requested: number): Promise<void> {\n const { perCallUsd, rollingUsd } = this.config;\n if (perCallUsd !== undefined && requested > perCallUsd) {\n throw new BudgetExceededError(\"per-call\", perCallUsd, await this.store.getSpent(), requested);\n }\n if (rollingUsd !== undefined) {\n const spent = await this.store.getSpent();\n if (spent + requested > rollingUsd) {\n throw new BudgetExceededError(\"rolling\", rollingUsd, spent, requested);\n }\n }\n }\n\n /** Add an actual cost to the running total (after a successful call). */\n async record(actual: number): Promise<void> {\n await this.store.addSpent(actual);\n }\n\n async totalSpent(): Promise<number> {\n return this.store.getSpent();\n }\n}\n","// Vision capability helper. The client owns orchestration (tier/budget/sink);\n// this module owns the vision-specific message shaping so it's unit-testable and\n// the capabilities/ layout stays meaningful. Default tier: \"vision\".\nimport type { VisionInput } from \"../schema/inputs.js\";\nimport type { Message, Tier } from \"../types.js\";\n\nexport const VISION_DEFAULT_TIER: Tier = \"vision\";\n\n/** Build the multimodal message(s) (optional system + user text + image) for a\n * vision call. A `system` instruction drives instruction-following far better\n * than packing rules into `prompt` for instruction-heavy tasks (e.g. a JSON critic). */\nexport function buildVisionMessages(input: VisionInput): Message[] {\n const messages: Message[] = [];\n if (input.system) messages.push({ role: \"system\", content: input.system });\n messages.push({\n role: \"user\",\n content: [\n { type: \"text\", text: input.prompt },\n { type: \"image\", image: input.image, mimeType: input.mimeType },\n ],\n });\n return messages;\n}\n","// Video Vision capability (F019). Like vision, but the multimodal part is a\n// video the model watches natively (Gemini, OpenRouter video models). The client\n// owns orchestration; this module owns the message shaping. Default tier: \"video\".\nimport type { VideoInput } from \"../schema/inputs.js\";\nimport type { Message, Tier } from \"../types.js\";\n\nexport const VIDEO_DEFAULT_TIER: Tier = \"video\";\n\n/** Build the message(s) (optional system + video + prompt) for a video-analysis call. */\nexport function buildVideoMessages(input: VideoInput): Message[] {\n const messages: Message[] = [];\n if (input.system) messages.push({ role: \"system\", content: input.system });\n messages.push({\n role: \"user\",\n content: [\n { type: \"video\", video: input.video, mimeType: input.mimeType },\n { type: \"text\", text: input.prompt },\n ],\n });\n return messages;\n}\n","// Translate capability helper. A thin prompt-contract on top of chat — the\n// client orchestrates (tier/budget/sink); this builds the messages. Default\n// tier: \"fast\". Returns the translation only, no preamble.\nimport type { TranslateInput } from \"../schema/inputs.js\";\nimport type { Message, Tier } from \"../types.js\";\n\nexport const TRANSLATE_DEFAULT_TIER: Tier = \"fast\";\n\nconst TRANSLATE_SYSTEM =\n \"You are a translation engine. Translate the user's text only. \" +\n \"Return the translation and nothing else — no preamble, no quotes.\";\n\nexport function buildTranslateMessages(input: TranslateInput): Message[] {\n const fromClause = input.from ? ` from ${input.from}` : \"\";\n return [\n { role: \"system\", content: TRANSLATE_SYSTEM },\n { role: \"user\", content: `Translate${fromClause} to ${input.to}:\\n\\n${input.text}` },\n ];\n}\n","// Embedding capability marker. The client orchestrates; this names the default\n// tier (OpenAI text-embedding-3-small via the embedding tier).\nimport type { Tier } from \"../types.js\";\n\nexport const EMBEDDING_DEFAULT_TIER: Tier = \"embedding\";\n","// Transcribe capability. No tier in the tier map (provider-specific, like image)\n// — defaults to OpenAI Whisper, overridable per call. Synergy: cctalk Danish\n// dictation. costUsd is 0 for v1 (Whisper is priced per minute, not per token).\nimport type { TierSpec } from \"../types.js\";\n\nexport const DEFAULT_TRANSCRIBE_SPEC: TierSpec = {\n provider: \"openai\",\n model: \"whisper-1\",\n transport: \"http\",\n};\n\n/** Fetch a URL to raw bytes; pass through bytes unchanged. */\nexport async function resolveAudio(\n audio: string | Uint8Array,\n fetchImpl: typeof fetch = fetch,\n): Promise<Uint8Array> {\n if (typeof audio !== \"string\") return audio;\n if (!/^https?:\\/\\//.test(audio)) {\n throw new Error(\"transcribe: string audio must be an http(s) URL (or pass raw bytes)\");\n }\n const res = await fetchImpl(audio);\n if (!res.ok) throw new Error(`transcribe: failed to fetch audio (${res.status})`);\n return new Uint8Array(await res.arrayBuffer());\n}\n","// Prompt-contract capabilities (F5.5). Each is a fixed system prompt over\n// chat/vision; extract adds Zod output validation with one retry. Exposed as\n// ai.contracts.* — built from the client so budget/cost tracking apply.\nimport type { AiClient, VisionInput } from \"../../schema/inputs.js\";\nimport type {\n Contracts,\n MockupInput,\n MockupResult,\n DesignInput,\n DesignResult,\n ExtractInput,\n ExtractResult,\n ClassifyInput,\n ClassifyResult,\n RerankInput,\n RerankResult,\n} from \"./types.js\";\n\n/** Pull the first JSON value out of a model reply (tolerates ```json fences + prose). */\nexport function parseJsonLoose(text: string): unknown {\n const fenced = text.replace(/```(?:json)?/gi, \"\").trim();\n const start = fenced.search(/[[{]/);\n if (start === -1) throw new Error(\"no JSON found in model output\");\n const slice = fenced.slice(start);\n // Walk back from the end to the matching closing bracket.\n const lastObj = slice.lastIndexOf(\"}\");\n const lastArr = slice.lastIndexOf(\"]\");\n const end = Math.max(lastObj, lastArr);\n return JSON.parse(slice.slice(0, end + 1));\n}\n\ntype ChatVision = Pick<AiClient, \"chat\" | \"vision\">;\n\nexport function makeContracts(client: ChatVision): Contracts {\n return {\n async mockup(input: MockupInput): Promise<MockupResult> {\n const constraints = input.constraints ? `\\n\\nConstraints:\\n${input.constraints}` : \"\";\n const res = await client.chat({\n system:\n \"You are a UI mockup generator. Output a single self-contained HTML document \" +\n \"using Tailwind CSS utility classes. Return ONLY the HTML — no markdown, no prose.\",\n prompt: `Build a UI mockup for:\\n${input.description}${constraints}`,\n tier: input.tier ?? \"smart\",\n purpose: input.purpose ?? \"contract:mockup\",\n });\n return { html: res.text, usage: res.usage };\n },\n\n async design(input: DesignInput): Promise<DesignResult> {\n const res = await client.vision({\n image: input.screenshot as VisionInput[\"image\"],\n prompt:\n \"You are a design-iteration engine. Given this screenshot, apply the instructions \" +\n `and return a single self-contained HTML document (Tailwind), ONLY the HTML.\\n\\n` +\n `Instructions:\\n${input.instructions}`,\n tier: input.tier ?? \"powerful\",\n purpose: input.purpose ?? \"contract:design\",\n });\n return { html: res.text, usage: res.usage };\n },\n\n async extract<T>(input: ExtractInput<T>): Promise<ExtractResult<T>> {\n const base =\n \"You are a structured-data extractor. Extract the requested data from the text and \" +\n \"return ONLY valid JSON — no markdown, no prose.\" +\n (input.instructions ? `\\n\\n${input.instructions}` : \"\");\n const run = async (reinforce: boolean) => {\n const res = await client.chat({\n system: reinforce ? `${base}\\n\\nYour previous output was not valid JSON. Return ONLY parseable JSON.` : base,\n prompt: input.text,\n tier: input.tier ?? \"smart\",\n purpose: input.purpose ?? \"contract:extract\",\n });\n return res;\n };\n let res = await run(false);\n try {\n return { data: input.schema.parse(parseJsonLoose(res.text)), usage: res.usage };\n } catch {\n // one retry with reinforcement\n res = await run(true);\n return { data: input.schema.parse(parseJsonLoose(res.text)), usage: res.usage };\n }\n },\n\n async classify(input: ClassifyInput): Promise<ClassifyResult> {\n const res = await client.chat({\n system:\n \"You are a zero-shot classifier. Choose exactly one label from the provided list. \" +\n 'Return ONLY JSON: {\"label\": \"<one of the labels>\", \"confidence\": <0..1>}.',\n prompt: `Labels: ${JSON.stringify(input.labels)}\\n\\nText:\\n${input.text}`,\n tier: input.tier ?? \"cheap\",\n purpose: input.purpose ?? \"contract:classify\",\n });\n const parsed = parseJsonLoose(res.text) as { label?: string; confidence?: number };\n const label = input.labels.includes(parsed.label ?? \"\") ? parsed.label! : (input.labels[0] ?? \"\");\n const confidence = typeof parsed.confidence === \"number\" ? parsed.confidence : 0;\n return { label, confidence, usage: res.usage };\n },\n\n async rerank(input: RerankInput): Promise<RerankResult> {\n const res = await client.chat({\n system:\n \"You are a relevance reranker. Score each item 0..1 for relevance to the query and \" +\n 'return ONLY JSON: [{\"item\": \"<verbatim item>\", \"score\": <0..1>}], ordered by score desc.',\n prompt: `Query: ${input.query}\\n\\nItems:\\n${JSON.stringify(input.items)}`,\n tier: input.tier ?? \"fast\",\n purpose: input.purpose ?? \"contract:rerank\",\n });\n const raw = parseJsonLoose(res.text) as { item?: string; score?: number }[];\n const ranked = (Array.isArray(raw) ? raw : [])\n .map((r) => ({ item: String(r.item ?? \"\"), score: typeof r.score === \"number\" ? r.score : 0 }))\n .sort((a, b) => b.score - a.score);\n return { ranked, usage: res.usage };\n },\n };\n}\n","// F037 — the voice registry. DERIVED from the curated rosters, never a second copy\n// of them: ELEVENLABS_DANISH_VOICES and AZURE_DANISH_VOICE_LIST stay the single\n// source for which voices we bless, and this module only adds the status layer on\n// top. A copied roster is a roster that drifts.\nimport { ELEVENLABS_DANISH_VOICES } from \"../providers/elevenlabs.js\";\nimport { AZURE_DANISH_VOICE_LIST, localeOf } from \"../providers/azure.js\";\nimport type { VoiceInfo, VoiceProvider } from \"./types.js\";\n\n/** When each provider's roster was last confirmed against the provider itself.\n * These are MEASUREMENTS with dates, not a claim of current truth — that is the\n * whole point of surfacing checkedAt. */\nconst CHECKED_AT: Record<VoiceProvider, string> = {\n // All 5 curated ids confirmed by SYNTHESIS — POST /v1/text-to-speech/{id} returned\n // 200 with distinct audio per voice (5 distinct sha256), and a fabricated id\n // returned 404, so a 200 means something.\n //\n // NB: GET /v1/voices/{id} is NOT a liveness test and must not be used as one. It\n // answers \"is this voice saved in our account\", and returns voice_not_found for a\n // public/shared voice that synthesizes perfectly well. Using it cost us a false\n // retirement (see the note on `mads` below) — the only honest liveness check for\n // ElevenLabs is a real synthesis call, which is exactly why v1 does no live check.\n elevenlabs: \"2026-08-11\",\n // F026 (6ca38c4) verified the 6 curated names against Azure's voices/list. Not\n // re-probed since: this machine has no Azure Speech key, and inventing a fresher\n // date than the last real check is exactly the lie checkedAt exists to prevent.\n azure: \"2026-06-23\",\n};\n\n/** Voices we know are GONE — keyed by curated name. A row here is the third state\n * the old two-state resolveVoice could not express. Keep the entry: deleting it\n * would send the friendly name to the provider as a raw voice id.\n *\n * Currently EMPTY. Every curated voice was synthesis-verified on 2026-08-11. This\n * map existing while empty is the point — it is the mechanism that lets us act on\n * a retirement the day one happens, instead of discovering we cannot express it. */\nconst RETIRED_DEFAULT: Record<string, string> = {};\n\nlet RETIRED: Record<string, string> = RETIRED_DEFAULT;\n\n/** Genders as published by the provider's voices endpoint. Absent = we have no\n * source; never inferred from a first name. `mads` is absent because it is not\n * saved to our account, and that endpoint only describes account voices — the\n * voice itself works fine. */\nconst ELEVENLABS_GENDER: Record<string, \"female\" | \"male\"> = {\n soren: \"male\",\n jesper: \"male\",\n noam: \"male\",\n camilla: \"female\",\n};\n\n/** Caveats worth showing in a picker that are NOT unavailability. */\nconst NOTES: Record<string, string> = {\n mads: \"usable, but not saved to the ElevenLabs account, so the voices endpoint publishes no metadata for it (verified by synthesis 2026-08-11)\",\n};\n\nfunction build(): VoiceInfo[] {\n const rows: VoiceInfo[] = [];\n\n for (const [name, id] of Object.entries(ELEVENLABS_DANISH_VOICES)) {\n const retired = RETIRED[name];\n rows.push({\n id,\n name,\n provider: \"elevenlabs\",\n // The curated ElevenLabs roster IS the Danish one (see the constant's name\n // + F020); the multilingual model speaks it as da-DK.\n locale: \"da-DK\",\n gender: ELEVENLABS_GENDER[name],\n available: retired === undefined,\n status: retired === undefined ? \"available\" : \"retired\",\n note: retired ?? NOTES[name],\n checkedAt: CHECKED_AT.elevenlabs,\n });\n }\n\n for (const v of AZURE_DANISH_VOICE_LIST) {\n const retired = RETIRED[v.name];\n rows.push({\n id: v.voiceId,\n name: v.name,\n provider: \"azure\",\n locale: localeOf(v.voiceId),\n gender: v.gender,\n available: retired === undefined,\n status: retired === undefined ? \"available\" : \"retired\",\n note: retired ?? NOTES[v.name],\n checkedAt: CHECKED_AT.azure,\n });\n }\n\n return rows;\n}\n\nlet ROWS: VoiceInfo[] = build();\n\n/** All curated voices, current status applied. Optionally scoped to one provider. */\nexport function allVoices(provider?: VoiceProvider): VoiceInfo[] {\n return provider ? ROWS.filter((v) => v.provider === provider) : [...ROWS];\n}\n\n/** Look up by curated friendly name OR by full provider voice id — a caller may\n * legitimately pass either. Anything else is untracked (undefined = fail-open). */\nexport function getVoice(nameOrId: string): VoiceInfo | undefined {\n return ROWS.find((v) => v.name === nameOrId || v.id === nameOrId);\n}\n\n/** TEST-ONLY. Mark curated voices retired so the third state can be exercised while\n * no real retirement exists. Deliberately not exported from the package entry —\n * a consumer must never be able to mark our roster dead. Pair with\n * resetVoiceRegistry() so a test cannot leak state into the next one. */\nexport function setRetiredVoicesForTests(map: Record<string, string>): void {\n RETIRED = map;\n ROWS = build();\n}\n\n/** TEST-ONLY. Restore the shipped registry. */\nexport function resetVoiceRegistry(): void {\n RETIRED = RETIRED_DEFAULT;\n ROWS = build();\n}\n","// F037 — voice availability. Mirrors src/availability/ (models) for VOICES, and\n// exists for a reason the model side does not have.\n//\n// `resolveVoice()` has only TWO states: a curated name maps to an id, or the input\n// is passed through verbatim as a raw provider voice id. There is no way to say\n// \"we know this voice, and it is gone\". So when a provider retires a voice, the\n// obvious fix — delete it from the curated map — makes the call fail MORE\n// confusingly: the literal friendly name (\"mads\") gets POSTed as a voice id.\n//\n// That missing third state is what this module adds. It is not primarily a\n// drift-detector; it is the only way to act on a retirement at all.\n\nexport type VoiceStatus = \"available\" | \"retired\" | \"unknown\";\n\nexport type VoiceProvider = \"elevenlabs\" | \"azure\";\n\n/** One row of the shared voice read — what a UI voice-picker renders. */\nexport interface VoiceInfo {\n /** Full provider voice id, e.g. \"da-DK-ChristelNeural\" / \"4RklGmuxoAskAbGXplXN\". */\n id: string;\n /** Curated friendly name a caller passes as `voice`, e.g. \"christel\". */\n name: string;\n provider: VoiceProvider;\n /** BCP-47 locale of the voice itself, e.g. \"da-DK\". NB: an Azure multilingual\n * voice speaking Danish reports its own locale (\"de-DE\" for Seraphina) — that\n * is what the adapter actually sends as xml:lang. */\n locale: string;\n /** Only where the provider publishes it — absent is \"we do not know\", never a\n * guess from the first name. */\n gender?: \"female\" | \"male\";\n available: boolean;\n status: VoiceStatus;\n /** Why it is unavailable, or any caveat worth showing in a picker. */\n note?: string;\n /** ISO date this row's status was last confirmed AGAINST THE PROVIDER. Exposed\n * on purpose (the F034.1 lesson): a registry that cannot be seen to go stale\n * is worse than one that can, because nobody knows when to re-check it. */\n checkedAt: string;\n}\n\n/** Result of checkVoice — deliberately the same shape as ResolveResult (F022) so\n * a consumer learns one idiom for models and voices. */\nexport interface VoiceResolveResult {\n /** True when the requested voice itself is usable. */\n ok: boolean;\n /** The id to actually send: the requested voice's id when ok, else the\n * fallback's. When there is no usable fallback this is the dead id and `ok`\n * is false — mirroring resolveModel, the caller must read `ok`. */\n voiceId: string;\n /** What the caller asked for, verbatim. */\n requested: string;\n provider?: VoiceProvider;\n /** True when `voiceId` differs from what was requested because we fell back. */\n fellBack: boolean;\n status: VoiceStatus;\n /** Why it degraded / why it is unavailable. */\n reason?: string;\n}\n\n/** Thrown when the requested voice is retired and no usable fallback exists.\n * Callers flag on `.code === \"voice_unavailable\"`. */\nexport class VoiceUnavailableError extends Error {\n readonly code = \"voice_unavailable\";\n readonly requested: string;\n readonly provider?: VoiceProvider;\n readonly note?: string;\n constructor(requested: string, note?: string, provider?: VoiceProvider) {\n super(`voice \"${requested}\" is unavailable${note ? ` (${note})` : \"\"}`);\n this.name = \"VoiceUnavailableError\";\n this.requested = requested;\n this.note = note;\n this.provider = provider;\n }\n}\n","// F037 — the synchronous, zero-I/O voice resolve + roster read, mirroring\n// src/availability/resolve.ts (F022) so a consumer learns ONE idiom for models and\n// voices. Never awaits, never touches the network: this sits on the TTS call path.\nimport { allVoices, getVoice } from \"./registry.js\";\nimport { VoiceUnavailableError } from \"./types.js\";\nimport type { VoiceInfo, VoiceProvider, VoiceResolveResult } from \"./types.js\";\n\nexport interface CheckVoiceOptions {\n /** One name/id or an ordered chain to try when `requested` is retired. */\n fallback?: string | string[];\n /** Throw VoiceUnavailableError instead of returning ok:false when nothing in the\n * chain is usable. For callers that want to fail loudly rather than degrade. */\n throwIfUnavailable?: boolean;\n}\n\n/**\n * The shared voice read — a UI picker greys out `available:false` rows and can show\n * `checkedAt` so a stale registry is visible rather than silently trusted.\n *\n * NB: distinct from `elevenlabsAdapter().listVoices()`, which is an async call to\n * ElevenLabs' live API. This one is synchronous, cross-provider, and reads only the\n * curated registry.\n */\nexport function listVoices(opts: { provider?: VoiceProvider } = {}): VoiceInfo[] {\n return allVoices(opts.provider);\n}\n\n/** Usable? Untracked voices are fail-open — we never block a raw provider voice id\n * just because it is not on our curated roster. */\nfunction usable(nameOrId: string): boolean {\n const v = getVoice(nameOrId);\n return v ? v.available : true;\n}\n\n/** The id to actually send for a name/id: the registry's full id when we know it,\n * otherwise the input verbatim (a raw provider voice id). */\nfunction idFor(nameOrId: string): string {\n return getVoice(nameOrId)?.id ?? nameOrId;\n}\n\n/**\n * Resolve a requested voice (curated name or raw provider id) to one that is\n * actually usable. Synchronous + offline by contract.\n *\n * - Available → pass through ({ ok:true, fellBack:false }).\n * - Retired + a usable fallback → swap ({ ok:false, fellBack:true }).\n * - Retired + no usable fallback → throw (throwIfUnavailable) or return ok:false.\n * - Untracked id → treated usable ({ status:\"unknown\" }), passed through verbatim.\n */\nexport function checkVoice(requested: string, opts: CheckVoiceOptions = {}): VoiceResolveResult {\n const entry = getVoice(requested);\n const provider = entry?.provider;\n\n if (usable(requested)) {\n return {\n ok: true,\n voiceId: idFor(requested),\n requested,\n provider,\n fellBack: false,\n status: entry?.status ?? \"unknown\",\n };\n }\n\n // Requested is retired — walk the fallback chain for the first usable one.\n const chain = opts.fallback === undefined ? [] : Array.isArray(opts.fallback) ? opts.fallback : [opts.fallback];\n for (const fb of chain) {\n if (usable(fb)) {\n return {\n ok: false,\n voiceId: idFor(fb),\n requested,\n provider: getVoice(fb)?.provider ?? provider,\n fellBack: true,\n status: entry?.status ?? \"retired\",\n reason: entry?.note ?? `${requested} is unavailable`,\n };\n }\n }\n\n if (opts.throwIfUnavailable) {\n throw new VoiceUnavailableError(requested, entry?.note, provider);\n }\n return {\n ok: false,\n voiceId: idFor(requested),\n requested,\n provider,\n fellBack: false,\n status: entry?.status ?? \"retired\",\n reason: entry?.note ?? `${requested} is unavailable`,\n };\n}\n","// Zod is the single source of truth for the public input shapes. The TypeScript\n// types are derived via z.infer — no hand-written interface duplicates them.\n// The client .parse()s every input at the boundary, so invalid input throws a\n// ZodError before any provider work happens.\nimport { z } from \"zod\";\nimport type {\n ProviderAdapter,\n CostSink,\n TranslateResult,\n ChatResult,\n ChatStreamEvent,\n ImageResult,\n AnimateResult,\n TrainStyleResult,\n EmbeddingResult,\n TranscribeResult,\n OcrResult,\n ModerationResult,\n PodcastResult,\n BatchRequestItem,\n BatchJob,\n BatchResultItem,\n TierSpec,\n} from \"../types.js\";\nimport type { Contracts } from \"../capabilities/contracts/types.js\";\n\n// ── Reusable sub-schemas ───────────────────────────────────────────────────\n\nexport const transportSchema = z.enum([\"http\", \"subprocess\"]);\n\nexport const tierSchema = z.enum([\n \"fast\",\n \"smart\",\n \"powerful\",\n \"cheap\",\n \"vision\",\n \"video\",\n \"embedding\",\n]);\n\nexport const tierSpecSchema = z.object({\n provider: z.string(),\n model: z.string(),\n transport: transportSchema,\n});\n\nexport const toolSchema = z.object({\n name: z.string(),\n description: z.string(),\n parameters: z.record(z.unknown()),\n});\n\n// F043.4. `arguments` is ours and canonical; `args` is what @broberg/chat emits.\n// The TYPE accepted both from the start — this SCHEMA did not, and chatInputSchema\n// runs on every ai.chat()/ai.chatStream(), so the fix never reached a real consumer:\n// a message history using `args` still failed with\n// \"messages.0.toolCalls.0.arguments — Required\", verbatim the error we said was fixed.\n// The end-to-end test that \"proved\" it called the adapter directly and skipped\n// validation entirely — a test that exercised the one path nobody uses.\n//\n// Zod also STRIPS unknown keys, so making `arguments` optional alone would have\n// silently dropped `args` on the floor. Both keys must be declared, and at least one\n// present.\nexport const toolCallSchema = z\n .object({\n id: z.string(),\n name: z.string(),\n arguments: z.record(z.unknown()).optional(),\n args: z.record(z.unknown()).optional(),\n })\n .refine((tc) => tc.arguments !== undefined || tc.args !== undefined, {\n message: \"tool call needs `arguments` (canonical) or `args` (@broberg/chat's spelling)\",\n path: [\"arguments\"],\n });\n\nexport const contentPartSchema = z.union([\n z.object({ type: z.literal(\"text\"), text: z.string() }),\n z.object({\n type: z.literal(\"image\"),\n image: z.union([z.string(), z.instanceof(Uint8Array)]),\n mimeType: z.string().optional(),\n }),\n]);\n\nexport const messageSchema = z.object({\n role: z.enum([\"system\", \"user\", \"assistant\", \"tool\"]),\n content: z.union([z.string(), z.array(contentPartSchema)]),\n toolCalls: z.array(toolCallSchema).optional(),\n toolCallId: z.string().optional(),\n});\n\n/** Per-call options shared by every capability input. */\nconst callOptions = {\n tier: tierSchema.optional(),\n override: tierSpecSchema.partial().optional(),\n fallback: z.array(z.union([tierSchema, tierSpecSchema])).optional(),\n purpose: z.string().optional(),\n /** Consumer-defined attribution dimensions (e.g. {tenantId}) ridden into the\n * cost sink for per-tenant/per-customer cost breakdown (F011). */\n labels: z.record(z.string(), z.string()).optional(),\n} as const;\n\n// ── The 5 capability inputs ────────────────────────────────────────────────\n\nexport const chatInputSchema = z.object({\n /** F039 — reuse a cached prompt prefix on Mistral at 10% of the input rate.\n * A stable id for \"the same conversation\" (conversation id, session id).\n * Derive it from (tenant, conversation): the key is a shared-prefix identity,\n * so two tenants with identical transcripts must get different keys. */\n promptCacheKey: z.string().optional(),\n /** F039.2 — prompt caching is ON by default on providers that support it.\n * false opts out; an explicit promptCacheKey always wins. */\n promptCache: z.boolean().optional(),\n prompt: z.string().optional(),\n messages: z.array(messageSchema).optional(),\n system: z.string().optional(),\n tools: z.array(toolSchema).optional(),\n maxTokens: z.number().int().positive().optional(),\n temperature: z.number().min(0).max(2).optional(),\n /** \"json\" requests JSON-object output (OpenAI-compatible response_format). */\n responseFormat: z.enum([\"json\", \"text\"]).optional(),\n ...callOptions,\n});\n\nexport const visionInputSchema = z.object({\n image: z.union([z.string(), z.instanceof(Uint8Array)]),\n prompt: z.string(),\n mimeType: z.string().optional(),\n /** System instruction — drives instruction-following far better than stuffing\n * rules into `prompt` for instruction-heavy vision tasks (e.g. a JSON critic). */\n system: z.string().optional(),\n ...callOptions,\n});\n\n// F019 — analyze a video natively (e.g. \"what's in the first 30s?\"). Same shape\n// as vision but with a video payload (URL, data-URL, or raw bytes).\nexport const videoInputSchema = z.object({\n video: z.union([z.string(), z.instanceof(Uint8Array)]),\n prompt: z.string(),\n mimeType: z.string().optional(),\n /** System instruction — same instruction-following benefit as on vision. */\n system: z.string().optional(),\n ...callOptions,\n});\n\nexport const translateInputSchema = z.object({\n text: z.string(),\n to: z.string(),\n from: z.string().optional(),\n ...callOptions,\n});\n\nexport const loraWeightSchema = z.object({\n path: z.string(),\n scale: z.number().optional(),\n});\n\nexport const imageInputSchema = z.object({\n prompt: z.string(),\n width: z.number().int().positive().optional(),\n height: z.number().int().positive().optional(),\n /** LoRAs to merge at inference (F021). */\n loras: z.array(loraWeightSchema).optional(),\n /** Shorthand for a single LoRA — normalized to loras:[{path, scale:1}]. */\n lora: z.string().optional(),\n /** F023 — a BFL finetune id (subject trained in the BFL dashboard). Routes to the\n * EU-resident BFL finetuned-portrait endpoint. */\n finetune: z.string().optional(),\n /** F023 — BFL finetune_strength (~0–2; higher = stronger likeness). */\n finetuneStrength: z.number().min(0).max(2).optional(),\n /** F023.5 — 1–8 reference photos (URL or raw bytes) → EU-resident BFL FLUX 2\n * multi-reference generation (likeness, no training step). */\n referenceImages: z.array(z.union([z.string(), z.instanceof(Uint8Array)])).min(1).max(8).optional(),\n /** F023.5 — fixed seed for reproducible output (BFL). */\n seed: z.number().int().optional(),\n /** F023.5 — output container (BFL FLUX 2). Default jpeg. */\n outputFormat: z.enum([\"jpeg\", \"png\", \"webp\"]).optional(),\n /** F023.5 — BFL content-moderation strictness, 0 (strict) … 6 (lax). Default 2. */\n safetyTolerance: z.number().int().min(0).max(6).optional(),\n /** F021.4 — re-roll once if fal returns a black image (NSFW false-positive). */\n retryOnBlack: z.boolean().optional(),\n ...callOptions,\n});\n\n// Image-to-video (F024) — animate a still into a short clip via a pluggable provider.\nexport const animateInputSchema = z.object({\n /** Input image: a URL or raw bytes (uploaded to fal storage). */\n image: z.union([z.string(), z.instanceof(Uint8Array)]),\n /** Motion/scene prompt. */\n prompt: z.string().optional(),\n /** Clip length in seconds (provider-dependent; Veo ≤ 8s). */\n durationSec: z.number().positive().optional(),\n /** e.g. \"720p\" / \"1080p\" (provider-dependent). */\n resolution: z.string().optional(),\n ...callOptions,\n});\n\nexport const trainStyleInputSchema = z.object({\n /** A hosted archive URL, or an array of image URLs the SDK zips in-memory. */\n images: z.union([z.string(), z.array(z.string())]),\n /** Style LoRA (disables captioning/masks). Default true. */\n isStyle: z.boolean().optional(),\n triggerWord: z.string().optional(),\n steps: z.number().int().positive().optional(),\n createMasks: z.boolean().optional(),\n ...callOptions,\n});\n\nexport const embeddingInputSchema = z.object({\n text: z.union([z.string(), z.array(z.string())]),\n ...callOptions,\n});\n\nexport const transcribeInputSchema = z.object({\n /** Audio URL or raw bytes. */\n audio: z.union([z.string(), z.instanceof(Uint8Array)]),\n language: z.string().optional(),\n /** Audio length in seconds — enables Whisper per-minute cost. */\n durationSec: z.number().positive().optional(),\n /** Bias toward brand/jargon terms (Azure phraseList, F029.3); others ignore it. */\n phrases: z.array(z.string()).optional(),\n /** Opt-in timestamps (F036) — a single granularity or an array. Omit → the\n * current { text, usage } shape, unchanged. Pass [\"word\",\"segment\"] for both.\n * Supported by Whisper (openai) + Azure fast-transcription (F036.1); other\n * adapters (Voxtral/mistral) ignore it and return text only. */\n timestamps: z\n .union([z.enum([\"word\", \"segment\"]), z.array(z.enum([\"word\", \"segment\"]))])\n .optional(),\n ...callOptions,\n});\n\n// OCR (F016.2) — document/image → structured markdown text, billed per page.\nexport const ocrInputSchema = z.object({\n /** A URL, data-URL, or raw bytes of the document/image. */\n document: z.union([z.string(), z.instanceof(Uint8Array)]),\n /** image/* → routed as an image; anything else → a document (PDF etc.). */\n mimeType: z.string().optional(),\n ...callOptions,\n});\n\n// Moderation (F016.4) — classify text against safety categories, billed per token.\nexport const moderationInputSchema = z.object({\n input: z.union([z.string(), z.array(z.string())]),\n ...callOptions,\n});\n\n// Podcast (F020) — a finished manuscript (speaker turns) + a speaker→voiceId map →\n// one finished multi-voice audio episode (ElevenLabs Text-to-Dialogue).\nexport const podcastInputSchema = z.object({\n script: z.array(z.object({ speaker: z.string(), text: z.string() })).min(1),\n voices: z.record(z.string(), z.string()),\n format: z.string().optional(),\n ...callOptions,\n});\n\n// Single-voice TTS (F020.4) — text → audio. `voice` is a curated name or a voiceId.\n// `lang`/`format` (F026) are used by the Azure adapter; ElevenLabs ignores them.\nexport const ttsInputSchema = z.object({\n text: z.string(),\n voice: z.string(),\n /** F037: voice to use if `voice` is one we know the provider has retired. Without\n * it a retired voice throws VoiceUnavailableError rather than reaching the API.\n *\n * THINK BEFORE SETTING THIS. It is right for batch work where any acceptable voice\n * will do (a generated podcast, a bulk render). It is WRONG where the voice is an\n * identity a human recognises — a brand voice, a house narrator: falling back means\n * your product suddenly speaks with a stranger's voice and says nothing about why.\n * There, leave it unset and let the throw alarm you. Silence WITH a message beats\n * the wrong audio WITHOUT one. (torrent-search-api's call on their own house voice,\n * 2026-08-11 — they took the alarm over the fallback, deliberately.) */\n voiceFallback: z.string().optional(),\n lang: z.string().optional(),\n format: z.string().optional(),\n rate: z.number().positive().optional(),\n ...callOptions,\n});\n\n// ── Client config ──────────────────────────────────────────────────────────\n\nexport const budgetSchema = z.object({\n perCallUsd: z.number().positive().optional(),\n rollingUsd: z.number().positive().optional(),\n});\n\n/** F022 — opt-in proactive availability gate. Off by default so existing call\n * sites are byte-identical. When autoResolve is on, a suspended primary model\n * is transparently swapped to `fallback` before dispatch (synchronous, no I/O). */\nexport const availabilitySchema = z.object({\n autoResolve: z.boolean().optional(),\n fallback: z.union([z.string(), z.array(z.string())]).optional(),\n});\n\nexport const aiConfigSchema = z.object({\n /** F039.2 — client-wide opt-out from prompt caching (default: on where the\n * provider supports it). A per-call `promptCache` wins over this. */\n promptCache: z.boolean().optional(),\n defaults: z.record(tierSchema, tierSpecSchema).optional(),\n // Functions can't be deeply validated — z.custom asserts the TS type and\n // passes the value through untouched.\n providers: z.record(z.string(), z.custom<ProviderAdapter>()).optional(),\n /** Omit → cost-tracking auto-wires from the upmetrics env (F034). Pass `null`\n * to opt OUT explicitly — for a consumer that already reports its own costs\n * and would otherwise be counted twice (F034.3). An object is used as-is. */\n costSink: z.custom<CostSink>().nullable().optional(),\n budget: budgetSchema.optional(),\n availability: availabilitySchema.optional(),\n});\n\n// ── Derived types (z.infer is the single source) ───────────────────────────\n\nexport type ChatInput = z.infer<typeof chatInputSchema>;\nexport type VisionInput = z.infer<typeof visionInputSchema>;\nexport type VideoInput = z.infer<typeof videoInputSchema>;\nexport type TranslateInput = z.infer<typeof translateInputSchema>;\nexport type ImageInput = z.infer<typeof imageInputSchema>;\nexport type AnimateInput = z.infer<typeof animateInputSchema>;\nexport type TrainStyleInput = z.infer<typeof trainStyleInputSchema>;\nexport type EmbeddingInput = z.infer<typeof embeddingInputSchema>;\nexport type TranscribeInput = z.infer<typeof transcribeInputSchema>;\nexport type OcrInput = z.infer<typeof ocrInputSchema>;\nexport type ModerationInput = z.infer<typeof moderationInputSchema>;\nexport type PodcastInput = z.infer<typeof podcastInputSchema>;\nexport type TtsInput = z.infer<typeof ttsInputSchema>;\nexport type AiConfig = z.infer<typeof aiConfigSchema>;\n\n/** The public facade. Defined here because it depends on the derived inputs. */\nexport interface AiClient {\n chat(input: ChatInput): Promise<ChatResult>;\n /** Streaming chat (F8) — same input as chat; yields ChatStreamEvents. The\n * caller owns the tool-loop (per-turn engine, not an agent runtime). */\n chatStream(input: ChatInput): AsyncIterable<ChatStreamEvent>;\n vision(input: VisionInput): Promise<ChatResult>;\n /** Video Vision (F019) — analyze a video natively. Default tier: \"video\". */\n video(input: VideoInput): Promise<ChatResult>;\n translate(input: TranslateInput): Promise<TranslateResult>;\n image(input: ImageInput): Promise<ImageResult>;\n /** Image-to-video (F024) — animate a still into a short clip → { url, usage }. fal. */\n animate(input: AnimateInput): Promise<AnimateResult>;\n /** Train a style/brand LoRA from images (F021) → { loraUrl, configUrl }. fal. */\n trainStyle(input: TrainStyleInput): Promise<TrainStyleResult>;\n embedding(input: EmbeddingInput): Promise<EmbeddingResult>;\n transcribe(input: TranscribeInput): Promise<TranscribeResult>;\n /** OCR (F016.2) — document/image → structured markdown, billed per page. Mistral. */\n ocr(input: OcrInput): Promise<OcrResult>;\n /** Moderation (F016.4) — classify text against safety categories. Mistral. */\n moderate(input: ModerationInput): Promise<ModerationResult>;\n /** Podcast (F020) — a finished manuscript → one multi-voice audio episode. ElevenLabs. */\n podcast(input: PodcastInput): Promise<PodcastResult>;\n /** Single-voice TTS (F020.4) — text → audio. `voice` = curated name or voiceId. ElevenLabs. */\n tts(input: TtsInput): Promise<PodcastResult>;\n /** Batch (F016.1) — submit many chat requests for async (≤24h) processing at 50% cost. Mistral. */\n batch: {\n submit(input: { requests: BatchRequestItem[]; override?: TierSpec }): Promise<BatchJob>;\n status(jobId: string, override?: TierSpec): Promise<BatchJob>;\n results(jobId: string, override?: TierSpec): Promise<BatchResultItem[]>;\n };\n /** Prompt-contract capabilities (F5.5) layered on chat/vision. */\n contracts: Contracts;\n}\n","// AUTO-GENERATED by scripts/gen-version.mjs — do not edit, do not commit.\nexport const VERSION = \"0.37.0\" as const;\nexport const SDK_TAG = \"@broberg/ai-sdk@0.37.0\" as const;\n","// upmetricsSink — the canonical cost sink. Forwards each Usage to the upmetrics\n// agent-run ingest (POST /api/agent, mode:\"record\"). Field mapping follows\n// upmetrics/docs/AGENT-SCHEMA.md \"For cost-sink authors\" exactly:\n// - agent_kind / agent_name are injected (not in Usage; required by ingest)\n// - camelCase Usage → snake_case wire fields\n// - capability + transport ride in tags (no top-level column)\n// - toolCalls[].errorCount → tool_calls[].error_count (deep rename)\n// - latencyMs → duration_ms; ts → started_at; ended_at = ts + latency\n// Errors never propagate (CostSink invariant). Do NOT use @upmetrics/agent\n// wrapAnthropic here — the SDK already owns the provider call.\nimport { SDK_TAG } from \"../../version.js\";\nimport type { CostSink, Usage } from \"../../types.js\";\n\nexport interface UpmetricsSinkConfig {\n /** Ingest base URL, e.g. https://upmetrics.org */\n baseUrl: string;\n /** Per-project api_key → sent as the X-Upmetrics-Key header. */\n apiKey: string;\n /** Consumer name dashboards group by (e.g. \"cms\", \"trail\", \"xrt81\") — NOT the\n * capability. */\n agentName: string;\n /** Defaults to \"chatbot\" (\"embedding\" auto-selected for embedding calls). */\n agentKind?: string;\n /** When true, guarantees no prompt/response content is ever sent (the sink\n * sends none regardless — Usage carries no excerpts — so this is belt-and-\n * suspenders for GDPR-health projects). */\n complianceMode?: boolean;\n /** Injectable fetch for testing; defaults to global fetch. */\n fetch?: typeof fetch;\n /** Optional error hook (errors are otherwise swallowed silently). */\n onError?: (err: unknown) => void;\n}\n\nexport function upmetricsSink(config: UpmetricsSinkConfig): CostSink {\n const doFetch = config.fetch ?? fetch;\n const url = `${config.baseUrl.replace(/\\/$/, \"\")}/api/agent`;\n\n return {\n async record(usage: Usage): Promise<void> {\n try {\n const startedAt = usage.ts || new Date().toISOString();\n const endedAt = new Date(\n new Date(startedAt).getTime() + (usage.latencyMs || 0),\n ).toISOString();\n\n const agentKind =\n config.agentKind ?? (usage.capability === \"embedding\" ? \"embedding\" : \"chatbot\");\n\n const body: Record<string, unknown> = {\n mode: \"record\",\n agent_kind: agentKind,\n agent_name: config.agentName,\n provider: usage.provider,\n model: usage.model,\n status: \"success\",\n input_tokens: usage.inputTokens,\n output_tokens: usage.outputTokens,\n cache_read_tokens: usage.cacheReadTokens,\n cache_creation_tokens: usage.cacheCreationTokens,\n cost_usd: usage.costUsd,\n duration_ms: usage.latencyMs,\n started_at: startedAt,\n ended_at: endedAt,\n tags: {\n // Consumer attribution labels (e.g. tenantId) ride in tags so no new\n // top-level field risks the strict-shape ingest schema (F011). The\n // SDK-owned keys win — a label can never clobber capability/transport/sdk.\n ...usage.labels,\n capability: usage.capability,\n transport: usage.transport,\n // F042: data residency of the route that answered. Rides in tags like\n // capability/transport — no ingest-schema change, and without it the one\n // field built for auditability existed only in memory.\n region: usage.region,\n sdk: SDK_TAG,\n },\n };\n if (usage.tier !== undefined) body.tier = usage.tier;\n if (usage.purpose !== undefined) body.purpose = usage.purpose;\n if (usage.toolCalls) {\n body.tool_calls = usage.toolCalls.map((t) => ({\n name: t.name,\n count: t.count,\n error_count: t.errorCount ?? 0,\n }));\n }\n // complianceMode is a no-op today (we never send excerpts) but documents intent.\n void config.complianceMode;\n\n const res = await doFetch(url, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n \"X-Upmetrics-Key\": config.apiKey,\n },\n body: JSON.stringify(body),\n });\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n config.onError?.(\n new Error(`upmetricsSink: ingest returned ${res.status}: ${text.slice(0, 200)}`),\n );\n }\n } catch (err) {\n // Never let a sink failure crash a real AI call.\n config.onError?.(err);\n }\n },\n };\n}\n","// createAI() — the facade factory. Resolves routing, picks a provider adapter,\n// delegates the call, stamps call-context metadata onto Usage, and reports to the\n// cost sink. Provider specifics live in adapters; cost compute/budget land in F3.\nimport { assertOverrideProvider, resolveTier } from \"./routing/tier-map.js\";\nimport { resolveModel } from \"./availability/resolve.js\";\nimport { defaultProviders } from \"./providers/registry.js\";\nimport { computeCost } from \"./cost/usage.js\";\nimport { BudgetGuard } from \"./cost/budget.js\";\nimport { buildVisionMessages, VISION_DEFAULT_TIER } from \"./capabilities/vision.js\";\nimport { buildVideoMessages, VIDEO_DEFAULT_TIER } from \"./capabilities/video.js\";\nimport { buildTranslateMessages, TRANSLATE_DEFAULT_TIER } from \"./capabilities/translate.js\";\nimport { EMBEDDING_DEFAULT_TIER } from \"./capabilities/embedding.js\";\nimport { DEFAULT_TRANSCRIBE_SPEC, resolveAudio } from \"./capabilities/transcribe.js\";\nimport { makeContracts } from \"./capabilities/contracts/index.js\";\nimport { checkVoice, VoiceUnavailableError } from \"./voices/index.js\";\nimport {\n aiConfigSchema,\n chatInputSchema,\n visionInputSchema,\n videoInputSchema,\n translateInputSchema,\n imageInputSchema,\n animateInputSchema,\n trainStyleInputSchema,\n embeddingInputSchema,\n transcribeInputSchema,\n ocrInputSchema,\n moderationInputSchema,\n podcastInputSchema,\n ttsInputSchema,\n} from \"./schema/inputs.js\";\nimport type {\n AiConfig,\n AiClient,\n ChatInput,\n VisionInput,\n VideoInput,\n TranslateInput,\n ImageInput,\n AnimateInput,\n TrainStyleInput,\n EmbeddingInput,\n TranscribeInput,\n OcrInput,\n ModerationInput,\n PodcastInput,\n TtsInput,\n} from \"./schema/inputs.js\";\nimport type {\n ChatResult,\n ChatStreamEvent,\n ImageResult,\n AnimateResult,\n TrainStyleResult,\n EmbeddingResult,\n TranscribeResult,\n OcrResult,\n ModerationResult,\n PodcastResult,\n BatchRequestItem,\n BatchJob,\n BatchResultItem,\n TranslateResult,\n ProviderAdapter,\n Message,\n Capability,\n Tier,\n TierSpec,\n Usage,\n CostSink,\n} from \"./types.js\";\nimport { upmetricsSink } from \"./cost/sinks/upmetrics.js\";\n\n/** Built-in image route (no image tier in the tier map — fal owns its routing). */\nconst DEFAULT_IMAGE_SPEC: TierSpec = {\n provider: \"fal\",\n model: \"fal-ai/flux/schnell\",\n transport: \"http\",\n};\n/** LoRA-inference route (F021) — used by ai.image when loras are supplied. */\nconst DEFAULT_LORA_IMAGE_SPEC: TierSpec = {\n provider: \"fal\",\n model: \"fal-ai/flux-lora\",\n transport: \"http\",\n};\n/** Style-LoRA training route (F021) — fal flux-lora-fast-training. */\nconst DEFAULT_TRAINSTYLE_SPEC: TierSpec = {\n provider: \"fal\",\n model: \"fal-ai/flux-lora-fast-training\",\n transport: \"http\",\n};\n/** Image-to-video route (F024) — Veo 3.1 DIRECT via the Gemini API (no fal markup,\n * our existing GEMINI_API_KEY, and the path to EU via Vertex later). Override to\n * {provider:\"fal\", model:\"fal-ai/veo3.1/...\"} for the aggregator / other models\n * (Kling, Seedance). US-hosted: consent-gated use (F024). */\nconst DEFAULT_ANIMATE_SPEC: TierSpec = {\n provider: \"gemini\",\n model: \"veo-3.1-generate-preview\",\n transport: \"http\",\n};\n/** Default audio directive for ai.animate (F024, Christian's preference): no\n * generated speech (it's the weak link, esp. non-English), but ambient sounds\n * matched to the scene are wanted. A soft prompt instruction. */\nconst ANIMATE_AUDIO_DIRECTIVE =\n \"No spoken dialogue, no talking, no voiceover. Include natural ambient background sounds that match the environment.\";\n\n/** Does the route we ACTUALLY resolved to produce an audio track? (F045)\n *\n * This used to be appended to every animate prompt unconditionally. super measured a\n * Kling clip we generated through fal and found NO audio stream at all — so on that\n * route the directive is not merely wasted tokens, it describes a world with sound to\n * a model that can only draw. The instruction that cannot be obeyed still competes for\n * attention with the one that can.\n *\n * Keyed on the MODEL, not the provider: fal also serves Veo (`fal-ai/veo3.1/...`),\n * which does have audio, so \"fal means silent\" would be wrong the moment someone\n * overrides to Veo through the aggregator. Unknown models get the directive — the\n * historical behaviour, and the safe direction: a silent model ignores a sentence\n * about sound, while withholding it from an audio model silently degrades the output\n * we ship by default. */\nfunction routeHasAudio(spec: { provider: string; model: string }): boolean {\n const m = spec.model.toLowerCase();\n // Known silent image-to-video families. Measured: Kling v2.5 (ffprobe, 0 audio streams).\n if (m.includes(\"kling\") || m.includes(\"seedance\") || m.includes(\"wan-\")) return false;\n return true;\n}\n/** EU-resident finetuned-portrait route (F023) — BFL, used by ai.image when a\n * `finetune` id is supplied. Hard-pinned to api.eu.bfl.ai inside the adapter. */\nconst DEFAULT_BFL_FINETUNE_SPEC: TierSpec = {\n provider: \"bfl\",\n model: \"flux-pro-1.1-ultra-finetuned\",\n transport: \"http\",\n};\n/** EU-resident multi-reference route (F023.5) — BFL FLUX 2, used by ai.image when\n * `referenceImages` are supplied (likeness with no training step). flux-2-max =\n * premium-quality default; override to flux-2-pro/flex for volume. EU-pinned. */\nconst DEFAULT_BFL_REFERENCE_SPEC: TierSpec = {\n provider: \"bfl\",\n model: \"flux-2-max\",\n transport: \"http\",\n};\n\n/** OCR + moderation are Mistral specialty endpoints (F016) — no tier, route by default. */\nconst DEFAULT_OCR_SPEC: TierSpec = { provider: \"mistral\", model: \"mistral-ocr-latest\", transport: \"http\" };\nconst DEFAULT_MODERATION_SPEC: TierSpec = { provider: \"mistral\", model: \"mistral-moderation-latest\", transport: \"http\" };\n/** Podcast route (F020) — ElevenLabs Text-to-Dialogue, eleven_v3 (multi-voice, multilingual). */\nconst DEFAULT_PODCAST_SPEC: TierSpec = { provider: \"elevenlabs\", model: \"eleven_v3\", transport: \"http\" };\n/** Single-voice TTS route (F020.4) — ElevenLabs eleven_multilingual_v2 (good Danish). */\nconst DEFAULT_TTS_SPEC: TierSpec = { provider: \"elevenlabs\", model: \"eleven_multilingual_v2\", transport: \"http\" };\n/** Batch route (F016.1) — Mistral batch jobs (50% cost), cheap default model. */\nconst DEFAULT_BATCH_SPEC: TierSpec = { provider: \"mistral\", model: \"mistral-small-latest\", transport: \"http\" };\n\n/** Cost-tracking on by DEFAULT (F034): an explicit config.costSink always wins;\n * otherwise, when the upmetrics env is present, auto-wire the canonical sink so\n * fleet-wide call-sites report without per-repo wiring (per-repo wiring drifts —\n * ~91% of Mistral spend was invisible because most call-sites passed no sink).\n * Env absent (no UPMETRICS_API_KEY) → undefined = ship-dark, current behaviour.\n * Server-entry only: createAI already pulls the provider adapters (which read\n * process.env at call time), so this module is never in the browser build (the\n * browser imports \"@broberg/ai-sdk/registry\"). */\nfunction defaultCostSink(): CostSink | undefined {\n const apiKey = process.env.UPMETRICS_API_KEY;\n if (!apiKey) return undefined;\n return upmetricsSink({\n baseUrl: process.env.UPMETRICS_BASE_URL ?? \"https://upmetrics.org\",\n apiKey,\n agentName: process.env.UPMETRICS_AGENT_NAME ?? process.env.npm_package_name ?? \"unknown\",\n complianceMode: process.env.UPMETRICS_COMPLIANCE === \"1\",\n });\n}\n\nexport function createAI(config: AiConfig = {}): AiClient {\n // Validate config at the boundary (throws ZodError on bad shape).\n const cfg = aiConfigSchema.parse(config);\n const providers = cfg.providers ?? defaultProviders;\n // Explicit wins — including explicit NONE. `undefined` (omitted) auto-wires\n // from env (F034); `null` is a deliberate opt-out for a consumer that already\n // reports its own costs and would otherwise be double-counted (F034.3); an\n // object is used as-is.\n const costSink = cfg.costSink === undefined ? defaultCostSink() : (cfg.costSink ?? undefined);\n const budget = cfg.budget ? new BudgetGuard(cfg.budget) : undefined;\n\n const estTokens = (s: string): number => Math.ceil(s.length / 4);\n\n /** Pre-flight budget check. Estimates this call's cost and throws\n * BudgetExceededError before the transport fires. No-op without a budget. */\n async function preflight(spec: TierSpec, estInTokens: number, estOutTokens: number): Promise<void> {\n if (!budget) return;\n await budget.check(computeCost(spec.provider, spec.model, estInTokens, estOutTokens));\n }\n\n /** Fold the actual cost into the rolling total after a successful call. */\n async function settle(usage: Usage): Promise<void> {\n if (budget) await budget.record(usage.costUsd);\n }\n\n const providerNames = Object.keys(providers);\n\n /** THE ONE PLACE a non-tier capability merges its override (F043.2). The guard used\n * to live inside resolveTier, which nine capabilities never call — so they merged\n * the override themselves and skipped it, and ai.image({override:{provider:\"fal\"}})\n * still posted BFL's flux-2-pro to fal.\n *\n * NOT used by tts/podcast/transcribe, and the reason is measured rather than\n * assumed: the guard exists because a foreign model id gets POSTED to the provider.\n * Azure's TTS never sends spec.model at all — it reads req.voiceId and puts the\n * model only in the usage record — so `ai.tts({override:{provider:\"azure\"}})` is a\n * legitimate, already-tested call with nothing to refuse. Guarding it broke that\n * test, and the test was right. Speech routes by VOICE; the model is an engine hint\n * each adapter interprets for itself. */\n function withOverride(\n base: TierSpec,\n override: Partial<TierSpec> | undefined,\n label: string,\n ): TierSpec {\n assertOverrideProvider(base, override, label, providerNames);\n return { ...base, ...override };\n }\n\n /** Merge an override WITHOUT the provider/model guard, stating why in the call.\n *\n * The guard exists because a foreign model id gets POSTED to the provider. Where\n * the provider never sends spec.model, there is nothing to refuse and guarding\n * breaks a legitimate call. That exemption is real — but until now a raw\n * `{...base, ...override}` looked identical whether it was DELIBERATE or FORGOTTEN,\n * and telling those two apart by counting call sites is exactly what failed three\n * times in the fleet this week.\n *\n * So the exemption gets a name and a mandatory reason, and a structural test\n * forbids the raw spread everywhere else. `why` is unused at runtime on purpose:\n * its whole job is to make a silent exemption impossible to write. */\n function mergeUnguarded(base: TierSpec, override: Partial<TierSpec> | undefined, why: string): TierSpec {\n void why;\n return { ...base, ...override };\n }\n\n function pickProvider(name: string): ProviderAdapter {\n // Object.hasOwn, not a bare lookup: `providers` inherits from Object.prototype, so\n // providers[\"constructor\"] returns a FUNCTION and passes the !adapter check. The\n // caller then got \"provider \\\"constructor\\\" does not support chat\" instead of \"no\n // provider adapter registered\" — it fails closed, but on exactly the override path\n // F043.2 just fixed for giving a misleading message, so leaving it would be\n // inconsistent with that change.\n const adapter = Object.hasOwn(providers, name) ? providers[name] : undefined;\n if (!adapter) {\n throw new Error(\n `createAI: no provider adapter registered for \"${name}\". Registered: ${Object.keys(providers).join(\", \") || \"(none)\"}`,\n );\n }\n return adapter;\n }\n\n /** Stamp call-context metadata the client owns onto the adapter's Usage:\n * capability, tier, purpose, the wall-clock latency, and the timestamp. */\n function enrich(\n usage: Usage,\n capability: Capability,\n tier: Tier | undefined,\n purpose: string | undefined,\n latencyMs: number,\n labels: Record<string, string> | undefined,\n ): Usage {\n usage.capability = capability;\n if (tier) usage.tier = tier;\n if (purpose) usage.purpose = purpose;\n if (labels && Object.keys(labels).length > 0) usage.labels = labels;\n usage.latencyMs = Math.round(latencyMs);\n if (!usage.ts) usage.ts = new Date().toISOString();\n return usage;\n }\n\n async function report(usage: Usage): Promise<void> {\n if (!costSink) return;\n try {\n await costSink.record(usage);\n } catch {\n // A broken sink must never crash a real AI call (F3.3 invariant).\n }\n }\n\n function toMessages(input: ChatInput): Message[] {\n if (input.messages && input.messages.length > 0) {\n // A top-level `system` must survive when `messages` is also supplied — prepend\n // it (unless the caller already leads with a system message) instead of\n // silently dropping it. Regression: system + messages → system was lost, so a\n // \"return ONLY JSON\" system instruction never reached the model (cms #4234).\n if (input.system && input.messages[0]?.role !== \"system\") {\n return [{ role: \"system\", content: input.system }, ...input.messages];\n }\n return input.messages;\n }\n const msgs: Message[] = [];\n if (input.system) msgs.push({ role: \"system\", content: input.system });\n msgs.push({ role: \"user\", content: input.prompt ?? \"\" });\n return msgs;\n }\n\n /** F022 — opt-in proactive availability gate. When cfg.availability.autoResolve\n * is set, swap a known-suspended primary model to its configured fallback\n * BEFORE dispatch (synchronous, registry-only — no I/O). Default off → the\n * spec is returned untouched and behaviour is byte-identical. This sits in\n * front of the reactive route-fallback below. */\n function applyAvailability(spec: TierSpec): TierSpec {\n if (!cfg.availability?.autoResolve) return spec;\n const r = resolveModel(spec.model, { fallback: cfg.availability.fallback, provider: spec.provider });\n return r.fellBack ? { ...spec, model: r.model } : spec;\n }\n\n /** Run a capability with an optional fallback chain. Tries the primary route,\n * then each fallback (Tier or TierSpec) in order if the call errors. A budget\n * breach propagates immediately (not a fallback trigger). On the first\n * success: stamp Usage, settle the budget, report to the sink, return. */\n async function runCapability<R extends { usage: Usage }>(opts: {\n primary: TierSpec;\n fallback?: (Tier | TierSpec)[];\n capability: Capability;\n tier?: Tier;\n purpose?: string;\n labels?: Record<string, string>;\n estIn: number;\n estOut: number;\n invoke: (spec: TierSpec) => Promise<R>;\n }): Promise<R> {\n const routes: TierSpec[] = [\n applyAvailability(opts.primary),\n ...(opts.fallback ?? []).map((f) =>\n typeof f === \"string\" ? resolveTier(f, undefined, cfg.defaults) : f,\n ),\n ];\n let lastErr: unknown;\n for (let i = 0; i < routes.length; i++) {\n const spec = routes[i]!;\n await preflight(spec, opts.estIn, opts.estOut); // BudgetExceededError propagates\n try {\n const t0 = performance.now();\n const res = await opts.invoke(spec);\n enrich(res.usage, opts.capability, i === 0 ? opts.tier : undefined, opts.purpose, performance.now() - t0, opts.labels);\n await settle(res.usage);\n await report(res.usage);\n return res;\n } catch (e) {\n lastErr = e; // try the next fallback route\n }\n }\n throw lastErr;\n }\n\n /** Whether a pre-first-token streaming error should fall back to the next\n * route. Eligible: network/timeout/parse (no status) + 429 + 5xx. Hard 4xx\n * bubbles up (no silent re-route) — sa contract #2565. */\n function eligibleForFallback(e: unknown): boolean {\n const status = (e as { status?: number } | null)?.status;\n if (status === undefined) return true;\n return status === 429 || status >= 500;\n }\n\n function errorEvent(e: unknown): ChatStreamEvent {\n const ev: ChatStreamEvent = {\n type: \"error\",\n message: e instanceof Error ? e.message : String(e),\n };\n const status = (e as { status?: number } | null)?.status;\n if (status !== undefined) ev.status = status;\n return ev;\n }\n\n /** Streaming chat with pre-stream fallback (F8.1). Yields ChatStreamEvents as\n * the turn unfolds. Fallback re-routes only BEFORE the first text/tool_call\n * event (deltas can't be un-emitted); once streaming has begun, an error is\n * surfaced as an error event and the stream ends. Budget breaches propagate. */\n async function* chatStreamImpl(input: ChatInput): AsyncIterable<ChatStreamEvent> {\n input = chatInputSchema.parse(input);\n const tier = input.tier ?? \"smart\";\n const messages = toMessages(input);\n const estIn = messages.reduce(\n (n, m) => n + estTokens(typeof m.content === \"string\" ? m.content : JSON.stringify(m.content)),\n 0,\n );\n const estOut = input.maxTokens ?? 512;\n const routes: TierSpec[] = [\n resolveTier(tier, input.override, cfg.defaults, providerNames),\n ...(input.fallback ?? []).map((f) =>\n typeof f === \"string\" ? resolveTier(f, undefined, cfg.defaults) : f,\n ),\n ];\n\n let lastErr: unknown;\n for (let i = 0; i < routes.length; i++) {\n const spec = routes[i]!;\n await preflight(spec, estIn, estOut); // BudgetExceededError propagates\n const adapter = pickProvider(spec.provider);\n if (!adapter.chatStream) {\n throw new Error(`createAI: provider \"${spec.provider}\" does not support streaming`);\n }\n const t0 = performance.now();\n let emitted = false;\n try {\n for await (const ev of adapter.chatStream({\n messages,\n spec,\n tools: input.tools,\n maxTokens: input.maxTokens,\n temperature: input.temperature,\n responseFormat: input.responseFormat,\n // F043: these two were dropped here, so a streamed call could not cache even\n // after the adapter learned how. A chat UI streams every turn and repeats the\n // same system prompt each time — the call shape with the most to gain was the\n // one paying full price. Kept identical to the chat branch above on purpose.\n promptCacheKey: input.promptCacheKey,\n promptCache: input.promptCache ?? cfg.promptCache,\n })) {\n if (ev.type === \"text\" || ev.type === \"tool_call\") emitted = true;\n if (ev.type === \"usage\") {\n enrich(ev.usage, \"chat\", i === 0 ? tier : undefined, input.purpose, performance.now() - t0, input.labels);\n await settle(ev.usage);\n await report(ev.usage);\n }\n yield ev;\n }\n return; // stream completed cleanly\n } catch (e) {\n lastErr = e;\n if (emitted || !eligibleForFallback(e)) {\n yield errorEvent(e); // mid-stream or hard error → surface + stop\n return;\n }\n // pre-first-token eligible error → try the next route\n }\n }\n yield errorEvent(lastErr);\n }\n\n const client: AiClient = {\n async chat(input: ChatInput): Promise<ChatResult> {\n input = chatInputSchema.parse(input);\n const tier = input.tier ?? \"smart\";\n const messages = toMessages(input);\n const estIn = messages.reduce(\n (n, m) => n + estTokens(typeof m.content === \"string\" ? m.content : JSON.stringify(m.content)),\n 0,\n );\n return runCapability({\n primary: resolveTier(tier, input.override, cfg.defaults, providerNames),\n fallback: input.fallback,\n capability: \"chat\",\n tier,\n purpose: input.purpose,\n labels: input.labels,\n estIn,\n estOut: input.maxTokens ?? 512,\n invoke: async (spec) => {\n const adapter = pickProvider(spec.provider);\n if (!adapter.chat) throw new Error(`createAI: provider \"${spec.provider}\" does not support chat`);\n return adapter.chat({ messages, spec, tools: input.tools, maxTokens: input.maxTokens, temperature: input.temperature, responseFormat: input.responseFormat, promptCacheKey: input.promptCacheKey, promptCache: input.promptCache ?? cfg.promptCache });\n },\n });\n },\n\n chatStream: chatStreamImpl,\n\n async vision(input: VisionInput): Promise<ChatResult> {\n input = visionInputSchema.parse(input);\n const tier = input.tier ?? VISION_DEFAULT_TIER;\n const messages: Message[] = buildVisionMessages(input);\n return runCapability({\n primary: resolveTier(tier, input.override, cfg.defaults, providerNames),\n fallback: input.fallback,\n capability: \"vision\",\n tier,\n purpose: input.purpose,\n labels: input.labels,\n estIn: estTokens(input.prompt) + 1000, // prompt + ~1k image payload\n estOut: 512,\n invoke: async (spec) => {\n const adapter = pickProvider(spec.provider);\n if (!adapter.vision) throw new Error(`createAI: provider \"${spec.provider}\" does not support vision`);\n return adapter.vision({ messages, spec });\n },\n });\n },\n\n async video(input: VideoInput): Promise<ChatResult> {\n input = videoInputSchema.parse(input);\n const tier = input.tier ?? VIDEO_DEFAULT_TIER;\n const messages: Message[] = buildVideoMessages(input);\n return runCapability({\n primary: resolveTier(tier, input.override, cfg.defaults, providerNames),\n fallback: input.fallback,\n capability: \"video\",\n tier,\n purpose: input.purpose,\n labels: input.labels,\n estIn: estTokens(input.prompt) + 4000, // prompt + video tokens (native video ≈ frames)\n estOut: 512,\n invoke: async (spec) => {\n const adapter = pickProvider(spec.provider);\n // Video routes through the vision method — same multimodal message path.\n if (!adapter.vision) throw new Error(`createAI: provider \"${spec.provider}\" does not support video`);\n return adapter.vision({ messages, spec });\n },\n });\n },\n\n async translate(input: TranslateInput): Promise<TranslateResult> {\n input = translateInputSchema.parse(input);\n const tier = input.tier ?? TRANSLATE_DEFAULT_TIER;\n const messages: Message[] = buildTranslateMessages(input);\n const estIn = estTokens(input.text) + 40;\n const res = await runCapability<TranslateResult>({\n primary: resolveTier(tier, input.override, cfg.defaults, providerNames),\n fallback: input.fallback,\n capability: \"translate\",\n tier,\n purpose: input.purpose,\n labels: input.labels,\n estIn,\n estOut: estIn,\n invoke: async (spec) => {\n const adapter = pickProvider(spec.provider);\n // A dedicated translation engine (F032, e.g. DeepL) is preferred when the\n // resolved provider implements it — its `to`/`from` are provider-specific\n // codes, not the free-form names the chat prompt-contract accepts.\n if (adapter.translate) return adapter.translate({ text: input.text, to: input.to, from: input.from, spec });\n if (!adapter.chat) throw new Error(`createAI: provider \"${spec.provider}\" does not support chat (translate routes through chat)`);\n return adapter.chat({ messages, spec });\n },\n });\n return { text: res.text, usage: res.usage };\n },\n\n async image(input: ImageInput): Promise<ImageResult> {\n input = imageInputSchema.parse(input);\n // Normalize the `lora` shorthand into the loras array.\n const loras = [\n ...(input.loras ?? []),\n ...(input.lora ? [{ path: input.lora }] : []),\n ];\n // Route by what's supplied (override still wins): `referenceImages` → the EU\n // BFL FLUX 2 multi-reference endpoint (F023.5, no training step); a `finetune`\n // id → the EU BFL finetuned-portrait endpoint (F023); LoRAs → flux-lora (F021,\n // flux/schnell can't merge LoRAs); else the plain image route.\n const base = input.referenceImages?.length\n ? DEFAULT_BFL_REFERENCE_SPEC\n : input.finetune\n ? DEFAULT_BFL_FINETUNE_SPEC\n : loras.length > 0\n ? DEFAULT_LORA_IMAGE_SPEC\n : DEFAULT_IMAGE_SPEC;\n return runCapability({\n primary: withOverride(base, input.override, \"image\"),\n fallback: input.fallback,\n capability: \"image\",\n purpose: input.purpose,\n labels: input.labels,\n estIn: 0, // image cost is not token-based\n estOut: 0,\n invoke: async (spec) => {\n const adapter = pickProvider(spec.provider);\n if (!adapter.image) throw new Error(`createAI: provider \"${spec.provider}\" does not support image`);\n return adapter.image({\n prompt: input.prompt,\n spec,\n width: input.width,\n height: input.height,\n loras: loras.length ? loras : undefined,\n finetune: input.finetune,\n finetuneStrength: input.finetuneStrength,\n referenceImages: input.referenceImages,\n seed: input.seed,\n outputFormat: input.outputFormat,\n safetyTolerance: input.safetyTolerance,\n retryOnBlack: input.retryOnBlack,\n });\n },\n });\n },\n\n async animate(input: AnimateInput): Promise<AnimateResult> {\n input = animateInputSchema.parse(input);\n // The audio directive is decided per RESOLVED route, INSIDE invoke — not here.\n // Built up front it would be computed before withOverride and before any\n // fallback, i.e. from a spec the call may never use: exactly the gap between\n // what we say and what we send that F045 is about.\n const basePrompt = input.prompt?.trim() ?? \"\";\n return runCapability({\n primary: withOverride(DEFAULT_ANIMATE_SPEC, input.override, \"animate\"),\n fallback: input.fallback,\n capability: \"animate\",\n purpose: input.purpose,\n labels: input.labels,\n estIn: 0, // video cost is per-second, not token-based\n estOut: 0,\n invoke: async (spec) => {\n const adapter = pickProvider(spec.provider);\n if (!adapter.animate) throw new Error(`createAI: provider \"${spec.provider}\" does not support animate`);\n const prompt = routeHasAudio(spec)\n ? `${basePrompt} ${ANIMATE_AUDIO_DIRECTIVE}`.trim()\n : basePrompt;\n return adapter.animate({\n image: input.image,\n prompt: prompt || undefined,\n durationSec: input.durationSec,\n resolution: input.resolution,\n spec,\n });\n },\n });\n },\n\n async trainStyle(input: TrainStyleInput): Promise<TrainStyleResult> {\n input = trainStyleInputSchema.parse(input);\n return runCapability({\n primary: withOverride(DEFAULT_TRAINSTYLE_SPEC, input.override, \"trainStyle\"),\n fallback: input.fallback,\n capability: \"trainStyle\",\n purpose: input.purpose,\n labels: input.labels,\n estIn: 0, // training is priced flat by fal, not token-based\n estOut: 0,\n invoke: async (spec) => {\n const adapter = pickProvider(spec.provider);\n if (!adapter.trainStyle)\n throw new Error(`createAI: provider \"${spec.provider}\" does not support trainStyle`);\n return adapter.trainStyle({\n images: input.images,\n spec,\n isStyle: input.isStyle,\n triggerWord: input.triggerWord,\n steps: input.steps,\n createMasks: input.createMasks,\n });\n },\n });\n },\n\n async ocr(input: OcrInput): Promise<OcrResult> {\n input = ocrInputSchema.parse(input);\n return runCapability({\n primary: withOverride(DEFAULT_OCR_SPEC, input.override, \"ocr\"),\n fallback: input.fallback,\n capability: \"ocr\",\n purpose: input.purpose,\n labels: input.labels,\n estIn: 0, // OCR cost is per-page, not token-based\n estOut: 0,\n invoke: async (spec) => {\n const adapter = pickProvider(spec.provider);\n if (!adapter.ocr) throw new Error(`createAI: provider \"${spec.provider}\" does not support ocr`);\n return adapter.ocr({ document: input.document, mimeType: input.mimeType, spec });\n },\n });\n },\n\n async moderate(input: ModerationInput): Promise<ModerationResult> {\n input = moderationInputSchema.parse(input);\n const items = Array.isArray(input.input) ? input.input : [input.input];\n return runCapability({\n primary: withOverride(DEFAULT_MODERATION_SPEC, input.override, \"moderate\"),\n fallback: input.fallback,\n capability: \"moderation\",\n purpose: input.purpose,\n labels: input.labels,\n estIn: items.reduce((n, s) => n + estTokens(s), 0),\n estOut: 0,\n invoke: async (spec) => {\n const adapter = pickProvider(spec.provider);\n if (!adapter.moderate) throw new Error(`createAI: provider \"${spec.provider}\" does not support moderation`);\n return adapter.moderate({ input: items, spec });\n },\n });\n },\n\n async podcast(input: PodcastInput): Promise<PodcastResult> {\n input = podcastInputSchema.parse(input);\n // Map each manuscript turn to a {text, voiceId} dialogue input.\n const inputs = input.script.map((turn) => {\n const mapped = input.voices[turn.speaker];\n if (!mapped) throw new Error(`ai.podcast: no voice mapped for speaker \"${turn.speaker}\"`);\n // F037: refuse a voice we know is retired. No fallback here on purpose —\n // silently collapsing two speakers onto one voice ruins a dialogue, so a\n // dead voice in a cast is a refusal, not a degradation.\n const res = checkVoice(mapped); // curated name → voiceId\n if (!res.ok) throw new VoiceUnavailableError(mapped, `${res.reason} — speaker \"${turn.speaker}\"`, res.provider);\n return { text: turn.text, voiceId: res.voiceId };\n });\n const chars = input.script.reduce((n, t) => n + t.text.length, 0);\n return runCapability({\n primary: mergeUnguarded(DEFAULT_PODCAST_SPEC, input.override, \"routes by voice, not by model — the adapter never sends spec.model\"),\n fallback: input.fallback,\n capability: \"podcast\",\n purpose: input.purpose,\n labels: input.labels,\n estIn: chars, // per-character cost (not token-based)\n estOut: 0,\n invoke: async (spec) => {\n const adapter = pickProvider(spec.provider);\n if (!adapter.dialogue) throw new Error(`createAI: provider \"${spec.provider}\" does not support podcast/dialogue`);\n return adapter.dialogue({ inputs, format: input.format, spec });\n },\n });\n },\n\n async tts(input: TtsInput): Promise<PodcastResult> {\n input = ttsInputSchema.parse(input);\n // F037: gate the voice BEFORE the call path. Resolving here rather than inside\n // invoke() means a refusal is immediate and cannot be mistaken for a provider\n // failure and retried against the fallback chain.\n const { voiceId } = checkVoice(input.voice, { fallback: input.voiceFallback, throwIfUnavailable: true });\n return runCapability({\n primary: mergeUnguarded(DEFAULT_TTS_SPEC, input.override, \"routes by voice, not by model — the adapter never sends spec.model\"),\n fallback: input.fallback,\n capability: \"tts\",\n purpose: input.purpose,\n labels: input.labels,\n estIn: input.text.length, // per-character cost\n estOut: 0,\n invoke: async (spec) => {\n const adapter = pickProvider(spec.provider);\n if (!adapter.tts) throw new Error(`createAI: provider \"${spec.provider}\" does not support tts`);\n return adapter.tts({ text: input.text, voiceId, lang: input.lang, format: input.format, rate: input.rate, spec });\n },\n });\n },\n\n async embedding(input: EmbeddingInput): Promise<EmbeddingResult> {\n input = embeddingInputSchema.parse(input);\n const tier = input.tier ?? EMBEDDING_DEFAULT_TIER;\n const text = Array.isArray(input.text) ? input.text : [input.text];\n return runCapability({\n primary: resolveTier(tier, input.override, cfg.defaults, providerNames),\n fallback: input.fallback,\n capability: \"embedding\",\n tier,\n purpose: input.purpose,\n labels: input.labels,\n estIn: text.reduce((n, t) => n + estTokens(t), 0),\n estOut: 0,\n invoke: async (spec) => {\n const adapter = pickProvider(spec.provider);\n if (!adapter.embedding) throw new Error(`createAI: provider \"${spec.provider}\" does not support embedding`);\n return adapter.embedding({ input: text, spec });\n },\n });\n },\n\n async transcribe(input: TranscribeInput): Promise<TranscribeResult> {\n input = transcribeInputSchema.parse(input);\n const audio = await resolveAudio(input.audio);\n return runCapability({\n primary: mergeUnguarded(DEFAULT_TRANSCRIBE_SPEC, input.override, \"routes by voice, not by model — the adapter never sends spec.model\"),\n fallback: input.fallback,\n capability: \"transcribe\",\n purpose: input.purpose,\n labels: input.labels,\n estIn: 0,\n estOut: 0,\n invoke: async (spec) => {\n const adapter = pickProvider(spec.provider);\n if (!adapter.transcribe) throw new Error(`createAI: provider \"${spec.provider}\" does not support transcribe`);\n const timestamps =\n input.timestamps === undefined\n ? undefined\n : Array.isArray(input.timestamps)\n ? input.timestamps\n : [input.timestamps];\n return adapter.transcribe({ audio, language: input.language, durationSec: input.durationSec, phrases: input.phrases, timestamps, spec });\n },\n });\n },\n\n batch: {\n async submit(input: { requests: BatchRequestItem[]; override?: TierSpec }): Promise<BatchJob> {\n const spec = withOverride(DEFAULT_BATCH_SPEC, input.override, \"batch\");\n const adapter = pickProvider(spec.provider);\n if (!adapter.batchSubmit) throw new Error(`createAI: provider \"${spec.provider}\" does not support batch`);\n return adapter.batchSubmit({ items: input.requests, spec });\n },\n async status(jobId: string, override?: TierSpec): Promise<BatchJob> {\n const spec = withOverride(DEFAULT_BATCH_SPEC, override, \"batch.status\");\n const adapter = pickProvider(spec.provider);\n if (!adapter.batchStatus) throw new Error(`createAI: provider \"${spec.provider}\" does not support batch`);\n return adapter.batchStatus({ jobId, spec });\n },\n async results(jobId: string, override?: TierSpec): Promise<BatchResultItem[]> {\n const spec = withOverride(DEFAULT_BATCH_SPEC, override, \"batch.results\");\n const adapter = pickProvider(spec.provider);\n if (!adapter.batchResults) throw new Error(`createAI: provider \"${spec.provider}\" does not support batch`);\n return adapter.batchResults({ jobId, spec });\n },\n },\n\n // Replaced below with the real prompt-contracts (needs the client itself).\n contracts: undefined as unknown as AiClient[\"contracts\"],\n };\n\n client.contracts = makeContracts(client);\n return client;\n}\n","// Stub provider adapters (F2.5). They satisfy ProviderAdapter so the client wires\n// up and resolves without real network calls. Real implementations land in F4\n// (anthropic/openai/gemini/openrouter/deepinfra) and F5.3 (fal image). The stub\n// usage carries zero tokens/cost — F3.1 fills real numbers in the live adapters.\nimport type {\n ProviderAdapter,\n ChatRequest,\n ChatResult,\n ImageRequest,\n ImageResult,\n EmbeddingRequest,\n EmbeddingResult,\n Usage,\n Capability,\n} from \"../types.js\";\n\nfunction stubUsage(\n provider: string,\n model: string,\n transport: \"http\" | \"subprocess\",\n capability: Capability,\n): Usage {\n return {\n provider,\n model,\n // Stubs answer no network, so there is no endpoint whose residency we could\n // report. \"unknown\" is the truthful reading — not a placeholder \"eu\".\n region: \"unknown\",\n transport,\n inputTokens: 0,\n outputTokens: 0,\n cacheReadTokens: 0,\n cacheCreationTokens: 0,\n costUsd: 0,\n latencyMs: 0,\n capability,\n // ts is supplied by the caller-side at real call time; stub uses a fixed marker\n // ('' avoids Date.now() — keeps the stub pure/deterministic for tests).\n ts: \"\",\n };\n}\n\nfunction lastUserText(req: ChatRequest): string {\n for (let i = req.messages.length - 1; i >= 0; i--) {\n const m = req.messages[i];\n if (m && m.role === \"user\") {\n return typeof m.content === \"string\"\n ? m.content\n : m.content.map((p) => (p.type === \"text\" ? p.text : \"[image]\")).join(\" \");\n }\n }\n return \"\";\n}\n\n/** Anthropic adapter stub (HTTP path). */\nexport const anthropicApiAdapter: ProviderAdapter = {\n name: \"anthropic\",\n async chat(req: ChatRequest): Promise<ChatResult> {\n return {\n text: `[stub:anthropic-api] ${lastUserText(req)}`,\n usage: stubUsage(\"anthropic\", req.spec.model, \"http\", \"chat\"),\n };\n },\n async vision(req: ChatRequest): Promise<ChatResult> {\n return {\n text: `[stub:anthropic-api:vision] ${lastUserText(req)}`,\n usage: stubUsage(\"anthropic\", req.spec.model, \"http\", \"vision\"),\n };\n },\n};\n\n/** Anthropic adapter stub (subprocess / `claude -p` path). */\nexport const anthropicSubprocessAdapter: ProviderAdapter = {\n name: \"anthropic\",\n async chat(req: ChatRequest): Promise<ChatResult> {\n const usage = stubUsage(\"anthropic\", req.spec.model, \"subprocess\", \"chat\");\n usage.subprocess = true;\n return { text: `[stub:anthropic-subprocess] ${lastUserText(req)}`, usage };\n },\n};\n\n/** Mistral adapter stub — covers the default text/vision tiers (F030: fast/smart/\n * powerful/vision/cheap all default to Mistral EU after the Anthropic phase-out). */\nexport const mistralStubAdapter: ProviderAdapter = {\n name: \"mistral\",\n async chat(req: ChatRequest): Promise<ChatResult> {\n return {\n text: `[stub:mistral] ${lastUserText(req)}`,\n usage: stubUsage(\"mistral\", req.spec.model, \"http\", \"chat\"),\n };\n },\n async vision(req: ChatRequest): Promise<ChatResult> {\n return {\n text: `[stub:mistral:vision] ${lastUserText(req)}`,\n usage: stubUsage(\"mistral\", req.spec.model, \"http\", \"vision\"),\n };\n },\n};\n\n/** OpenAI adapter stub — covers the embedding default tier + a chat fallback. */\nexport const openaiStubAdapter: ProviderAdapter = {\n name: \"openai\",\n async chat(req: ChatRequest): Promise<ChatResult> {\n return {\n text: `[stub:openai] ${lastUserText(req)}`,\n usage: stubUsage(\"openai\", req.spec.model, \"http\", \"chat\"),\n };\n },\n async embedding(req: EmbeddingRequest): Promise<EmbeddingResult> {\n return {\n vectors: req.input.map(() => [0, 0, 0]),\n usage: stubUsage(\"openai\", req.spec.model, \"http\", \"embedding\"),\n };\n },\n};\n\n/** fal.ai adapter stub — image generation (real one in fal.ts, F5.3). */\nexport const falStubAdapter: ProviderAdapter = {\n name: \"fal\",\n async image(req: ImageRequest): Promise<ImageResult> {\n return {\n url: `https://stub.fal/${encodeURIComponent(req.prompt).slice(0, 32)}.png`,\n usage: stubUsage(\"fal\", req.spec.model, \"http\", \"image\"),\n };\n },\n};\n\n/** Stub provider registry — deterministic, no network. Used by tests via\n * createAI({ providers: stubProviders }). The real default registry (registry.ts)\n * wires the live adapters. */\nexport const stubProviders: Record<string, ProviderAdapter> = {\n anthropic: anthropicApiAdapter,\n mistral: mistralStubAdapter,\n openai: openaiStubAdapter,\n fal: falStubAdapter,\n};\n","// F022 — async, off-the-hot-path availability refresh. The host runs this\n// out-of-band (a timer / at idle); it mutates the registry overlay so the next\n// synchronous resolveModel() sees overnight changes like the 2026-06-12 Fable /\n// Mythos suspension. NEVER on the resolve hot path. Never hard-fails the SDK:\n// a network/auth error keeps the curated defaults.\nimport { providerIds, setAvailability } from \"./registry.js\";\n\nexport interface RefreshOptions {\n /** Only \"anthropic\" is wired in v1 (where the incident hit). */\n provider?: \"anthropic\";\n /** Injectable for tests. Defaults to global fetch. */\n fetch?: typeof fetch;\n /** Defaults to process.env.ANTHROPIC_API_KEY. */\n apiKey?: string;\n /** Min ms between live fetches for a provider (default 1h). */\n ttlMs?: number;\n /** Injectable clock for deterministic TTL tests. Defaults to Date.now(). */\n now?: number;\n}\n\nexport interface RefreshResult {\n refreshed: boolean;\n checked: number;\n markedUnavailable: string[];\n}\n\nconst NOT_REFRESHED: RefreshResult = { refreshed: false, checked: 0, markedUnavailable: [] };\nconst DEFAULT_TTL_MS = 60 * 60 * 1000; // 1h\nconst ANTHROPIC_MODELS_URL = \"https://api.anthropic.com/v1/models\";\n\n/** Last successful live fetch per provider, for TTL short-circuiting. */\nconst lastRefreshAt = new Map<string, number>();\n\n/** Reset the TTL bookkeeping. For tests. */\nexport function resetRefreshState(): void {\n lastRefreshAt.clear();\n}\n\ninterface AnthropicModelsResponse {\n data?: { id?: string }[];\n}\n\n/**\n * Reconcile tracked models against the provider's live list. For Anthropic:\n * GET /v1/models — any tracked anthropic id NOT in the live set is marked\n * unavailable; ids present are (re)marked available. TTL-cached; a fetch within\n * the window is a no-op. Returns { refreshed:false } on any error or missing key.\n */\nexport async function refreshAvailability(opts: RefreshOptions = {}): Promise<RefreshResult> {\n const provider = opts.provider ?? \"anthropic\";\n if (provider !== \"anthropic\") return NOT_REFRESHED;\n\n const ttl = opts.ttlMs ?? DEFAULT_TTL_MS;\n const now = opts.now ?? Date.now();\n const last = lastRefreshAt.get(provider);\n if (last !== undefined && now - last < ttl) return NOT_REFRESHED; // within TTL → skip\n\n const apiKey = opts.apiKey ?? process.env.ANTHROPIC_API_KEY;\n if (!apiKey) return NOT_REFRESHED;\n\n const f = opts.fetch ?? fetch;\n let liveIds: Set<string>;\n try {\n const res = await f(ANTHROPIC_MODELS_URL, {\n headers: { \"x-api-key\": apiKey, \"anthropic-version\": \"2023-06-01\", accept: \"application/json\" },\n });\n if (!res.ok) return NOT_REFRESHED;\n const json = (await res.json()) as AnthropicModelsResponse;\n liveIds = new Set((json.data ?? []).map((m) => m.id).filter((id): id is string => typeof id === \"string\"));\n } catch {\n return NOT_REFRESHED; // network error → keep defaults\n }\n\n // A models list that came back empty is almost certainly an API hiccup, not\n // \"every model is dead\" — don't suspend the whole provider on it.\n if (liveIds.size === 0) return NOT_REFRESHED;\n\n const tracked = providerIds(provider);\n const markedUnavailable: string[] = [];\n for (const id of tracked) {\n const live = liveIds.has(id);\n if (live) {\n setAvailability(id, true);\n } else {\n setAvailability(id, false, \"not in provider model list (live refresh)\");\n markedUnavailable.push(id);\n }\n }\n\n lastRefreshAt.set(provider, now);\n return { refreshed: true, checked: tracked.length, markedUnavailable };\n}\n","// Persistent BudgetStore backed by bun:sqlite (F7.1). The rolling total survives\n// process restarts and is shared by every process pointing at the same file, so\n// a budget ceiling is a real production guard — not a per-process counter that\n// resets on deploy. bun:sqlite is imported lazily (Node-safe import, like sqliteSink).\nimport type { BudgetStore } from \"../types.js\";\n\nexport interface SqliteBudgetStoreConfig {\n /** SQLite file path, e.g. \"./ai-budget.db\". */\n dbPath: string;\n /** Window/bucket key — use e.g. a day-stamp for a daily budget. Default \"default\". */\n key?: string;\n}\n\nexport function sqliteBudgetStore(config: SqliteBudgetStoreConfig): BudgetStore {\n const key = config.key ?? \"default\";\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let ready: Promise<any> | null = null;\n const open = async () => {\n const { Database } = await import(\"bun:sqlite\");\n const db = new Database(config.dbPath);\n db.run(\n `CREATE TABLE IF NOT EXISTS budget_spend (key TEXT PRIMARY KEY, spent_usd REAL NOT NULL DEFAULT 0)`,\n );\n return db;\n };\n\n return {\n async getSpent(): Promise<number> {\n const db = await (ready ??= open());\n const row = db\n .query(`SELECT spent_usd FROM budget_spend WHERE key = $key`)\n .get({ $key: key }) as { spent_usd: number } | null;\n return row?.spent_usd ?? 0;\n },\n async addSpent(usd: number): Promise<void> {\n const db = await (ready ??= open());\n db.run(\n `INSERT INTO budget_spend (key, spent_usd) VALUES ($key, $usd)\n ON CONFLICT(key) DO UPDATE SET spent_usd = spent_usd + $usd`,\n { $key: key, $usd: usd },\n );\n },\n };\n}\n","import type { CostSink } from \"../../types.js\";\n\n/** A sink that does nothing. The default when no costSink is configured. */\nexport const noopSink: CostSink = {\n record() {\n // intentionally empty\n },\n};\n","import type { CostSink, Usage } from \"../../types.js\";\n\n/** Fan a Usage out to several sinks. Uses allSettled so one failing sink never\n * prevents the others from recording (and never propagates to the caller). */\nexport function multiSink(sinks: CostSink[]): CostSink {\n return {\n async record(usage: Usage): Promise<void> {\n // async wrapper turns a synchronous throw in s.record into a rejected\n // promise, so allSettled isolates it (a sync throw would otherwise escape\n // the .map before allSettled ran).\n await Promise.allSettled(sinks.map(async (s) => s.record(usage)));\n },\n };\n}\n","// discordSink — posts a per-call cost embed to a Discord webhook. Secondary sink\n// (upmetricsSink is canonical); handy for repos not wired to Upmetrics or for an\n// at-a-glance spend feed. Plain fetch, no Discord SDK. Errors never propagate.\nimport type { CostSink, Usage } from \"../../types.js\";\n\nexport interface DiscordSinkConfig {\n webhookUrl: string;\n /** Skip posting paid calls below this USD threshold (anti-spam). Subprocess\n * (Max-plan free) calls always post so the \"free\" feed stays visible.\n * Default 0 → post everything. */\n minUsd?: number;\n fetch?: typeof fetch;\n onError?: (err: unknown) => void;\n}\n\nexport function discordSink(config: DiscordSinkConfig): CostSink {\n const doFetch = config.fetch ?? fetch;\n const minUsd = config.minUsd ?? 0;\n\n return {\n async record(usage: Usage): Promise<void> {\n try {\n // Skip cheap PAID calls; always show subprocess (free) calls.\n if (!usage.subprocess && usage.costUsd < minUsd) return;\n\n const costLabel = usage.subprocess\n ? \"Max plan (free)\"\n : `$${usage.costUsd.toFixed(6)}`;\n\n const embed = {\n title: `AI call — ${usage.capability}`,\n fields: [\n { name: \"Provider\", value: usage.provider, inline: true },\n { name: \"Model\", value: usage.model, inline: true },\n { name: \"Transport\", value: usage.transport, inline: true },\n { name: \"Cost\", value: costLabel, inline: true },\n {\n name: \"Tokens\",\n value: `${usage.inputTokens} in / ${usage.outputTokens} out`,\n inline: true,\n },\n { name: \"Latency\", value: `${usage.latencyMs} ms`, inline: true },\n ],\n timestamp: usage.ts || new Date().toISOString(),\n };\n\n const res = await doFetch(config.webhookUrl, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ embeds: [embed] }),\n });\n if (!res.ok) {\n config.onError?.(new Error(`discordSink: webhook returned ${res.status}`));\n }\n } catch (err) {\n config.onError?.(err);\n }\n },\n };\n}\n","// sqliteSink — persists every Usage to a local bun:sqlite DB. Secondary/offline\n// sink (upmetricsSink is canonical). No npm dependency — bun:sqlite is built in.\n//\n// IMPORTANT: bun:sqlite is imported LAZILY (dynamic import on first use), not at\n// module top level. A static `import \"bun:sqlite\"` would leak into the package\n// entry and crash every Node consumer (`ERR_UNSUPPORTED_ESM_URL_SCHEME`). With\n// the lazy import, importing @broberg/ai-sdk works everywhere; bun:sqlite only\n// loads when sqliteSink/getCostSummary actually run (Bun only).\nimport type { CostSink, Usage } from \"../../types.js\";\n\nexport interface SqliteSinkConfig {\n /** Path to the SQLite file, e.g. \"./ai-cost.db\" (or \":memory:\"). */\n dbPath: string;\n}\n\nconst CREATE_TABLE = `\nCREATE TABLE IF NOT EXISTS ai_usage (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n ts TEXT NOT NULL,\n provider TEXT NOT NULL,\n model TEXT NOT NULL,\n tier TEXT,\n transport TEXT NOT NULL,\n capability TEXT NOT NULL,\n region TEXT NOT NULL DEFAULT 'unknown',\n purpose TEXT,\n input_tokens INTEGER NOT NULL,\n output_tokens INTEGER NOT NULL,\n cache_read_tokens INTEGER NOT NULL,\n cache_creation_tokens INTEGER NOT NULL,\n cost_usd REAL NOT NULL,\n latency_ms INTEGER NOT NULL,\n subprocess INTEGER NOT NULL DEFAULT 0\n)`;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nasync function openDb(dbPath: string, readonly = false): Promise<any> {\n const { Database } = await import(\"bun:sqlite\");\n return new Database(dbPath, readonly ? { readonly: true } : undefined);\n}\n\nexport function sqliteSink(config: SqliteSinkConfig): CostSink {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let ready: Promise<any> | null = null;\n const init = async () => {\n const db = await openDb(config.dbPath);\n db.run(CREATE_TABLE);\n // CREATE TABLE IF NOT EXISTS does NOTHING to a table that already exists, so a\n // consumer with a db from an earlier version keeps the old columns and every\n // INSERT would fail on the new one. The DEFAULT means existing rows read back as\n // 'unknown' — which is the truthful answer for a call made before we recorded it,\n // not a placeholder.\n const cols = db.query(`PRAGMA table_info(ai_usage)`).all() as { name: string }[];\n if (!cols.some((c) => c.name === \"region\")) {\n db.run(`ALTER TABLE ai_usage ADD COLUMN region TEXT NOT NULL DEFAULT 'unknown'`);\n }\n const insert = db.prepare(\n `INSERT INTO ai_usage\n (ts, provider, model, tier, transport, capability, region, purpose,\n input_tokens, output_tokens, cache_read_tokens, cache_creation_tokens,\n cost_usd, latency_ms, subprocess)\n VALUES ($ts, $provider, $model, $tier, $transport, $capability, $region, $purpose,\n $input, $output, $cacheRead, $cacheCreation, $cost, $latency, $subprocess)`,\n );\n return insert;\n };\n\n return {\n async record(usage: Usage): Promise<void> {\n const insert = await (ready ??= init());\n insert.run({\n $ts: usage.ts || new Date().toISOString(),\n $provider: usage.provider,\n $model: usage.model,\n $tier: usage.tier ?? null,\n $transport: usage.transport,\n $capability: usage.capability,\n $region: usage.region,\n $purpose: usage.purpose ?? null,\n $input: usage.inputTokens,\n $output: usage.outputTokens,\n $cacheRead: usage.cacheReadTokens,\n $cacheCreation: usage.cacheCreationTokens,\n $cost: usage.costUsd,\n $latency: usage.latencyMs,\n $subprocess: usage.subprocess ? 1 : 0,\n });\n },\n };\n}\n\nexport interface CostSummary {\n totalUsd: number;\n byProvider: Record<string, number>;\n byCapability: Record<string, number>;\n}\n\n/** Aggregate the recorded spend from a sqliteSink DB. Creates the table if the\n * DB has never been written to, so an empty DB summarises cleanly to 0. */\nexport async function getCostSummary(dbPath: string): Promise<CostSummary> {\n const db = await openDb(dbPath);\n db.run(CREATE_TABLE);\n const total = db\n .query(`SELECT SUM(cost_usd) AS total FROM ai_usage`)\n .get() as { total: number | null };\n const byProvider: Record<string, number> = {};\n for (const row of db\n .query(`SELECT provider, SUM(cost_usd) AS sum FROM ai_usage GROUP BY provider`)\n .all() as { provider: string; sum: number }[]) {\n byProvider[row.provider] = row.sum;\n }\n const byCapability: Record<string, number> = {};\n for (const row of db\n .query(`SELECT capability, SUM(cost_usd) AS sum FROM ai_usage GROUP BY capability`)\n .all() as { capability: string; sum: number }[]) {\n byCapability[row.capability] = row.sum;\n }\n return { totalUsd: total?.total ?? 0, byProvider, byCapability };\n}\n","// upmetricsCostClient — the cost READ-back side, companion to upmetricsSink (the\n// write side). Upmetrics owns cost AGGREGATION (it already rolls up agent_runs):\n// this is a thin, browser-clean wrapper over its public cost read-API\n// (upmetrics/docs/COST-API.md, F014) so a consuming app reads its OWN accumulated\n// cost from the canonical source instead of re-aggregating locally.\n//\n// Money is integer micro-USD ($1 = 1_000_000); Upmetrics rounds once at the\n// response boundary so sub-cent calls aren't lost. Pure fetch, zero new deps, no\n// bun:sqlite import → safe to import from a browser/Vite build.\n\n/** Thrown when the cost read-API rejects (e.g. 401 invalid_api_key) or is unreachable. */\nexport class UpmetricsCostError extends Error {\n readonly status?: number;\n readonly code?: string;\n constructor(message: string, opts?: { status?: number; code?: string }) {\n super(message);\n this.name = \"UpmetricsCostError\";\n this.status = opts?.status;\n this.code = opts?.code;\n }\n}\n\nexport interface UpmetricsCostClientConfig {\n /** Read-API base URL, e.g. https://upmetrics.org */\n baseUrl: string;\n /** Per-project api_key (uk_…) — sent as X-Upmetrics-Key; resolves to your own project only. */\n apiKey: string;\n /** Injectable fetch for testing; defaults to global fetch. */\n fetch?: typeof fetch;\n}\n\n/** Shared filter surface for summary + timeseries (mirrors COST-API.md query params). */\nexport interface CostQuery {\n /** Relative window; ignored when from/to are given. */\n window?: \"day\" | \"week\" | \"month\";\n /** Explicit window start (ISO-8601 or epoch-ms) — overrides `window`. */\n from?: string | number;\n /** Explicit window end (ISO-8601 or epoch-ms) — overrides `window`. */\n to?: string | number;\n provider?: string;\n model?: string;\n tier?: string;\n /** Filter to one consumer (the sink's agent_name). */\n agentName?: string;\n transport?: \"http\" | \"subprocess\";\n /** Tag filters → `tag.<key>=<value>` (e.g. { tenantId: \"sanne\" }). */\n tags?: Record<string, string>;\n}\n\nexport interface CostSummaryQuery extends CostQuery {\n /** Break the total down per distinct value of this tag key (the per-tenant view). */\n groupBy?: string;\n}\n\nexport interface CostTimeseriesQuery extends CostQuery {\n /** Bucket granularity (default \"day\"). */\n bucket?: \"day\" | \"hour\";\n}\n\n/** One breakdown row, ordered by cost desc. `tier`/`capability` fall back to \"(none)\". */\nexport interface UpmetricsCostRow {\n key: string;\n micro_usd: number;\n input_tokens: number;\n output_tokens: number;\n run_count: number;\n}\n\nexport interface UpmetricsCostSummary {\n generated_at: string;\n window: { from: string; to: string };\n total_micro_usd: number;\n input_tokens: number;\n output_tokens: number;\n cache_read_tokens: number;\n cache_creation_tokens: number;\n run_count: number;\n metered: { metered_micro_usd: number; free_run_count: number };\n by_provider: UpmetricsCostRow[];\n by_model: UpmetricsCostRow[];\n by_tier: UpmetricsCostRow[];\n by_capability: UpmetricsCostRow[];\n /** Present only when `groupBy` was requested. */\n group_by?: string;\n by_group?: UpmetricsCostRow[];\n}\n\nexport interface UpmetricsCostTimeseries {\n generated_at: string;\n bucket: \"day\" | \"hour\";\n window: { from: string; to: string };\n /** Only non-zero buckets are returned — pad missing buckets yourself. */\n points: Array<{\n ts: string;\n micro_usd: number;\n input_tokens: number;\n output_tokens: number;\n run_count: number;\n }>;\n}\n\n/** Convert integer micro-USD to a USD float for display. `$1 = 1_000_000`. */\nexport const usdFromMicro = (microUsd: number): number => microUsd / 1_000_000;\n\nfunction buildQuery(q: CostQuery & { groupBy?: string; bucket?: string }): string {\n const p = new URLSearchParams();\n if (q.bucket) p.set(\"bucket\", q.bucket);\n if (q.from !== undefined) p.set(\"from\", String(q.from));\n if (q.to !== undefined) p.set(\"to\", String(q.to));\n // `window` is ignored server-side when from/to are present; only send it otherwise.\n if (q.window && q.from === undefined && q.to === undefined) p.set(\"window\", q.window);\n if (q.provider) p.set(\"provider\", q.provider);\n if (q.model) p.set(\"model\", q.model);\n if (q.tier) p.set(\"tier\", q.tier);\n if (q.agentName) p.set(\"agent_name\", q.agentName);\n if (q.transport) p.set(\"transport\", q.transport);\n if (q.groupBy) p.set(\"groupBy\", q.groupBy);\n for (const [k, v] of Object.entries(q.tags ?? {})) p.set(`tag.${k}`, v);\n const s = p.toString();\n return s ? `?${s}` : \"\";\n}\n\nexport function upmetricsCostClient(config: UpmetricsCostClientConfig): {\n summary(query?: CostSummaryQuery): Promise<UpmetricsCostSummary>;\n timeseries(query?: CostTimeseriesQuery): Promise<UpmetricsCostTimeseries>;\n} {\n const doFetch = config.fetch ?? fetch;\n const base = config.baseUrl.replace(/\\/$/, \"\");\n\n async function get<T>(path: string, query: string): Promise<T> {\n let res: Response;\n try {\n res = await doFetch(`${base}${path}${query}`, {\n method: \"GET\",\n headers: { \"X-Upmetrics-Key\": config.apiKey },\n });\n } catch (err) {\n throw new UpmetricsCostError(\n `upmetricsCostClient: ${path} unreachable: ${(err as Error)?.message ?? String(err)}`,\n );\n }\n if (!res.ok) {\n let code: string | undefined;\n const text = await res.text().catch(() => \"\");\n try {\n code = (JSON.parse(text) as { error?: string }).error;\n } catch {\n /* non-JSON error body */\n }\n throw new UpmetricsCostError(\n `upmetricsCostClient: ${path} returned ${res.status}${code ? ` (${code})` : \"\"}`,\n { status: res.status, code },\n );\n }\n return (await res.json()) as T;\n }\n\n return {\n summary(query: CostSummaryQuery = {}): Promise<UpmetricsCostSummary> {\n return get<UpmetricsCostSummary>(\"/api/cost/summary\", buildQuery(query));\n },\n timeseries(query: CostTimeseriesQuery = {}): Promise<UpmetricsCostTimeseries> {\n return get<UpmetricsCostTimeseries>(\"/api/cost/timeseries\", buildQuery(query));\n },\n };\n}\n"],"mappings":"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","names":["url","mimeType","data","listVoices","DEFAULT_REGION","EU_BASE","sleep","res"]}
|