{"version":3,"file":"index.mjs","names":[],"sources":["../../gateway-core/src/errors.ts","../../gateway-core/src/gateway-fetch.ts","../../gateway-core/src/gateway-providers.ts","../../gateway-core/src/resumable-stream.ts","../../gateway-core/src/workers-ai.ts","../src/providers.ts","../src/index.ts"],"sourcesContent":["/**\n * Error type shared by the gateway delegate and the resumable-stream engine.\n *\n * Lives in `@cloudflare/gateway-core` because the resume engine (here) and the\n * delegate (in `workers-ai-provider`) both throw it. Note: since each consumer\n * inlines this source into its own bundle, `instanceof GatewayDelegateError`\n * only matches within a single package's bundle — match on `.name`/`.kind`\n * across package boundaries.\n */\nexport type GatewayDelegateErrorKind = \"config\" | \"dispatch\" | \"provider\" | \"resume-expired\";\n\nexport class GatewayDelegateError extends Error {\n\treadonly kind: GatewayDelegateErrorKind;\n\toverride readonly cause?: unknown;\n\n\tconstructor(kind: GatewayDelegateErrorKind, message: string, cause?: unknown) {\n\t\tsuper(message);\n\t\tthis.name = \"GatewayDelegateError\";\n\t\tthis.kind = kind;\n\t\tthis.cause = cause;\n\t}\n}\n","/**\n * Shared AI Gateway dispatch primitives: the `cf-aig-*` header builder, the\n * provider-key / hop-by-hop header strip, body decoding, and universal-endpoint\n * entry construction.\n *\n * These are consumed by `workers-ai-provider` (the gateway-path `createGatewayFetch`\n * and the delegate's `makeGatewayFetch`/`makeRunFetch`) and by `@cloudflare/tanstack-ai`\n * (its REST/binding `createGatewayFetch`), so there's a single place that knows how\n * to translate caching/metadata/log options into gateway headers.\n */\n\n/** Metadata values the gateway accepts (`bigint` is serialized to a string). */\nexport type GatewayMetadata = Record<string, number | string | boolean | null | bigint>;\n\n/** JSON-encode metadata for the `cf-aig-metadata` header (`bigint` → string). */\nexport function serializeMetadata(metadata: GatewayMetadata): string {\n\treturn JSON.stringify(metadata, (_k, v) => (typeof v === \"bigint\" ? v.toString() : v));\n}\n\n/** Hop-by-hop headers that must never be forwarded to the gateway. */\nexport const STRIP_HEADERS_BASE: readonly string[] = [\"content-length\", \"host\"];\n\n/** Normalize any `HeadersInit` shape into a plain object. */\nexport function headersToObject(h: HeadersInit | undefined): Record<string, string> {\n\tconst out: Record<string, string> = {};\n\tif (!h) return out;\n\tif (h instanceof Headers) {\n\t\tfor (const [k, v] of h) out[k] = v;\n\t} else if (Array.isArray(h)) {\n\t\tfor (const [k, v] of h) out[k] = v;\n\t} else {\n\t\tObject.assign(out, h);\n\t}\n\treturn out;\n}\n\n/** Best-effort decode of a request body to text for re-parsing as JSON. */\nexport function asText(body: BodyInit | null | undefined): string {\n\tif (typeof body === \"string\") return body;\n\tif (body instanceof Uint8Array) return new TextDecoder().decode(body);\n\tif (body instanceof ArrayBuffer) return new TextDecoder().decode(body);\n\treturn \"{}\";\n}\n\n/** Retry controls that map onto the `cf-aig-*` retry headers. */\nexport interface GatewayRetryOptions {\n\t/** Max retry attempts → `cf-aig-max-attempts`. */\n\tmaxAttempts?: number;\n\t/** Delay between retries (ms) → `cf-aig-retry-delay`. */\n\tretryDelayMs?: number;\n\t/** Backoff strategy → `cf-aig-backoff`. */\n\tbackoff?: \"constant\" | \"linear\" | \"exponential\";\n}\n\n/**\n * Gateway request controls that map onto `cf-aig-*` request headers. Mirrors the\n * binding's `GatewayOptions` (the run path forwards those to `binding.run`) so the\n * gateway path reaches parity, plus the universal-endpoint-only `byokAlias`/`zdr`.\n */\nexport interface GatewayCacheOptions {\n\t/** Gateway-side response cache TTL (seconds) → `cf-aig-cache-ttl`. */\n\tcacheTtl?: number;\n\t/** Bypass the gateway cache → `cf-aig-skip-cache`. */\n\tskipCache?: boolean;\n\t/** Custom cache key → `cf-aig-cache-key`. */\n\tcacheKey?: string;\n\t/** Arbitrary log metadata → `cf-aig-metadata` (JSON). */\n\tmetadata?: GatewayMetadata;\n\t/** Toggle gateway logging → `cf-aig-collect-log`. */\n\tcollectLog?: boolean;\n\t/** Trace id for this event → `cf-aig-event-id`. */\n\teventId?: string;\n\t/** Upstream provider timeout (ms) → `cf-aig-request-timeout`. */\n\trequestTimeoutMs?: number;\n\t/** Retry controls → `cf-aig-max-attempts` / `cf-aig-retry-delay` / `cf-aig-backoff`. */\n\tretries?: GatewayRetryOptions;\n\t/**\n\t * BYOK stored-key alias to authenticate with → `cf-aig-byok-alias`. Selects a\n\t * non-`default` key configured for the provider on the gateway.\n\t */\n\tbyokAlias?: string;\n\t/**\n\t * Per-request Zero Data Retention override (Unified Billing only) → `cf-aig-zdr`.\n\t * `true` forces ZDR-capable upstreams; `false` disables it for this request.\n\t */\n\tzdr?: boolean;\n}\n\n/**\n * Set the `cf-aig-*` cache/log/request headers on `headers` for every option\n * that is defined. Mutates `headers` in place (callers pass the entry's header\n * object).\n */\nexport function applyGatewayCacheHeaders(\n\theaders: Record<string, string>,\n\topts: GatewayCacheOptions,\n): void {\n\tif (opts.cacheTtl !== undefined) headers[\"cf-aig-cache-ttl\"] = String(opts.cacheTtl);\n\tif (opts.skipCache) headers[\"cf-aig-skip-cache\"] = \"true\";\n\tif (opts.cacheKey !== undefined) headers[\"cf-aig-cache-key\"] = opts.cacheKey;\n\tif (opts.metadata) headers[\"cf-aig-metadata\"] = serializeMetadata(opts.metadata);\n\tif (opts.collectLog !== undefined) headers[\"cf-aig-collect-log\"] = String(opts.collectLog);\n\tif (opts.eventId !== undefined) headers[\"cf-aig-event-id\"] = opts.eventId;\n\tif (opts.requestTimeoutMs !== undefined)\n\t\theaders[\"cf-aig-request-timeout\"] = String(opts.requestTimeoutMs);\n\tif (opts.byokAlias !== undefined) headers[\"cf-aig-byok-alias\"] = opts.byokAlias;\n\tif (opts.zdr !== undefined) headers[\"cf-aig-zdr\"] = String(opts.zdr);\n\tif (opts.retries) {\n\t\tconst { maxAttempts, retryDelayMs, backoff } = opts.retries;\n\t\tif (maxAttempts !== undefined) headers[\"cf-aig-max-attempts\"] = String(maxAttempts);\n\t\tif (retryDelayMs !== undefined) headers[\"cf-aig-retry-delay\"] = String(retryDelayMs);\n\t\tif (backoff !== undefined) headers[\"cf-aig-backoff\"] = backoff;\n\t}\n}\n\n/** A single AI Gateway universal-endpoint request entry. */\nexport interface GatewayEntry {\n\tprovider: string;\n\tendpoint: string;\n\theaders: Record<string, string>;\n\tquery: Record<string, unknown>;\n}\n\nexport interface BuildGatewayEntryParams {\n\t/** Gateway provider id (e.g. `\"openai\"`, `\"google-vertex-ai\"`). */\n\tproviderId: string;\n\t/** Already host-stripped endpoint path (+ query). */\n\tendpoint: string;\n\t/** Incoming request headers from the wrapped provider SDK. */\n\tinitHeaders: HeadersInit | undefined;\n\t/** Parsed request body, forwarded verbatim as `query`. */\n\tbody: Record<string, unknown>;\n\t/**\n\t * Provider auth header names to strip (e.g. the registry `authHeaders`) so the\n\t * gateway's stored key / unified billing authenticates upstream. Omit for BYOK.\n\t */\n\tstripAuthHeaders?: readonly string[];\n\t/** Extra headers added after stripping. */\n\textraHeaders?: Record<string, string>;\n\t/** Cache / log controls. */\n\tcache?: GatewayCacheOptions;\n}\n\n/**\n * Assemble a single gateway entry: strip hop-by-hop + provider-auth headers,\n * layer on `extraHeaders` and `cf-aig-*` cache headers, and attach the body as\n * `query`. Endpoint derivation stays with the caller because the gateway-path\n * (registry host-strip) and the REST path (`/v1/` strip) differ.\n */\nexport function buildGatewayEntry(params: BuildGatewayEntryParams): GatewayEntry {\n\tconst strip = new Set<string>(STRIP_HEADERS_BASE);\n\tif (params.stripAuthHeaders) {\n\t\tfor (const h of params.stripAuthHeaders) strip.add(h.toLowerCase());\n\t}\n\n\tconst headers: Record<string, string> = {};\n\tfor (const [k, v] of Object.entries(headersToObject(params.initHeaders))) {\n\t\tif (!strip.has(k.toLowerCase())) headers[k] = v;\n\t}\n\tif (params.extraHeaders) Object.assign(headers, params.extraHeaders);\n\tif (params.cache) applyGatewayCacheHeaders(headers, params.cache);\n\n\treturn {\n\t\tprovider: params.providerId,\n\t\tendpoint: params.endpoint,\n\t\theaders,\n\t\tquery: params.body,\n\t};\n}\n","/**\n * Registry of Cloudflare AI Gateway providers.\n *\n * One table drives both delegate surfaces:\n *\n *   - **Slug delegate** (`wai(\"openai/gpt-5\")`): `resolverKey` is the slug prefix\n *     the user types. `runCatalog` providers dispatch through the resumable run\n *     path (`env.AI.run`, unified billing, `cf-aig-run-id`); the rest go through\n *     the gateway path (`env.AI.gateway().run`, BYOK, no resume). `wireFormat`\n *     selects the built-in `@ai-sdk/*` parser; absent ⇒ the provider is reachable\n *     only via the bring-your-own-provider wrapper (it isn't chat/completions\n *     shaped, e.g. audio/image providers).\n *   - **Bring-your-own-provider** (`createGatewayProvider`): `hostPattern` +\n *     `transformEndpoint` map a wrapped provider's request URL to the gateway\n *     `provider` id + endpoint path.\n *\n * Slugs mirror the AI Gateway provider directory\n * (developers.cloudflare.com/ai-gateway/usage/providers/); endpoint transforms\n * mirror `ai-gateway-provider`'s provider table. `runCatalog` / `billing` flags\n * follow the documented unified-billing list (OpenAI, Anthropic, Google AI\n * Studio, Google Vertex, xAI/Grok, Groq) and are otherwise conservative — the\n * e2e suite confirms them live, since resume is undocumented upstream.\n */\n\n/** Response wire format the slug delegate can parse with a built-in `@ai-sdk/*` provider. */\nexport type WireFormat = \"openai\" | \"anthropic\" | \"google\";\n\n/** How a provider is billed + keyed when reached through the gateway. */\nexport type Billing = \"unified\" | \"byok\";\n\nexport interface GatewayProviderInfo {\n\t/**\n\t * Slug prefix the user types in `wai(\"<resolverKey>/<model>\")`. For\n\t * `runCatalog` providers this is also the run-catalog author (so\n\t * `env.AI.run(\"<resolverKey>/<model>\")` resolves).\n\t */\n\tresolverKey: string;\n\t/** Provider id for the gateway universal endpoint (`env.AI.gateway().run([{ provider }])`). */\n\tgatewayProviderId: string;\n\t/**\n\t * Built-in parser wire format. `openai` covers the whole OpenAI-compatible\n\t * long tail (deepseek, grok, groq, mistral, perplexity, …). Absent ⇒ reachable\n\t * only via the bring-your-own-provider wrapper (provider-native, non-chat, or a\n\t * gateway-path URL shape we don't reproduce reliably from the slug delegate).\n\t */\n\twireFormat?: WireFormat;\n\t/**\n\t * Wire format the unified-billing **run path** (`env.AI.run`) emits for this\n\t * provider — which is NOT always the provider's native format. Cloudflare's\n\t * unified catalog normalizes most providers to OpenAI chat-completions (so\n\t * `google` is parsed with the `openai` plugin on the run path), but passes\n\t * **Anthropic through natively** (`content[].text`, native tool shape), so\n\t * anthropic must be parsed with the `anthropic` plugin. Defaults to `\"openai\"`\n\t * for run-catalog providers when omitted. Only meaningful when `runCatalog`.\n\t */\n\trunWireFormat?: WireFormat;\n\t/**\n\t * Base URL the wire-format builder should target so the request URL it\n\t * generates host-strips (via {@link transformEndpoint}) to the provider's\n\t * gateway-native endpoint. Omit to use the `@ai-sdk` provider's default (the\n\t * provider's own host — correct for `openai`/`anthropic`/`google`). Required\n\t * for OpenAI-wire providers that share the `openai` plugin but live on a\n\t * different host (deepseek, grok, groq, mistral, perplexity, …).\n\t */\n\tbaseURL?: string;\n\t/** On the unified-billing resumable run catalog (`env.AI.run`, `cf-aig-run-id`). */\n\trunCatalog: boolean;\n\t/**\n\t * Whether the provider has a gateway path (`env.AI.gateway().run`). `false` ⇒\n\t * **run-path only**: the provider is on the unified run catalog but is not a\n\t * native gateway provider, so caching, server-side fallback, and\n\t * `transport: \"gateway\"` are unavailable and the delegate rejects them with a\n\t * clear error (rather than failing upstream). Defaults to `true`.\n\t */\n\tgatewayPath?: boolean;\n\t/** Billing model when reached through the gateway. */\n\tbilling: Billing;\n\t/** Header(s) carrying the upstream provider key (stripped on the gateway path unless BYOK-forwarded). */\n\tauthHeaders: string[];\n\t/** Host matcher for bring-your-own-provider URL detection. */\n\thostPattern?: RegExp;\n\t/** Strip the provider host, leaving the gateway endpoint path (+ query). */\n\ttransformEndpoint?: (url: string) => string;\n}\n\n/** Strip a leading `https://<host>/` prefix, leaving the endpoint path + query. */\nfunction hostStrip(pattern: RegExp): (url: string) => string {\n\treturn (url: string) => url.replace(pattern, \"\");\n}\n\nconst OPENAI_HOST = /^https:\\/\\/api\\.openai\\.com\\//;\nconst ANTHROPIC_HOST = /^https:\\/\\/api\\.anthropic\\.com\\//;\nconst GOOGLE_HOST = /^https:\\/\\/generativelanguage\\.googleapis\\.com\\//;\nconst VERTEX_HOST = /^https:\\/\\/(?:[a-z0-9-]+-)?aiplatform\\.googleapis\\.com\\//;\nconst XAI_HOST = /^https:\\/\\/api\\.x\\.ai\\//;\nconst GROQ_HOST = /^https:\\/\\/api\\.groq\\.com\\/openai\\/v1\\//;\nconst DEEPSEEK_HOST = /^https:\\/\\/api\\.deepseek\\.com\\//;\nconst MISTRAL_HOST = /^https:\\/\\/api\\.mistral\\.ai\\//;\nconst PERPLEXITY_HOST = /^https:\\/\\/api\\.perplexity\\.ai\\//;\nconst CEREBRAS_HOST = /^https:\\/\\/api\\.cerebras\\.ai\\//;\nconst OPENROUTER_HOST = /^https:\\/\\/openrouter\\.ai\\/api\\//;\nconst FIREWORKS_HOST = /^https:\\/\\/api\\.fireworks\\.ai\\/inference\\/v1\\//;\nconst COHERE_HOST = /^https:\\/\\/api\\.cohere\\.(?:com|ai)\\//;\nconst REPLICATE_HOST = /^https:\\/\\/api\\.replicate\\.com\\//;\nconst HUGGINGFACE_HOST = /^https:\\/\\/api-inference\\.huggingface\\.co\\/models\\//;\nconst CARTESIA_HOST = /^https:\\/\\/api\\.cartesia\\.ai\\//;\nconst FAL_HOST = /^https:\\/\\/fal\\.run\\//;\nconst IDEOGRAM_HOST = /^https:\\/\\/api\\.ideogram\\.ai\\//;\nconst DEEPGRAM_HOST = /^https:\\/\\/api\\.deepgram\\.com\\//;\nconst ELEVENLABS_HOST = /^https:\\/\\/api\\.elevenlabs\\.io\\//;\nconst GROK_KEY = \"grok\";\n\n// Bedrock's URL carries the AWS region, which the gateway endpoint preserves as\n// `bedrock-runtime/<region>/<rest>` (mirrors ai-gateway-provider).\nconst BEDROCK_HOST = /^https:\\/\\/bedrock-runtime\\.(?<region>[^.]+)\\.amazonaws\\.com\\//;\nfunction bedrockTransform(url: string): string {\n\tconst m = url.match(\n\t\t/^https:\\/\\/bedrock-runtime\\.(?<region>[^.]+)\\.amazonaws\\.com\\/(?<rest>.*)$/,\n\t);\n\tif (!m?.groups) return url;\n\tconst { region, rest } = m.groups;\n\tif (!region || rest === undefined) return url;\n\treturn `bedrock-runtime/${region}/${rest}`;\n}\n\n// Azure's URL carries the resource + deployment, so it needs a bespoke transform\n// (mirrors ai-gateway-provider). Only used for bring-your-own-provider detection.\nconst AZURE_HOST =\n\t/^https:\\/\\/(?<resource>[^.]+)\\.openai\\.azure\\.com\\/openai\\/deployments\\/(?<deployment>[^/]+)\\/(?<rest>.*)$/;\nfunction azureTransform(url: string): string {\n\tconst m = url.match(AZURE_HOST);\n\tif (!m?.groups) return url;\n\tconst { resource, deployment, rest } = m.groups;\n\tif (!resource || !deployment || !rest) return url;\n\treturn `${resource}/${deployment}/${rest}`;\n}\n\n/**\n * The provider table. Order matters only for `detectProviderByUrl` (first match\n * wins); slugs are looked up by `resolverKey`.\n */\nexport const GATEWAY_PROVIDERS: GatewayProviderInfo[] = [\n\t// ---- Unified-billing run-catalog providers (resumable run path) ----\n\t{\n\t\tresolverKey: \"openai\",\n\t\tgatewayProviderId: \"openai\",\n\t\twireFormat: \"openai\",\n\t\trunCatalog: true,\n\t\tbilling: \"unified\",\n\t\tauthHeaders: [\"authorization\"],\n\t\thostPattern: OPENAI_HOST,\n\t\ttransformEndpoint: hostStrip(OPENAI_HOST),\n\t},\n\t{\n\t\tresolverKey: \"anthropic\",\n\t\tgatewayProviderId: \"anthropic\",\n\t\twireFormat: \"anthropic\",\n\t\t// Unified billing passes Anthropic through natively (unlike google, which it\n\t\t// normalizes to openai-wire), so the run path also speaks Anthropic Messages.\n\t\trunWireFormat: \"anthropic\",\n\t\trunCatalog: true,\n\t\tbilling: \"unified\",\n\t\tauthHeaders: [\"x-api-key\", \"authorization\"],\n\t\thostPattern: ANTHROPIC_HOST,\n\t\ttransformEndpoint: hostStrip(ANTHROPIC_HOST),\n\t},\n\t{\n\t\tresolverKey: \"google\",\n\t\tgatewayProviderId: \"google-ai-studio\",\n\t\t// Gateway path hits Gemini's native endpoint (google-wire); the unified run\n\t\t// path, however, returns openai-wire — so runWireFormat defaults to \"openai\".\n\t\twireFormat: \"google\",\n\t\trunCatalog: true,\n\t\tbilling: \"unified\",\n\t\tauthHeaders: [\"x-goog-api-key\", \"authorization\"],\n\t\thostPattern: GOOGLE_HOST,\n\t\ttransformEndpoint: hostStrip(GOOGLE_HOST),\n\t},\n\t{\n\t\tresolverKey: \"xai\",\n\t\tgatewayProviderId: GROK_KEY,\n\t\twireFormat: \"openai\",\n\t\t// Targeted so a forced gateway-path request host-strips correctly (the run\n\t\t// path, the default for xai, ignores this).\n\t\tbaseURL: \"https://api.x.ai/v1\",\n\t\trunCatalog: true,\n\t\tbilling: \"unified\",\n\t\tauthHeaders: [\"authorization\"],\n\t\thostPattern: XAI_HOST,\n\t\ttransformEndpoint: hostStrip(XAI_HOST),\n\t},\n\t{\n\t\tresolverKey: \"groq\",\n\t\tgatewayProviderId: \"groq\",\n\t\twireFormat: \"openai\",\n\t\t// Groq's gateway-native endpoint strips `/openai/v1/`, so the builder must\n\t\t// target that base or a forced gateway request doubles the prefix.\n\t\tbaseURL: \"https://api.groq.com/openai/v1\",\n\t\trunCatalog: true,\n\t\tbilling: \"unified\",\n\t\tauthHeaders: [\"authorization\"],\n\t\thostPattern: GROQ_HOST,\n\t\ttransformEndpoint: hostStrip(GROQ_HOST),\n\t},\n\t// Unified-catalog chat providers that are NOT in the native gateway directory:\n\t// they exist only on the resumable run path (env.AI.run, unified billing), so\n\t// there's no BYOK gateway path. Both return OpenAI chat-completions wire (so the\n\t// `openai` plugin parses them) and emit `cf-aig-run-id` on streams (resumable),\n\t// verified live against the default gateway. Forcing transport:\"gateway\" for\n\t// these errors upstream (no native provider) — that's expected.\n\t{\n\t\t// Alibaba Qwen, served via DashScope's OpenAI-compatible endpoint.\n\t\tresolverKey: \"alibaba\",\n\t\tgatewayProviderId: \"alibaba\",\n\t\twireFormat: \"openai\",\n\t\trunCatalog: true,\n\t\tgatewayPath: false,\n\t\tbilling: \"unified\",\n\t\tauthHeaders: [\"authorization\"],\n\t},\n\t{\n\t\t// MiniMax (M-series). OpenAI-wire with extra fields (reasoning_content,\n\t\t// audio_content) the openai parser ignores; core choices[].delta.content is standard.\n\t\tresolverKey: \"minimax\",\n\t\tgatewayProviderId: \"minimax\",\n\t\twireFormat: \"openai\",\n\t\trunCatalog: true,\n\t\tgatewayPath: false,\n\t\tbilling: \"unified\",\n\t\tauthHeaders: [\"authorization\"],\n\t},\n\t{\n\t\tresolverKey: \"google-vertex\",\n\t\tgatewayProviderId: \"google-vertex-ai\",\n\t\t// Vertex's URL carries project/location/publisher segments that the\n\t\t// `@ai-sdk/google` default (AI Studio) does not produce, so the slug\n\t\t// delegate can't shape it reliably — reach Vertex via createGatewayProvider.\n\t\trunCatalog: false,\n\t\tbilling: \"unified\",\n\t\tauthHeaders: [\"authorization\"],\n\t\thostPattern: VERTEX_HOST,\n\t\ttransformEndpoint: hostStrip(VERTEX_HOST),\n\t},\n\n\t// ---- OpenAI-compatible long tail (gateway path, BYOK) ----\n\t{\n\t\tresolverKey: \"deepseek\",\n\t\tgatewayProviderId: \"deepseek\",\n\t\twireFormat: \"openai\",\n\t\tbaseURL: \"https://api.deepseek.com\",\n\t\trunCatalog: false,\n\t\tbilling: \"byok\",\n\t\tauthHeaders: [\"authorization\"],\n\t\thostPattern: DEEPSEEK_HOST,\n\t\ttransformEndpoint: hostStrip(DEEPSEEK_HOST),\n\t},\n\t{\n\t\tresolverKey: \"mistral\",\n\t\tgatewayProviderId: \"mistral\",\n\t\twireFormat: \"openai\",\n\t\tbaseURL: \"https://api.mistral.ai/v1\",\n\t\trunCatalog: false,\n\t\tbilling: \"byok\",\n\t\tauthHeaders: [\"authorization\"],\n\t\thostPattern: MISTRAL_HOST,\n\t\ttransformEndpoint: hostStrip(MISTRAL_HOST),\n\t},\n\t{\n\t\tresolverKey: \"perplexity\",\n\t\tgatewayProviderId: \"perplexity-ai\",\n\t\twireFormat: \"openai\",\n\t\tbaseURL: \"https://api.perplexity.ai\",\n\t\trunCatalog: false,\n\t\tbilling: \"byok\",\n\t\tauthHeaders: [\"authorization\"],\n\t\thostPattern: PERPLEXITY_HOST,\n\t\ttransformEndpoint: hostStrip(PERPLEXITY_HOST),\n\t},\n\t{\n\t\tresolverKey: \"cerebras\",\n\t\tgatewayProviderId: \"cerebras\",\n\t\twireFormat: \"openai\",\n\t\tbaseURL: \"https://api.cerebras.ai/v1\",\n\t\trunCatalog: false,\n\t\tbilling: \"byok\",\n\t\tauthHeaders: [\"authorization\"],\n\t\thostPattern: CEREBRAS_HOST,\n\t\ttransformEndpoint: hostStrip(CEREBRAS_HOST),\n\t},\n\t{\n\t\tresolverKey: \"openrouter\",\n\t\tgatewayProviderId: \"openrouter\",\n\t\twireFormat: \"openai\",\n\t\tbaseURL: \"https://openrouter.ai/api/v1\",\n\t\trunCatalog: false,\n\t\tbilling: \"byok\",\n\t\tauthHeaders: [\"authorization\"],\n\t\thostPattern: OPENROUTER_HOST,\n\t\ttransformEndpoint: hostStrip(OPENROUTER_HOST),\n\t},\n\t{\n\t\t// Fireworks is OpenAI-compatible. Present on ai-gateway-provider (#409) but\n\t\t// not the current provider directory — treat as BYOK long-tail.\n\t\tresolverKey: \"fireworks\",\n\t\tgatewayProviderId: \"fireworks\",\n\t\twireFormat: \"openai\",\n\t\tbaseURL: \"https://api.fireworks.ai/inference/v1\",\n\t\trunCatalog: false,\n\t\tbilling: \"byok\",\n\t\tauthHeaders: [\"authorization\"],\n\t\thostPattern: FIREWORKS_HOST,\n\t\ttransformEndpoint: hostStrip(FIREWORKS_HOST),\n\t},\n\t// Providers whose gateway-path URL shape isn't reliably reproducible from the\n\t// shared openai builder (cohere's /compat surface, baseten's per-deployment\n\t// hosts, parallel, azure's resource/deployment path) are bring-your-own-provider\n\t// only — set your own @ai-sdk provider baseURL and route via createGatewayProvider.\n\t{\n\t\tresolverKey: \"cohere\",\n\t\tgatewayProviderId: \"cohere\",\n\t\trunCatalog: false,\n\t\tbilling: \"byok\",\n\t\tauthHeaders: [\"authorization\"],\n\t\thostPattern: COHERE_HOST,\n\t\ttransformEndpoint: hostStrip(COHERE_HOST),\n\t},\n\t{\n\t\t// Baseten serves per-deployment hosts, so there's no single detectable URL\n\t\t// shape — reach it with an explicit `provider` via createGatewayProvider.\n\t\tresolverKey: \"baseten\",\n\t\tgatewayProviderId: \"baseten\",\n\t\trunCatalog: false,\n\t\tbilling: \"byok\",\n\t\tauthHeaders: [\"authorization\"],\n\t},\n\t{\n\t\tresolverKey: \"parallel\",\n\t\tgatewayProviderId: \"parallel\",\n\t\trunCatalog: false,\n\t\tbilling: \"byok\",\n\t\tauthHeaders: [\"authorization\", \"x-api-key\"],\n\t},\n\t{\n\t\tresolverKey: \"azure-openai\",\n\t\tgatewayProviderId: \"azure-openai\",\n\t\trunCatalog: false,\n\t\tbilling: \"byok\",\n\t\tauthHeaders: [\"api-key\", \"authorization\"],\n\t\thostPattern: AZURE_HOST,\n\t\ttransformEndpoint: azureTransform,\n\t},\n\n\t// ---- Provider-native only: reachable via the bring-your-own-provider wrapper ----\n\t// (no `wireFormat` ⇒ not auto-wired by the slug delegate)\n\t{\n\t\tresolverKey: \"aws-bedrock\",\n\t\tgatewayProviderId: \"aws-bedrock\",\n\t\trunCatalog: false,\n\t\tbilling: \"byok\",\n\t\tauthHeaders: [\"authorization\"],\n\t\thostPattern: BEDROCK_HOST,\n\t\ttransformEndpoint: bedrockTransform,\n\t},\n\t{\n\t\tresolverKey: \"huggingface\",\n\t\tgatewayProviderId: \"huggingface\",\n\t\trunCatalog: false,\n\t\tbilling: \"byok\",\n\t\tauthHeaders: [\"authorization\"],\n\t\thostPattern: HUGGINGFACE_HOST,\n\t\ttransformEndpoint: hostStrip(HUGGINGFACE_HOST),\n\t},\n\t{\n\t\tresolverKey: \"replicate\",\n\t\tgatewayProviderId: \"replicate\",\n\t\trunCatalog: false,\n\t\tbilling: \"byok\",\n\t\tauthHeaders: [\"authorization\"],\n\t\thostPattern: REPLICATE_HOST,\n\t\ttransformEndpoint: hostStrip(REPLICATE_HOST),\n\t},\n\t{\n\t\tresolverKey: \"fal\",\n\t\tgatewayProviderId: \"fal\",\n\t\trunCatalog: false,\n\t\tbilling: \"byok\",\n\t\tauthHeaders: [\"authorization\"],\n\t\thostPattern: FAL_HOST,\n\t\ttransformEndpoint: hostStrip(FAL_HOST),\n\t},\n\t{\n\t\tresolverKey: \"ideogram\",\n\t\tgatewayProviderId: \"ideogram\",\n\t\trunCatalog: false,\n\t\tbilling: \"byok\",\n\t\tauthHeaders: [\"authorization\"],\n\t\thostPattern: IDEOGRAM_HOST,\n\t\ttransformEndpoint: hostStrip(IDEOGRAM_HOST),\n\t},\n\t{\n\t\tresolverKey: \"cartesia\",\n\t\tgatewayProviderId: \"cartesia\",\n\t\trunCatalog: false,\n\t\tbilling: \"byok\",\n\t\tauthHeaders: [\"authorization\", \"x-api-key\"],\n\t\thostPattern: CARTESIA_HOST,\n\t\ttransformEndpoint: hostStrip(CARTESIA_HOST),\n\t},\n\t{\n\t\tresolverKey: \"deepgram\",\n\t\tgatewayProviderId: \"deepgram\",\n\t\trunCatalog: false,\n\t\tbilling: \"byok\",\n\t\tauthHeaders: [\"authorization\", \"token\"],\n\t\thostPattern: DEEPGRAM_HOST,\n\t\ttransformEndpoint: hostStrip(DEEPGRAM_HOST),\n\t},\n\t{\n\t\tresolverKey: \"elevenlabs\",\n\t\tgatewayProviderId: \"elevenlabs\",\n\t\trunCatalog: false,\n\t\tbilling: \"byok\",\n\t\tauthHeaders: [\"xi-api-key\", \"authorization\"],\n\t\thostPattern: ELEVENLABS_HOST,\n\t\ttransformEndpoint: hostStrip(ELEVENLABS_HOST),\n\t},\n];\n\n/** Aliases that map a friendly slug prefix to a canonical `resolverKey`. */\nconst RESOLVER_ALIASES: Record<string, string> = {\n\t// xAI's run-catalog author is `xai`, but `grok` is the common name.\n\tgrok: \"xai\",\n\t\"google-ai-studio\": \"google\",\n\t\"google-vertex-ai\": \"google-vertex\",\n\tbedrock: \"aws-bedrock\",\n\tazure: \"azure-openai\",\n};\n\nconst BY_RESOLVER_KEY = new Map<string, GatewayProviderInfo>(\n\tGATEWAY_PROVIDERS.map((p) => [p.resolverKey, p]),\n);\n\n/** Look up a provider by the slug prefix the user typed (honoring aliases). */\nexport function findProviderBySlug(resolverKey: string): GatewayProviderInfo | undefined {\n\tconst canonical = RESOLVER_ALIASES[resolverKey] ?? resolverKey;\n\treturn BY_RESOLVER_KEY.get(canonical);\n}\n\n/** Detect the gateway provider from a wrapped provider's request URL (BYOG). */\nexport function detectProviderByUrl(url: string): GatewayProviderInfo | undefined {\n\treturn GATEWAY_PROVIDERS.find((p) => p.hostPattern?.test(url));\n}\n\n/** All slug keys with a built-in parser (auto-wireable by the slug delegate). */\nexport function wireableProviders(): GatewayProviderInfo[] {\n\treturn GATEWAY_PROVIDERS.filter((p) => p.wireFormat !== undefined);\n}\n","import { GatewayDelegateError } from \"./errors\";\n\n/**\n * Resumable run-path stream (RFC §7.1).\n *\n * Wraps the byte stream from a run-path response (`env.AI.run(..., {\n * returnRawResponse })`) so a transient mid-stream drop is recovered\n * transparently: the wrapper reconnects to the gateway resume endpoint and keeps\n * feeding bytes to the same consumer, so the downstream `@ai-sdk/*` parser never\n * sees the break.\n *\n * Byte alignment is the one correctness subtlety. The gateway `resume?from=N`\n * endpoint takes an SSE *event index* (count of `\\n\\n` terminators) and replays\n * whole events from that index. So the wrapper only ever emits *complete* events\n * downstream and buffers any trailing partial event. On a drop the buffered\n * partial is discarded and resume starts from the count of complete events\n * already emitted — landing exactly on the next event boundary, with no\n * duplicated or truncated bytes.\n *\n * Expiry: once the gateway buffer TTL (~5.5 min) elapses, resume returns 404\n * `{\"error\":\"Request not found\"}`. Behavior is governed by `onResumeExpired`:\n * `\"error\"` (default) surfaces a `GatewayDelegateError(\"resume-expired\")` into\n * the stream; `\"accept-partial\"` ends the stream cleanly with whatever was\n * already delivered (the caller's higher layer — e.g. Think — can then continue\n * or regenerate).\n */\n\ntype AiWithFetch = Ai & {\n\tfetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;\n};\n\nexport type ResumeExpiredPolicy = \"error\" | \"accept-partial\";\n\nexport interface ResumableStreamOptions {\n\t/** Cloudflare AI binding (e.g. `env.AI`) — used for the resume fetch. */\n\tbinding: Ai;\n\t/** Gateway id the run was issued under. */\n\tgateway: string;\n\t/** The `cf-aig-run-id` of the run to resume. */\n\trunId: string;\n\t/**\n\t * Initial run-path response body. Omit for **cross-invocation re-attach**: the\n\t * stream then starts by fetching `resume?from={fromEvent}` directly (e.g. a new\n\t * Durable Object invocation re-attaching to a run after eviction).\n\t */\n\tinitial?: ReadableStream<Uint8Array>;\n\t/**\n\t * SSE event index to (re-)attach from. Defaults to `0`. Used as the starting\n\t * `from` when `initial` is omitted, and as the base offset for the event\n\t * counter (so a later reconnect resumes from the correct absolute index).\n\t */\n\tfromEvent?: number;\n\t/** What to do when the resume buffer has expired (404). Defaults to `\"error\"`. */\n\tonResumeExpired?: ResumeExpiredPolicy;\n\t/** Max reconnect attempts before giving up. Defaults to 5. */\n\tmaxReconnects?: number;\n\t/** Fired before each reconnect with the resume `from` index and attempt number. */\n\tonReconnect?: (fromEvent: number, attempt: number) => void;\n\t/**\n\t * Fired with the cumulative SSE event offset whenever complete events are\n\t * emitted. Use it to persist `{ runId, eventOffset }` for cross-invocation\n\t * re-attach (throttle your own writes — this can fire per chunk).\n\t */\n\tonProgress?: (eventOffset: number) => void;\n\t/**\n\t * Abort signal for the consuming request. When it aborts (or the downstream\n\t * consumer cancels the wrapped stream), the engine stops **without**\n\t * reconnecting — an intentional cancel must never trigger a resume reconnect.\n\t * The signal is also forwarded to the resume fetch.\n\t */\n\tsignal?: AbortSignal;\n}\n\nfunction concat(a: Uint8Array, b: Uint8Array): Uint8Array<ArrayBuffer> {\n\tconst out = new Uint8Array(new ArrayBuffer(a.length + b.length));\n\tout.set(a, 0);\n\tout.set(b, a.length);\n\treturn out;\n}\n\n/** Index just past the last `\\n\\n` in `buf`, or -1 if there is no complete event. */\nfunction lastEventBoundary(buf: Uint8Array): number {\n\tfor (let i = buf.length - 2; i >= 0; i--) {\n\t\tif (buf[i] === 0x0a && buf[i + 1] === 0x0a) return i + 2;\n\t}\n\treturn -1;\n}\n\n/** Count of `\\n\\n` terminators (= complete SSE events) in `buf`. */\nfunction countEvents(buf: Uint8Array): number {\n\tlet n = 0;\n\tfor (let i = 0; i + 1 < buf.length; i++) {\n\t\tif (buf[i] === 0x0a && buf[i + 1] === 0x0a) {\n\t\t\tn++;\n\t\t\ti++; // don't double-count \"\\n\\n\\n\"\n\t\t}\n\t}\n\treturn n;\n}\n\nfunction resumeUrl(gateway: string, runId: string, from: number): string {\n\treturn `https://workers-binding.ai/ai-gateway/gateways/${gateway}/run/${runId}/resume?from=${from}`;\n}\n\nexport function createResumableStream(options: ResumableStreamOptions): ReadableStream<Uint8Array> {\n\tconst { binding, gateway, runId } = options;\n\tconst maxReconnects = options.maxReconnects ?? 5;\n\tconst onExpired = options.onResumeExpired ?? \"error\";\n\n\tlet emittedEvents = options.fromEvent ?? 0; // absolute SSE event index reached\n\tlet pending: Uint8Array<ArrayBuffer> = new Uint8Array(new ArrayBuffer(0));\n\tlet reconnects = 0;\n\t// Set when the consumer cancels the wrapped stream; the read loop checks it\n\t// (alongside `options.signal`) so a cancel/abort never triggers a reconnect.\n\tlet canceled = false;\n\tlet activeReader: ReadableStreamDefaultReader<Uint8Array> | null = null;\n\n\tconst isAborted = () => canceled || options.signal?.aborted === true;\n\n\t// Fetch `resume?from={emittedEvents}`; on a terminal outcome (expiry / error /\n\t// network throw) it settles the controller and returns null.\n\tasync function fetchResume(\n\t\tcontroller: ReadableStreamDefaultController<Uint8Array>,\n\t): Promise<ReadableStream<Uint8Array> | null> {\n\t\tlet res: Response;\n\t\ttry {\n\t\t\tres = await (binding as AiWithFetch).fetch(resumeUrl(gateway, runId, emittedEvents), {\n\t\t\t\tmethod: \"GET\",\n\t\t\t\tsignal: options.signal,\n\t\t\t});\n\t\t} catch (fetchErr) {\n\t\t\tcontroller.error(\n\t\t\t\tnew GatewayDelegateError(\n\t\t\t\t\t\"dispatch\",\n\t\t\t\t\t`Resume request threw at event ${emittedEvents}.`,\n\t\t\t\t\tfetchErr,\n\t\t\t\t),\n\t\t\t);\n\t\t\treturn null;\n\t\t}\n\n\t\tif (res.status === 404) {\n\t\t\tif (onExpired === \"accept-partial\") {\n\t\t\t\tcontroller.close();\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tcontroller.error(\n\t\t\t\tnew GatewayDelegateError(\n\t\t\t\t\t\"resume-expired\",\n\t\t\t\t\t`Resume buffer expired (404) at event ${emittedEvents}. The gateway buffer ` +\n\t\t\t\t\t\t\"TTL (~5.5 min) elapsed; fall back to continuation or regeneration.\",\n\t\t\t\t),\n\t\t\t);\n\t\t\treturn null;\n\t\t}\n\t\tif (!res.ok || !res.body) {\n\t\t\tcontroller.error(\n\t\t\t\tnew GatewayDelegateError(\n\t\t\t\t\t\"dispatch\",\n\t\t\t\t\t`Resume failed (${res.status}) at event ${emittedEvents}.`,\n\t\t\t\t),\n\t\t\t);\n\t\t\treturn null;\n\t\t}\n\t\treturn res.body;\n\t}\n\n\treturn new ReadableStream<Uint8Array>({\n\t\tasync start(controller) {\n\t\t\t// In-stream wrap starts from the live body; cross-invocation re-attach\n\t\t\t// (no `initial`) starts by resuming from `fromEvent`. An initial-attach\n\t\t\t// failure is terminal — it is not charged against the reconnect budget.\n\t\t\tlet current: ReadableStream<Uint8Array>;\n\t\t\tif (options.initial) {\n\t\t\t\tcurrent = options.initial;\n\t\t\t} else {\n\t\t\t\tconst body = await fetchResume(controller);\n\t\t\t\tif (!body) return;\n\t\t\t\tcurrent = body;\n\t\t\t}\n\n\t\t\tfor (;;) {\n\t\t\t\tconst reader = current.getReader();\n\t\t\t\tactiveReader = reader;\n\t\t\t\ttry {\n\t\t\t\t\tfor (;;) {\n\t\t\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\t\t\tif (done) {\n\t\t\t\t\t\t\tif (pending.length > 0) {\n\t\t\t\t\t\t\t\tcontroller.enqueue(pending);\n\t\t\t\t\t\t\t\tpending = new Uint8Array(new ArrayBuffer(0));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcontroller.close();\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!value || value.length === 0) continue;\n\n\t\t\t\t\t\tpending = concat(pending, value);\n\t\t\t\t\t\tconst boundary = lastEventBoundary(pending);\n\t\t\t\t\t\tif (boundary > 0) {\n\t\t\t\t\t\t\tconst complete = pending.slice(0, boundary);\n\t\t\t\t\t\t\tcontroller.enqueue(complete);\n\t\t\t\t\t\t\temittedEvents += countEvents(complete);\n\t\t\t\t\t\t\toptions.onProgress?.(emittedEvents);\n\t\t\t\t\t\t\tpending = pending.slice(boundary);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\treader.releaseLock();\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// reader may already be released\n\t\t\t\t\t}\n\n\t\t\t\t\t// An intentional cancel/abort must never auto-recover. Stop\n\t\t\t\t\t// without reconnecting (the stream is already being torn down).\n\t\t\t\t\tif (isAborted()) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (reconnects >= maxReconnects) {\n\t\t\t\t\t\tcontroller.error(\n\t\t\t\t\t\t\tnew GatewayDelegateError(\n\t\t\t\t\t\t\t\t\"resume-expired\",\n\t\t\t\t\t\t\t\t`Exceeded ${maxReconnects} reconnect attempts at event ${emittedEvents}.`,\n\t\t\t\t\t\t\t\terr,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Discard the unfinished partial — resume realigns on the boundary.\n\t\t\t\t\tpending = new Uint8Array(new ArrayBuffer(0));\n\t\t\t\t\treconnects++;\n\t\t\t\t\toptions.onReconnect?.(emittedEvents, reconnects);\n\n\t\t\t\t\tconst body = await fetchResume(controller);\n\t\t\t\t\tif (!body) return;\n\t\t\t\t\tcurrent = body;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tcancel(reason) {\n\t\t\t// Downstream consumer canceled (e.g. the request was aborted). Mark\n\t\t\t// canceled so the read loop won't reconnect, and release the upstream.\n\t\t\tcanceled = true;\n\t\t\tif (activeReader) {\n\t\t\t\tactiveReader.cancel(reason).catch(() => {\n\t\t\t\t\t// upstream may already be closed\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t});\n}\n","/**\n * Shared, framework-agnostic Workers AI helpers.\n *\n * These are the pieces that `workers-ai-provider` (native `LanguageModelV3`) and\n * `@cloudflare/tanstack-ai` (OpenAI-SDK shim) both need: the SSE byte decoder,\n * message normalization for the binding's stricter schema, response-text\n * extraction across WAI's response shapes, and the gpt-oss forced-tool-call\n * salvage.\n *\n * IMPORTANT — id/dependency decoupling: nothing here depends on the `ai` package\n * or mints framework tool-call ids. `parseLeakedToolCalls` returns neutral\n * `{ toolName, input }` records; each consumer assigns its own ids and adapts to\n * its own tool-call shape. This keeps `gateway-core` free of an `ai` dependency.\n */\n\n// ---------------------------------------------------------------------------\n// SSE byte decoding\n// ---------------------------------------------------------------------------\n\n/**\n * TransformStream that decodes a raw byte stream into SSE `data:` payloads.\n * Each output chunk is the string content after `data: ` (one per SSE event),\n * with line buffering for partial chunks.\n */\nexport class SSEDecoder extends TransformStream<Uint8Array, string> {\n\tconstructor() {\n\t\tlet buffer = \"\";\n\t\tconst decoder = new TextDecoder();\n\n\t\tconst emit = (line: string, controller: TransformStreamDefaultController<string>) => {\n\t\t\tconst trimmed = line.trim();\n\t\t\tif (!trimmed) return;\n\t\t\tif (trimmed.startsWith(\"data: \")) {\n\t\t\t\tcontroller.enqueue(trimmed.slice(6));\n\t\t\t} else if (trimmed.startsWith(\"data:\")) {\n\t\t\t\tcontroller.enqueue(trimmed.slice(5));\n\t\t\t}\n\t\t};\n\n\t\tsuper({\n\t\t\ttransform(chunk, controller) {\n\t\t\t\tbuffer += decoder.decode(chunk, { stream: true });\n\t\t\t\tconst lines = buffer.split(\"\\n\");\n\t\t\t\tbuffer = lines.pop() || \"\";\n\t\t\t\tfor (const line of lines) emit(line, controller);\n\t\t\t},\n\n\t\t\tflush(controller) {\n\t\t\t\tif (buffer.trim()) emit(buffer, controller);\n\t\t\t},\n\t\t});\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Message normalization\n// ---------------------------------------------------------------------------\n\n/**\n * Normalize messages before passing to the Workers AI binding.\n *\n * The binding has strict schema validation that differs from the OpenAI API:\n * `content` must not be `null`/`undefined` (coerced to `\"\"`). Content arrays\n * (image_url parts) pass through untouched for vision-capable models.\n */\nexport function normalizeMessagesForBinding<T extends Record<string, unknown>>(messages: T[]): T[] {\n\treturn messages.map((msg) => {\n\t\tconst normalized = { ...msg };\n\t\tif (normalized.content === null || normalized.content === undefined) {\n\t\t\t(normalized as Record<string, unknown>).content = \"\";\n\t\t}\n\t\treturn normalized;\n\t});\n}\n\n// ---------------------------------------------------------------------------\n// Response-text extraction\n// ---------------------------------------------------------------------------\n\n/**\n * Extract text from a Workers AI response, handling multiple response shapes:\n * - OpenAI format: `{ choices: [{ message: { content: \"...\" } }] }`\n * - Native format: `{ response: \"...\" }`\n * - Structured-output quirk: `{ response: { ... } }` (object) / `\"{ ... }\"` (JSON string)\n * - Numeric `{ response: 42 }`\n */\nexport function processText(output: Record<string, unknown>): string | undefined {\n\tconst choices = output.choices as Array<{ message?: { content?: string | null } }> | undefined;\n\tconst choiceContent = choices?.[0]?.message?.content;\n\tif (choiceContent != null && String(choiceContent).length > 0) {\n\t\treturn String(choiceContent);\n\t}\n\n\tif (\"response\" in output) {\n\t\tconst response = output.response;\n\t\tif (typeof response === \"object\" && response !== null) {\n\t\t\treturn JSON.stringify(response);\n\t\t}\n\t\tif (typeof response === \"number\") {\n\t\t\treturn String(response);\n\t\t}\n\t\tif (response === null || response === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn String(response);\n\t}\n\treturn undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Forced tool-call salvage (gpt-oss harmony quirk)\n// ---------------------------------------------------------------------------\n\n/** A tool call recovered from leaked text — id-less and framework-neutral. */\nexport interface NeutralToolCall {\n\ttoolName: string;\n\t/** JSON-encoded arguments string. */\n\tinput: string;\n}\n\n/**\n * Was a specific tool forced for this request?\n *\n * True for both `tool_choice: \"required\"` and the named-function form\n * `{ type: \"function\", function: { name } }`.\n */\nexport function isForcedToolChoice(toolChoice: unknown): boolean {\n\tif (toolChoice === \"required\") return true;\n\treturn (\n\t\ttypeof toolChoice === \"object\" &&\n\t\ttoolChoice !== null &&\n\t\t(toolChoice as { type?: unknown }).type === \"function\"\n\t);\n}\n\n/** Collect the requested tool names from mapped tools. */\nexport function getToolNames(\n\ttools: Array<{ function: { name?: string } }> | undefined,\n): Set<string> {\n\treturn new Set(\n\t\t(tools ?? [])\n\t\t\t.map((tool) => tool.function?.name)\n\t\t\t.filter((name): name is string => typeof name === \"string\"),\n\t);\n}\n\n/**\n * Parse tool calls that a model leaked as JSON text instead of structured\n * `tool_calls`. Shared by the non-streaming salvage and the streaming buffer.\n *\n * Only JSON objects whose `name` is one of `knownToolNames` are recovered;\n * everything else (prose, harmony channel/role leaks like `{\"name\":\"analysis\"}`,\n * hallucinated names) is ignored to avoid fabricating bogus calls.\n *\n * Returns neutral `{ toolName, input }` records — callers assign their own ids.\n */\nexport function parseLeakedToolCalls(text: string, knownToolNames: Set<string>): NeutralToolCall[] {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(text.trim());\n\t} catch {\n\t\treturn [];\n\t}\n\n\tconst candidates = Array.isArray(parsed) ? parsed : [parsed];\n\tconst salvaged: NeutralToolCall[] = [];\n\n\tfor (const candidate of candidates) {\n\t\tif (typeof candidate !== \"object\" || candidate === null) continue;\n\t\tconst obj = candidate as Record<string, unknown>;\n\t\tconst name = obj.name;\n\t\tif (typeof name !== \"string\" || !knownToolNames.has(name)) continue;\n\n\t\t// Arguments may be wrapped (`arguments`/`parameters`) or flattened as\n\t\t// siblings of `name`.\n\t\tlet args: unknown;\n\t\tif (\"arguments\" in obj) {\n\t\t\targs = obj.arguments;\n\t\t} else if (\"parameters\" in obj) {\n\t\t\targs = obj.parameters;\n\t\t} else {\n\t\t\tconst { name: _name, ...rest } = obj;\n\t\t\targs = rest;\n\t\t}\n\n\t\tsalvaged.push({\n\t\t\ttoolName: name,\n\t\t\tinput: typeof args === \"string\" ? args : JSON.stringify(args ?? {}),\n\t\t});\n\t}\n\n\treturn salvaged;\n}\n","/**\n * `ai-gateway-provider`'s URL→provider lookup table.\n *\n * The canonical provider registry now lives in `@cloudflare/gateway-core` and is\n * shared with `workers-ai-provider` / `@cloudflare/tanstack-ai`. This module\n * derives the legacy `{ name, regex, transformEndpoint, headerKey? }` shape that\n * `index.ts` consumes from that single source of truth, so there's only one place\n * that knows how to map a provider host to its gateway endpoint.\n *\n * Two things are intentionally preserved here:\n *  - the `compat` entry (the unified `/v1/compat/` surface) has no core\n *    equivalent, so it stays local and is appended last; and\n *  - `headerKey` is only emitted for providers whose native BYOK header is not\n *    `authorization` (matching the historical table, where `index.ts` defaults to\n *    stripping `authorization`).\n */\nimport { GATEWAY_PROVIDERS } from \"@cloudflare/gateway-core\";\n\nexport interface AiGatewayProviderConfig {\n\tname: string;\n\tregex: RegExp;\n\ttransformEndpoint: (url: string) => string;\n\theaderKey?: string;\n}\n\nconst derived: AiGatewayProviderConfig[] = GATEWAY_PROVIDERS.flatMap((p) => {\n\t// Only providers with a detectable host shape participate in URL routing.\n\tif (!p.hostPattern || !p.transformEndpoint) return [];\n\tconst nativeAuthHeader = p.authHeaders[0];\n\treturn [\n\t\t{\n\t\t\tname: p.gatewayProviderId,\n\t\t\tregex: p.hostPattern,\n\t\t\ttransformEndpoint: p.transformEndpoint,\n\t\t\t...(nativeAuthHeader && nativeAuthHeader !== \"authorization\"\n\t\t\t\t? { headerKey: nativeAuthHeader }\n\t\t\t\t: {}),\n\t\t},\n\t];\n});\n\nexport const providers: AiGatewayProviderConfig[] = [\n\t...derived,\n\t{\n\t\tname: \"compat\",\n\t\tregex: /^https:\\/\\/gateway\\.ai\\.cloudflare\\.com\\/v1\\/compat\\//,\n\t\ttransformEndpoint: (url: string) =>\n\t\t\turl.replace(/^https:\\/\\/gateway\\.ai\\.cloudflare\\.com\\/v1\\/compat\\//, \"\"),\n\t},\n];\n","import {\n\tapplyGatewayCacheHeaders,\n\tcreateResumableStream,\n\ttype ResumableStreamOptions,\n\ttype ResumeExpiredPolicy,\n} from \"@cloudflare/gateway-core\";\nimport type { LanguageModelV3 } from \"@ai-sdk/provider\";\nimport type { FetchFunction } from \"@ai-sdk/provider-utils\";\nimport { CF_TEMP_TOKEN } from \"./auth\";\nimport { providers } from \"./providers\";\n\nexport class AiGatewayInternalFetchError extends Error {}\n\nexport class AiGatewayDoesNotExist extends Error {}\n\nexport class AiGatewayUnauthorizedError extends Error {}\n\nasync function streamToObject(stream: ReadableStream) {\n\tconst response = new Response(stream);\n\treturn await response.json();\n}\n\n/**\n * Read the AI Gateway error code from a failed response without consuming the\n * original body (the response may still be handed to the wrapped model). Returns\n * `undefined` when the body isn't the expected `{ success: false, error: [...] }`\n * shape.\n */\nasync function readGatewayErrorCode(resp: Response): Promise<number | undefined> {\n\tlet result: {\n\t\tsuccess?: boolean;\n\t\terror?: { code: number; message: string }[];\n\t};\n\ttry {\n\t\tresult = await resp.clone().json();\n\t} catch {\n\t\treturn undefined;\n\t}\n\tif (result.success === false && result.error && result.error.length > 0) {\n\t\treturn result.error[0]?.code;\n\t}\n\treturn undefined;\n}\n\ntype InternalLanguageModelV3 = LanguageModelV3 & {\n\tconfig?: { fetch?: FetchFunction | undefined };\n};\n\nexport class AiGatewayChatLanguageModel implements LanguageModelV3 {\n\treadonly specificationVersion = \"v3\";\n\treadonly defaultObjectGenerationMode = \"json\";\n\n\treadonly supportedUrls: Record<string, RegExp[]> | PromiseLike<Record<string, RegExp[]>> = {\n\t\t// No URLS are supported for this language model\n\t};\n\n\treadonly models: InternalLanguageModelV3[];\n\treadonly config: AiGatewaySettings;\n\n\tget modelId(): string {\n\t\tif (!this.models[0]) {\n\t\t\tthrow new Error(\"models cannot be empty array\");\n\t\t}\n\n\t\treturn this.models[0].modelId;\n\t}\n\n\tget provider(): string {\n\t\tif (!this.models[0]) {\n\t\t\tthrow new Error(\"models cannot be empty array\");\n\t\t}\n\n\t\treturn this.models[0].provider;\n\t}\n\n\tconstructor(models: LanguageModelV3[], config: AiGatewaySettings) {\n\t\tthis.models = models;\n\t\tthis.config = config;\n\t}\n\n\tasync processModelRequest<\n\t\tT extends LanguageModelV3[\"doStream\"] | LanguageModelV3[\"doGenerate\"],\n\t>(\n\t\toptions: Parameters<T>[0],\n\t\tmodelMethod: \"doStream\" | \"doGenerate\",\n\t): Promise<Awaited<ReturnType<T>>> {\n\t\tconst requests: { url: string; request: Request; modelProvider: string }[] = [];\n\n\t\t// Model configuration and request collection\n\t\tfor (const model of this.models) {\n\t\t\tif (!model.config || !Object.keys(model.config).includes(\"fetch\")) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Sorry, but provider \"${model.provider}\" is currently not supported, please open a issue in the github repo!`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tmodel.config.fetch = (url, request) => {\n\t\t\t\trequests.push({\n\t\t\t\t\tmodelProvider: model.provider,\n\t\t\t\t\trequest: request as Request,\n\t\t\t\t\turl: url as string,\n\t\t\t\t});\n\t\t\t\tthrow new AiGatewayInternalFetchError(\"Stopping provider execution...\");\n\t\t\t};\n\n\t\t\ttry {\n\t\t\t\tawait model[modelMethod](options);\n\t\t\t} catch (e) {\n\t\t\t\tif (!(e instanceof AiGatewayInternalFetchError)) {\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Process requests\n\t\tconst body = await Promise.all(\n\t\t\trequests.map(async (req) => {\n\t\t\t\tlet providerConfig: (typeof providers)[number] | null = null;\n\t\t\t\tfor (const provider of providers) {\n\t\t\t\t\tif (provider.regex.test(req.url)) {\n\t\t\t\t\t\tproviderConfig = provider;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!providerConfig) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Sorry, but provider \"${req.modelProvider}\" is currently not supported, please open a issue in the github repo!`,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif (!req.request.body) {\n\t\t\t\t\tthrow new Error(\"Ai Gateway provider received an unexpected empty body\");\n\t\t\t\t}\n\n\t\t\t\t// For AI Gateway BYOK / unified billing requests\n\t\t\t\t// delete the fake injected CF_TEMP_TOKEN\n\n\t\t\t\tconst authHeader = providerConfig.headerKey ?? \"authorization\";\n\t\t\t\tconst authValue =\n\t\t\t\t\t\"get\" in req.request.headers\n\t\t\t\t\t\t? req.request.headers.get(authHeader)\n\t\t\t\t\t\t: req.request.headers[authHeader];\n\t\t\t\tif (authValue?.includes(CF_TEMP_TOKEN)) {\n\t\t\t\t\tif (\"delete\" in req.request.headers) {\n\t\t\t\t\t\treq.request.headers.delete(authHeader);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdelete req.request.headers[authHeader];\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\tendpoint: providerConfig.transformEndpoint(req.url),\n\t\t\t\t\theaders: req.request.headers,\n\t\t\t\t\tprovider: providerConfig.name,\n\t\t\t\t\tquery: await streamToObject(req.request.body),\n\t\t\t\t};\n\t\t\t}),\n\t\t);\n\n\t\t// Handle response\n\t\tconst headers = parseAiGatewayOptions(this.config.options ?? {});\n\t\tlet resp: Response;\n\n\t\tif (\"binding\" in this.config) {\n\t\t\tconst updatedBody = body.map((obj) => ({\n\t\t\t\t...obj,\n\t\t\t\theaders: {\n\t\t\t\t\t...(obj.headers ?? {}),\n\t\t\t\t\t...Object.fromEntries(headers.entries()),\n\t\t\t\t},\n\t\t\t}));\n\t\t\tresp = await this.config.binding.run(updatedBody, {\n\t\t\t\tsignal: options.abortSignal,\n\t\t\t});\n\t\t} else {\n\t\t\theaders.set(\"Content-Type\", \"application/json\");\n\t\t\theaders.set(\"cf-aig-authorization\", `Bearer ${this.config.apiKey}`);\n\t\t\tresp = await fetch(\n\t\t\t\t`https://gateway.ai.cloudflare.com/v1/${this.config.accountId}/${this.config.gateway}`,\n\t\t\t\t{\n\t\t\t\t\tbody: JSON.stringify(body),\n\t\t\t\t\theaders: headers,\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\tsignal: options.abortSignal,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\t// Error handling: the gateway signals a missing gateway (2001) or failed\n\t\t// gateway auth (2009) via a `{ success: false, error: [...] }` body.\n\t\tif (resp.status === 400 && (await readGatewayErrorCode(resp)) === 2001) {\n\t\t\tthrow new AiGatewayDoesNotExist(\"This AI gateway does not exist\");\n\t\t}\n\t\tif (resp.status === 401 && (await readGatewayErrorCode(resp)) === 2009) {\n\t\t\tthrow new AiGatewayUnauthorizedError(\n\t\t\t\t\"Your AI Gateway has authentication active, but you didn't provide a valid apiKey\",\n\t\t\t);\n\t\t}\n\n\t\tconst step = Number.parseInt(resp.headers.get(\"cf-aig-step\") ?? \"0\", 10);\n\t\tif (!this.models[step]) {\n\t\t\tthrow new Error(\"Unexpected AI Gateway Error\");\n\t\t}\n\n\t\t// Opt-in resumable streaming (binding/run path only). When `resume` is\n\t\t// configured and the streaming response carries a `cf-aig-run-id`, wrap the\n\t\t// SSE body so a transient mid-stream drop reconnects to the gateway resume\n\t\t// endpoint transparently. No run id (e.g. the REST/API-key path, or a\n\t\t// gateway that doesn't surface one) means this is a no-op.\n\t\tif (\n\t\t\tmodelMethod === \"doStream\" &&\n\t\t\t\"resume\" in this.config &&\n\t\t\tthis.config.resume &&\n\t\t\tresp.body\n\t\t) {\n\t\t\tconst runId = resp.headers.get(\"cf-aig-run-id\");\n\t\t\tif (runId) {\n\t\t\t\tconst { binding, gateway, onResumeExpired, maxReconnects } = this.config.resume;\n\t\t\t\tresp = new Response(\n\t\t\t\t\tcreateResumableStream({\n\t\t\t\t\t\tbinding,\n\t\t\t\t\t\tgateway,\n\t\t\t\t\t\trunId,\n\t\t\t\t\t\tinitial: resp.body,\n\t\t\t\t\t\tonResumeExpired,\n\t\t\t\t\t\tmaxReconnects,\n\t\t\t\t\t\tsignal: options.abortSignal,\n\t\t\t\t\t}),\n\t\t\t\t\t{\n\t\t\t\t\t\theaders: resp.headers,\n\t\t\t\t\t\tstatus: resp.status,\n\t\t\t\t\t\tstatusText: resp.statusText,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tthis.models[step].config = {\n\t\t\t...this.models[step].config,\n\t\t\tfetch: (_url, _req) => resp as unknown as Promise<Response>,\n\t\t};\n\n\t\treturn this.models[step][modelMethod](options) as Promise<Awaited<ReturnType<T>>>;\n\t}\n\n\tasync doStream(\n\t\toptions: Parameters<LanguageModelV3[\"doStream\"]>[0],\n\t): Promise<Awaited<ReturnType<LanguageModelV3[\"doStream\"]>>> {\n\t\treturn this.processModelRequest<LanguageModelV3[\"doStream\"]>(options, \"doStream\");\n\t}\n\n\tasync doGenerate(\n\t\toptions: Parameters<LanguageModelV3[\"doGenerate\"]>[0],\n\t): Promise<Awaited<ReturnType<LanguageModelV3[\"doGenerate\"]>>> {\n\t\treturn this.processModelRequest<LanguageModelV3[\"doGenerate\"]>(options, \"doGenerate\");\n\t}\n}\n\n/**\n * AI Gateway provider for the Vercel AI SDK. Wraps one or more `@ai-sdk/*`\n * language models and routes their requests through Cloudflare's AI Gateway\n * universal endpoint, with cross-vendor server-side fallback (the first model\n * that succeeds wins, selected via `cf-aig-step`).\n */\nexport interface AiGateway {\n\t(models: LanguageModelV3 | LanguageModelV3[]): LanguageModelV3;\n\n\tchat(models: LanguageModelV3 | LanguageModelV3[]): LanguageModelV3;\n}\n\nexport type AiGatewayRetries = {\n\tmaxAttempts?: 1 | 2 | 3 | 4 | 5;\n\tretryDelayMs?: number;\n\tbackoff?: \"constant\" | \"linear\" | \"exponential\";\n};\n\n/** @deprecated Misspelling — use {@link AiGatewayRetries} instead. */\nexport type AiGatewayReties = AiGatewayRetries;\n\nexport type AiGatewayOptions = {\n\tcacheKey?: string;\n\tcacheTtl?: number;\n\tskipCache?: boolean;\n\tmetadata?: Record<string, number | string | boolean | null | bigint>;\n\tcollectLog?: boolean;\n\teventId?: string;\n\trequestTimeoutMs?: number;\n\tretries?: AiGatewayRetries;\n\t/**\n\t * BYOK stored-key alias to authenticate with → `cf-aig-byok-alias`. Selects a\n\t * non-`default` key configured for the provider on the gateway.\n\t */\n\tbyokAlias?: string;\n\t/**\n\t * Per-request Zero Data Retention override (Unified Billing only) →\n\t * `cf-aig-zdr`. `true` forces ZDR-capable upstreams; `false` disables it for\n\t * this request.\n\t */\n\tzdr?: boolean;\n};\nexport type AiGatewayAPISettings = {\n\tgateway: string;\n\taccountId: string;\n\tapiKey?: string;\n\toptions?: AiGatewayOptions;\n};\n/**\n * Opt-in resumable streaming for the binding (run) path. Supply the full\n * Cloudflare AI binding (`env.AI`) plus the gateway id; when a streaming run\n * surfaces a `cf-aig-run-id`, transient mid-stream drops reconnect transparently\n * via the gateway resume endpoint. The reconnect uses `binding.fetch(...)`, so\n * this must be the AI binding itself — not the `env.AI.gateway(<id>)`\n * sub-binding passed as `binding` above.\n */\nexport type AiGatewayResumeSettings = {\n\t/** Full Cloudflare AI binding (`env.AI`) used for the resume reconnect fetch. */\n\tbinding: ResumableStreamOptions[\"binding\"];\n\t/** Gateway id the run was issued under (the `env.AI.gateway(<id>)` name). */\n\tgateway: string;\n\t/** What to do when the resume buffer has expired (404). Defaults to `\"error\"`. */\n\tonResumeExpired?: ResumeExpiredPolicy;\n\t/** Max reconnect attempts before giving up. Defaults to 5. */\n\tmaxReconnects?: number;\n};\n\nexport type AiGatewayBindingSettings = {\n\tbinding: {\n\t\trun(data: unknown, options?: { signal?: AbortSignal }): Promise<Response>;\n\t};\n\toptions?: AiGatewayOptions;\n\t/**\n\t * Opt-in resumable streaming. No-op on the REST/API-key path (which has no\n\t * `cf-aig-run-id`). See {@link AiGatewayResumeSettings}.\n\t */\n\tresume?: AiGatewayResumeSettings;\n};\nexport type AiGatewaySettings = AiGatewayAPISettings | AiGatewayBindingSettings;\n\nexport function createAiGateway(options: AiGatewaySettings): AiGateway {\n\tconst createChatModel = (models: LanguageModelV3 | LanguageModelV3[]) => {\n\t\treturn new AiGatewayChatLanguageModel(Array.isArray(models) ? models : [models], options);\n\t};\n\n\tconst provider = (models: LanguageModelV3 | LanguageModelV3[]) => createChatModel(models);\n\n\tprovider.chat = createChatModel;\n\n\treturn provider;\n}\n\n/**\n * Translate {@link AiGatewayOptions} into the `cf-aig-*` request headers the AI\n * Gateway universal endpoint understands. Delegates to the shared\n * `@cloudflare/gateway-core` header builder so the header names and semantics\n * stay identical to the `workers-ai-provider` delegate (e.g. the current\n * `cf-aig-cache-ttl` / `cf-aig-skip-cache` names rather than the deprecated\n * `cf-cache-ttl` / `cf-skip-cache`).\n */\nexport function parseAiGatewayOptions(options: AiGatewayOptions): Headers {\n\tconst record: Record<string, string> = {};\n\tapplyGatewayCacheHeaders(record, options);\n\treturn new Headers(record);\n}\n"],"mappings":"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"}