{"version":3,"file":"gateway-provider-CQU-v2IO.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","../../gateway-core/src/workers-ai-errors.ts","../src/errors.ts","../src/gateway-provider.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.\n *\n * `runCatalog` marks providers whose models Cloudflare actually serves on the\n * unified-billing `env.AI.run` path (resumable, `cf-aig-run-id`). Membership is\n * NOT \"any OpenAI-wire provider\" — it's empirically what the run router accepts:\n * the headline unified providers (OpenAI, Anthropic, Google AI Studio, xAI, Groq),\n * the DashScope/MiniMax run-only providers, and `deepseek/*` (issue #596). Within\n * a run-catalog provider, unified-billing eligibility is still decided per-MODEL\n * (e.g. `deepseek/deepseek-v4-pro` is unified while `deepseek/deepseek-chat`\n * returns a clear \"use BYOK\" signal). Everything else — the OpenAI-wire long tail\n * (mistral, perplexity, cerebras, openrouter, fireworks), the provider-native\n * `wireFormat`-less providers, and Vertex — is `runCatalog:false` and reached via\n * the BYOK gateway path. `env.AI.run` distinguishes the two cleanly: `7003\n * model-not-found` for off-catalog slugs vs `2021 use-BYOK` for a recognized\n * BYOK-only model. All of this is guarded live by the e2e run-path membership probe.\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// ---- DeepSeek: OpenAI-wire long-tail provider that IS on the unified run catalog ----\n\t// `deepseek/*` is served on the unified-billing run path (`env.AI.run`), unlike\n\t// the rest of the OpenAI-wire long tail below (which the run router does not\n\t// recognize). Eligibility is per-MODEL: `deepseek/deepseek-v4-pro` bills unified\n\t// (#596), while `deepseek/deepseek-chat` returns \"not available via unified\n\t// billing; use BYOK\" — a clear signal the caller answers with `byok`. So the run\n\t// path is the correct DEFAULT (matches pre-3.2, unblocks #596); BYOK stays\n\t// reachable per call via `transport:\"gateway\"` / `byok`, and\n\t// `baseURL`/`transformEndpoint` keep that forced gateway path working.\n\t// Verified live: v4-pro ⇒ 200, deepseek-chat ⇒ 402 use-BYOK (e2e probe).\n\t{\n\t\tresolverKey: \"deepseek\",\n\t\tgatewayProviderId: \"deepseek\",\n\t\twireFormat: \"openai\",\n\t\tbaseURL: \"https://api.deepseek.com\",\n\t\trunCatalog: true,\n\t\tbilling: \"unified\",\n\t\tauthHeaders: [\"authorization\"],\n\t\thostPattern: DEEPSEEK_HOST,\n\t\ttransformEndpoint: hostStrip(DEEPSEEK_HOST),\n\t},\n\n\t// ---- OpenAI-compatible long tail: BYOK gateway path only ----\n\t// These are OpenAI-wire providers reachable through the native gateway\n\t// directory, but NOT on Cloudflare's unified-billing run catalog: `env.AI.run`\n\t// returns `7003 model-not-found` for their canonical model ids (mistral,\n\t// cerebras, openrouter, fireworks), and perplexity is recognized-but-BYOK\n\t// (`2021 \"use BYOK\"`). None can be run unified, so they route through the BYOK\n\t// gateway path (`env.AI.gateway().run`, no resume) — supply your provider key\n\t// via `extraHeaders` + `byok`. `baseURL`/`transformEndpoint` shape that path.\n\t// (Empirically classified by the e2e run-path membership probe; if Cloudflare\n\t// adds any of these to unified billing, flip `runCatalog`/`billing` and the\n\t// probe will confirm.)\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\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 * Shared, dependency-free Workers AI error classification used by every\n * consumer of `@cloudflare/gateway-core` (`workers-ai-provider` and\n * `@cloudflare/tanstack-ai`).\n *\n * The Workers AI **binding** (`env.AI.run`) throws plain `Error`s whose message\n * carries an internal code (e.g. `\"3040: Capacity temporarily exceeded\"`) but\n * no HTTP status. Retry machinery (the AI SDK's `APICallError` retry, the OpenAI\n * SDK's status-based retry, and our own non-chat retry loop) all key off an HTTP\n * status, so we translate the internal code into the documented status and let\n * each layer derive retryability from it — this is what makes transient failures\n * like \"out of capacity\" (3040 → 429) automatically retried.\n *\n * This module is intentionally free of any provider-SDK types so it can be\n * inlined into each consumer's bundle.\n */\n\n/**\n * Workers AI internal error code → HTTP status code.\n *\n * Source: https://developers.cloudflare.com/workers-ai/platform/errors/\n */\nexport const WORKERS_AI_ERROR_CODE_TO_STATUS: Record<number, number> = {\n\t5007: 400, // No such model\n\t5004: 400, // Invalid data\n\t3039: 400, // Finetune missing required files\n\t3003: 400, // Incomplete request\n\t5018: 403, // Account not allowed for private model\n\t5016: 403, // Model agreement not accepted\n\t3023: 403, // Account blocked\n\t3041: 403, // Account not allowed for private model\n\t5019: 405, // Deprecated SDK version\n\t5005: 405, // LoRa unsupported\n\t3042: 404, // Invalid model ID\n\t3006: 413, // Request too large\n\t3007: 408, // Timeout\n\t3008: 408, // Aborted\n\t3036: 429, // Account limited (daily free allocation used up)\n\t3040: 429, // Out of capacity (no data center to forward to)\n};\n\n/** Read a human-readable message from any thrown value (Error, DOMException, plain object, string). */\nexport function messageOf(error: unknown): string {\n\tif (error instanceof Error) return error.message;\n\tif (typeof error === \"string\") return error;\n\tif (error && typeof error === \"object\") {\n\t\tconst message = (error as { message?: unknown }).message;\n\t\tif (typeof message === \"string\") return message;\n\t}\n\treturn String(error);\n}\n\n/**\n * Best-effort extraction of a Workers AI internal error code from a thrown\n * binding error. Prefers a numeric `code` property when present, otherwise\n * parses the `\"<code>: <message>\"` form the binding uses (optionally prefixed,\n * e.g. `\"InferenceUpstreamError: 3040: ...\"`). Only recognized codes are\n * returned, and when several `\"<number>:\"` groups appear (e.g. a leading\n * request id) the first that maps to a known code wins, so unrelated numbers\n * can't be misread as a code.\n */\nexport function parseWorkersAIErrorCode(error: unknown): number | undefined {\n\tif (error && typeof error === \"object\") {\n\t\tconst code = (error as { code?: unknown }).code;\n\t\tif (typeof code === \"number\" && code in WORKERS_AI_ERROR_CODE_TO_STATUS) {\n\t\t\treturn code;\n\t\t}\n\t\tif (typeof code === \"string\") {\n\t\t\tconst parsed = Number.parseInt(code, 10);\n\t\t\tif (Number.isFinite(parsed) && parsed in WORKERS_AI_ERROR_CODE_TO_STATUS) {\n\t\t\t\treturn parsed;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst message = messageOf(error);\n\tfor (const match of message.matchAll(/\\b(\\d{3,5})\\s*:/g)) {\n\t\tconst parsed = Number.parseInt(match[1]!, 10);\n\t\tif (parsed in WORKERS_AI_ERROR_CODE_TO_STATUS) {\n\t\t\treturn parsed;\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Map a thrown Workers AI binding error to its documented HTTP status, or\n * `undefined` when the error isn't a recognized Workers AI code (so callers can\n * decide how to treat unknown failures rather than fabricating a status).\n */\nexport function workersAIStatusFromError(error: unknown): number | undefined {\n\tconst code = parseWorkersAIErrorCode(error);\n\treturn code != null ? WORKERS_AI_ERROR_CODE_TO_STATUS[code] : undefined;\n}\n\n/**\n * True for cancellation errors that must propagate untouched (never wrapped or\n * retried, so each layer's own abort detection still fires). Mirrors the AI\n * SDK's `isAbortError`: a real abort from `fetch`/the binding is a\n * `DOMException`, which is NOT `instanceof Error`, so both must be checked.\n */\nexport function isAbortError(error: unknown): boolean {\n\treturn (\n\t\t(error instanceof Error || error instanceof DOMException) &&\n\t\t(error.name === \"AbortError\" ||\n\t\t\terror.name === \"ResponseAborted\" ||\n\t\t\terror.name === \"TimeoutError\")\n\t);\n}\n\n/**\n * Whether an HTTP status should be retried. Matches the set used by the AI SDK\n * and the OpenAI SDK: request timeout (408), conflict (409), rate limit (429),\n * and any server error (>= 500).\n */\nexport function isRetryableStatus(status: number): boolean {\n\treturn status === 408 || status === 409 || status === 429 || status >= 500;\n}\n","/**\n * Typed errors for the gateway delegate.\n *\n *   - {@link WorkersAIGatewayError} — a single dispatch failed. Carries a coarse\n *     {@link GatewayErrorCode}, a `recoverable` hint (whether a retry/fallback is\n *     worth attempting), and the parsed gateway/provider envelope.\n *   - {@link WorkersAIFallbackError} — every model in a client-side fallback chain\n *     failed. Carries the per-attempt tree so callers can see exactly what was\n *     tried and why each leg failed.\n */\n\n/** Coarse classification of a gateway/provider failure. */\nexport type GatewayErrorCode =\n\t| \"auth\" // 401 / 403 — bad or missing key (BYOK), or unified billing not enabled\n\t| \"rate-limit\" // 429 — throttled\n\t| \"not-found\" // 404 — unknown model/endpoint (or expired resume buffer)\n\t| \"bad-request\" // 400 / 422 — malformed request\n\t| \"provider-error\" // 5xx — upstream provider failure\n\t| \"gateway-error\" // gateway/transport failure with no usable status\n\t| \"resume-expired\" // resume buffer TTL elapsed (404 from resume endpoint)\n\t| \"unknown\";\n\n/** Context attached to a {@link WorkersAIGatewayError}. */\nexport interface GatewayErrorContext {\n\t/** Gateway provider id (e.g. `\"openai\"`, `\"google-ai-studio\"`). */\n\tprovider?: string;\n\t/** Provider-native model id. */\n\tmodelId?: string;\n\t/** Transport the failed dispatch used. */\n\ttransport?: \"run\" | \"gateway\";\n\t/** HTTP status, if any. */\n\tstatus?: number | null;\n\t/** `cf-aig-log-id` for cross-referencing in the dashboard. */\n\tlogId?: string | null;\n\t/** `cf-aig-run-id`, if the run path issued one. */\n\trunId?: string | null;\n}\n\n/** Map an HTTP status to a {@link GatewayErrorCode} + recoverability hint. */\nexport function classifyStatus(status: number): {\n\tcode: GatewayErrorCode;\n\trecoverable: boolean;\n} {\n\tif (status === 401 || status === 403) return { code: \"auth\", recoverable: false };\n\tif (status === 429) return { code: \"rate-limit\", recoverable: true };\n\tif (status === 404) return { code: \"not-found\", recoverable: false };\n\tif (status === 400 || status === 422) return { code: \"bad-request\", recoverable: false };\n\tif (status >= 500) return { code: \"provider-error\", recoverable: true };\n\treturn { code: \"unknown\", recoverable: false };\n}\n\n/** Best-effort extraction of a human message from a CF/provider error envelope. */\nexport function extractErrorMessage(raw: unknown): string | undefined {\n\tif (typeof raw === \"string\") {\n\t\tconst trimmed = raw.trim();\n\t\tif (!trimmed) return undefined;\n\t\ttry {\n\t\t\treturn extractErrorMessage(JSON.parse(trimmed));\n\t\t} catch {\n\t\t\treturn trimmed.slice(0, 500);\n\t\t}\n\t}\n\tif (!raw || typeof raw !== \"object\") return undefined;\n\tconst obj = raw as Record<string, unknown>;\n\t// CF gateway envelope: { errors: [{ code, message }] }\n\tif (Array.isArray(obj.errors) && obj.errors.length > 0) {\n\t\tconst first = obj.errors[0] as Record<string, unknown>;\n\t\tif (typeof first?.message === \"string\") return first.message;\n\t}\n\t// Provider envelopes: { error: { message } } or { error: \"...\" } or { message }\n\tif (obj.error && typeof obj.error === \"object\") {\n\t\tconst err = obj.error as Record<string, unknown>;\n\t\tif (typeof err.message === \"string\") return err.message;\n\t}\n\tif (typeof obj.error === \"string\") return obj.error;\n\tif (typeof obj.message === \"string\") return obj.message;\n\treturn undefined;\n}\n\n/** A single dispatch failure through AI Gateway (run or gateway path). */\nexport class WorkersAIGatewayError extends Error {\n\treadonly code: GatewayErrorCode;\n\t/** Whether a retry or fallback to another model is worth attempting. */\n\treadonly recoverable: boolean;\n\treadonly status: number | null;\n\treadonly context: GatewayErrorContext;\n\t/** Parsed gateway/provider error envelope (or raw text). */\n\treadonly raw?: unknown;\n\toverride readonly cause?: unknown;\n\n\tconstructor(\n\t\tcode: GatewayErrorCode,\n\t\tmessage: string,\n\t\topts: {\n\t\t\trecoverable?: boolean;\n\t\t\tstatus?: number | null;\n\t\t\tcontext?: GatewayErrorContext;\n\t\t\traw?: unknown;\n\t\t\tcause?: unknown;\n\t\t} = {},\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"WorkersAIGatewayError\";\n\t\tthis.code = code;\n\t\tthis.recoverable = opts.recoverable ?? false;\n\t\tthis.status = opts.status ?? null;\n\t\tthis.context = opts.context ?? {};\n\t\tthis.raw = opts.raw;\n\t\tthis.cause = opts.cause;\n\t}\n\n\t/**\n\t * Classify an arbitrary thrown value. Understands AI SDK `APICallError`\n\t * (reads `statusCode` / `responseBody` / `isRetryable`); falls back to a\n\t * recoverable `gateway-error` for transport/connection failures so a fallback\n\t * chain keeps trying.\n\t */\n\tstatic fromUnknown(e: unknown): WorkersAIGatewayError {\n\t\tif (e instanceof WorkersAIGatewayError) return e;\n\t\tconst obj = e && typeof e === \"object\" ? (e as Record<string, unknown>) : {};\n\t\tconst status = typeof obj.statusCode === \"number\" ? obj.statusCode : null;\n\t\tconst responseBody = typeof obj.responseBody === \"string\" ? obj.responseBody : undefined;\n\n\t\tif (status !== null) {\n\t\t\tconst classified = classifyStatus(status);\n\t\t\t// AI SDK already decides retryability per status; prefer it when present.\n\t\t\tconst recoverable =\n\t\t\t\ttypeof obj.isRetryable === \"boolean\" ? obj.isRetryable : classified.recoverable;\n\t\t\tconst message =\n\t\t\t\textractErrorMessage(responseBody) ??\n\t\t\t\t(e instanceof Error ? e.message : `Gateway dispatch failed (HTTP ${status}).`);\n\t\t\tlet raw: unknown = responseBody;\n\t\t\ttry {\n\t\t\t\traw = responseBody ? JSON.parse(responseBody) : responseBody;\n\t\t\t} catch {\n\t\t\t\t// keep raw text\n\t\t\t}\n\t\t\treturn new WorkersAIGatewayError(classified.code, message, {\n\t\t\t\trecoverable,\n\t\t\t\tstatus,\n\t\t\t\traw,\n\t\t\t\tcause: e,\n\t\t\t});\n\t\t}\n\n\t\treturn new WorkersAIGatewayError(\n\t\t\t\"gateway-error\",\n\t\t\te instanceof Error ? e.message : String(e),\n\t\t\t{ recoverable: true, cause: e },\n\t\t);\n\t}\n\n\t/** Build from an HTTP `Response` (reads the body for the envelope). */\n\tstatic async fromResponse(\n\t\tresp: Response,\n\t\tcontext: GatewayErrorContext = {},\n\t): Promise<WorkersAIGatewayError> {\n\t\tconst text = await resp.text().catch(() => \"\");\n\t\tconst { code, recoverable } = classifyStatus(resp.status);\n\t\tconst message =\n\t\t\textractErrorMessage(text) ?? `Gateway dispatch failed (HTTP ${resp.status}).`;\n\t\tlet raw: unknown = text;\n\t\ttry {\n\t\t\traw = text ? JSON.parse(text) : text;\n\t\t} catch {\n\t\t\t// keep raw text\n\t\t}\n\t\treturn new WorkersAIGatewayError(code, message, {\n\t\t\trecoverable,\n\t\t\tstatus: resp.status,\n\t\t\traw,\n\t\t\tcontext: {\n\t\t\t\t...context,\n\t\t\t\tstatus: resp.status,\n\t\t\t\tlogId: resp.headers.get(\"cf-aig-log-id\"),\n\t\t\t\trunId: resp.headers.get(\"cf-aig-run-id\"),\n\t\t\t},\n\t\t});\n\t}\n}\n\n/** One leg of a client-side fallback chain. */\nexport interface FallbackAttempt {\n\t/** The model slug attempted. */\n\tmodel: string;\n\t/** Transport used for this attempt. */\n\ttransport: \"run\" | \"gateway\";\n\t/** Whether this attempt succeeded. */\n\tok: boolean;\n\t/** HTTP status, if any. */\n\tstatus?: number | null;\n\t/** The classified error, when the attempt failed. */\n\terror?: WorkersAIGatewayError;\n}\n\n/** Every model in a client-side fallback chain failed. */\nexport class WorkersAIFallbackError extends Error {\n\t/** The ordered attempt tree (primary first, then each fallback). */\n\treadonly attempts: FallbackAttempt[];\n\n\tconstructor(attempts: FallbackAttempt[], message?: string) {\n\t\tconst tried = attempts.map((a) => a.model).join(\" → \");\n\t\tsuper(message ?? `All fallback models failed: ${tried}.`);\n\t\tthis.name = \"WorkersAIFallbackError\";\n\t\tthis.attempts = attempts;\n\t}\n\n\t/** The last (most recent) attempt's error, if any. */\n\tget lastError(): WorkersAIGatewayError | undefined {\n\t\tfor (let i = this.attempts.length - 1; i >= 0; i--) {\n\t\t\tconst e = this.attempts[i].error;\n\t\t\tif (e) return e;\n\t\t}\n\t\treturn undefined;\n\t}\n}\n","import { asText, buildGatewayEntry } from \"@cloudflare/gateway-core\";\nimport { WorkersAIGatewayError } from \"./errors\";\nimport { detectProviderByUrl, type GatewayProviderInfo } from \"./gateway-providers\";\n\n/**\n * Bring-your-own-provider: route any `@ai-sdk/*` provider's HTTP traffic through\n * Cloudflare AI Gateway, without the catalog slug delegate. The provider keeps\n * its own request/response shaping; this only swaps the transport.\n *\n * Use it for providers the slug delegate cannot auto-wire (bedrock, replicate,\n * audio/image providers, anything provider-native), or when you want full control\n * of the underlying `@ai-sdk` provider. This is the gateway path only — BYOK and\n * caching are available, resume (`cf-aig-run-id`) is not.\n *\n * @example\n * ```ts\n * import { createOpenAI } from \"@ai-sdk/openai\";\n * import { createGatewayFetch } from \"workers-ai-provider/gateway\";\n *\n * const openai = createOpenAI({\n *   apiKey: env.OPENAI_API_KEY, // forwarded when byok: true\n *   fetch: createGatewayFetch({ binding: env.AI, gateway: \"my-gw\", byok: true }),\n * });\n * const model = openai(\"gpt-5\");\n * ```\n */\nexport interface GatewayFetchConfig {\n\t/** A Cloudflare AI binding (e.g. `env.AI`). */\n\tbinding: Ai;\n\t/** Gateway id (or options). */\n\tgateway: GatewayOptions | string;\n\t/**\n\t * Force a gateway provider id instead of detecting it from the request URL.\n\t * Required when the wrapped provider's host is not in the registry.\n\t */\n\tprovider?: string;\n\t/**\n\t * Forward the upstream provider key (Authorization / x-api-key / …) instead of\n\t * stripping it. Required for BYOK providers. Defaults to `false` (strip, so\n\t * unified billing / the gateway's stored key applies).\n\t */\n\tbyok?: boolean;\n\t/** Extra headers added to every gateway entry. */\n\textraHeaders?: Record<string, string>;\n\t/** Gateway-path response caching (seconds). */\n\tcacheTtl?: number;\n\t/** Bypass gateway cache. */\n\tskipCache?: boolean;\n}\n\ninterface AiGatewayRunner {\n\trun(body: unknown, options?: Record<string, unknown>): Promise<Response>;\n}\n\n/**\n * A `fetch` that dispatches the wrapped provider's request through AI Gateway.\n * Detects the gateway provider id from the request URL (or uses `config.provider`),\n * strips the provider host to the endpoint path, and forwards the body verbatim.\n */\nexport function createGatewayFetch(config: GatewayFetchConfig): typeof globalThis.fetch {\n\tif (!config?.binding) {\n\t\tthrow new WorkersAIGatewayError(\n\t\t\t\"gateway-error\",\n\t\t\t\"createGatewayFetch requires a `binding` (e.g. { binding: env.AI }).\",\n\t\t);\n\t}\n\tconst gatewayId = typeof config.gateway === \"string\" ? config.gateway : config.gateway?.id;\n\tif (!gatewayId) {\n\t\tthrow new WorkersAIGatewayError(\n\t\t\t\"gateway-error\",\n\t\t\t'createGatewayFetch requires a `gateway` id (e.g. gateway: \"my-gateway\").',\n\t\t);\n\t}\n\n\treturn (async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {\n\t\tconst rawUrl = typeof input === \"string\" ? input : input.toString();\n\n\t\tlet info: GatewayProviderInfo | undefined;\n\t\tif (config.provider) {\n\t\t\tinfo = undefined; // explicit provider id; no registry lookup needed\n\t\t} else {\n\t\t\tinfo = detectProviderByUrl(rawUrl);\n\t\t\tif (!info) {\n\t\t\t\tthrow new WorkersAIGatewayError(\n\t\t\t\t\t\"gateway-error\",\n\t\t\t\t\t`Could not detect a gateway provider from URL \"${rawUrl}\". ` +\n\t\t\t\t\t\t'Pass `provider: \"<gateway-provider-id>\"` explicitly.',\n\t\t\t\t\t{ recoverable: false },\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tconst providerId = config.provider ?? (info as GatewayProviderInfo).gatewayProviderId;\n\t\tconst endpoint = info?.transformEndpoint\n\t\t\t? info.transformEndpoint(rawUrl)\n\t\t\t: rawUrl.replace(/^https?:\\/\\/[^/]+\\//, \"\");\n\t\tconst body = JSON.parse(asText(init?.body)) as Record<string, unknown>;\n\n\t\tconst entry = buildGatewayEntry({\n\t\t\tproviderId,\n\t\t\tendpoint,\n\t\t\tinitHeaders: init?.headers,\n\t\t\tbody,\n\t\t\t...(!config.byok && info ? { stripAuthHeaders: info.authHeaders } : {}),\n\t\t\t...(config.extraHeaders ? { extraHeaders: config.extraHeaders } : {}),\n\t\t\tcache: { cacheTtl: config.cacheTtl, skipCache: config.skipCache },\n\t\t});\n\t\tconst gw = (config.binding as unknown as { gateway(id: string): AiGatewayRunner }).gateway(\n\t\t\tgatewayId,\n\t\t);\n\t\tconst runOptions: Record<string, unknown> = {};\n\t\tif (init?.signal) runOptions.signal = init.signal;\n\t\treturn gw.run([entry], runOptions);\n\t}) as typeof globalThis.fetch;\n}\n\n/**\n * Wrap an `@ai-sdk/*` provider factory so its traffic flows through AI Gateway.\n * A thin convenience over {@link createGatewayFetch} — it injects the gateway\n * `fetch` (and a placeholder `apiKey` unless you supply one for BYOK).\n *\n * @example\n * ```ts\n * import { createOpenAI } from \"@ai-sdk/openai\";\n * import { createGatewayProvider } from \"workers-ai-provider/gateway\";\n *\n * const openai = createGatewayProvider(createOpenAI, {\n *   binding: env.AI,\n *   gateway: \"my-gw\",\n * });\n * const model = openai(\"gpt-5\");\n * ```\n */\nexport function createGatewayProvider<T>(\n\tfactory: (opts: { apiKey?: string; baseURL?: string; fetch: typeof globalThis.fetch }) => T,\n\tconfig: GatewayFetchConfig & { apiKey?: string; baseURL?: string },\n): T {\n\treturn factory({\n\t\tapiKey: config.apiKey ?? \"unused\",\n\t\t...(config.baseURL ? { baseURL: config.baseURL } : {}),\n\t\tfetch: createGatewayFetch(config),\n\t});\n}\n"],"mappings":"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"}