workers-ai-provider 3.3.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -171,7 +171,7 @@ Images can be provided as `Uint8Array`, base64 strings, or data URLs. Multiple i
171
171
  ## Tool calling
172
172
 
173
173
  ```ts
174
- import { generateText, stepCountIs } from "ai";
174
+ import { generateText, isStepCount } from "ai";
175
175
  import { z } from "zod";
176
176
 
177
177
  const { text } = await generateText({
@@ -184,7 +184,7 @@ const { text } = await generateText({
184
184
  execute: async ({ city }) => ({ city, temperature: 18, condition: "Cloudy" }),
185
185
  },
186
186
  },
187
- stopWhen: stepCountIs(2),
187
+ stopWhen: isStepCount(2),
188
188
  });
189
189
  ```
190
190
 
@@ -310,6 +310,8 @@ const { results } = await rerank({
310
310
 
311
311
  [AI Search](https://developers.cloudflare.com/ai-search/) is Cloudflare's managed RAG service. Connect your data and query it with natural language.
312
312
 
313
+ > For Cloudflare's new `ai_search_namespaces` Workers binding — upload files to AI Search for indexing, then search or chat over them — use the dedicated [`ai-search-provider`](../ai-search-provider/README.md) package. The `createAISearch` shown here wraps the legacy `AutoRAG` binding.
314
+
313
315
  ```jsonc
314
316
  // wrangler.jsonc
315
317
  {
@@ -373,7 +375,7 @@ const result = streamText({
373
375
  // result.response.headers["cf-aig-run-id"] is set — resume from there.
374
376
  ```
375
377
 
376
- The settings argument is **typed from the model id**: pass a `"<provider>/<model>"` catalog slug and the second argument autocompletes the per-call gateway options (`resume`, `fallback`, `cacheTtl`, `byok`, `metadata`, …, i.e. `DelegateCallOptions`); pass a `@cf/...` id and it autocompletes the usual `WorkersAIChatSettings`. `providers` is optional and **additive**: leave it unset and `createWorkersAI` behaves exactly as before; passing a catalog slug without it throws a helpful error pointing you here.
378
+ The settings argument is **typed from the model id**: pass a `"<provider>/<model>"` catalog slug and the second argument autocompletes the per-call gateway options (`resume`, `fallback`, `cacheTtl`, `byok`, `metadata`, …, i.e. `DelegateCallOptions`); pass a `@cf/...` id and it autocompletes the usual `WorkersAIChatSettings`. `providers` is optional and **additive**: leave it unset and `createWorkersAI` behaves exactly as before `@cf/...` ids work as always, and a `"<provider>/<model>"` catalog slug still routes through the unified-billing run path (defaulting to your account's `"default"` gateway, with the built-in OpenAI-compatible parser). Configure `providers` to unlock higher-fidelity parsing plus the per-call delegate options (BYOK, caching, fallback, resume); requesting one of those without `providers` throws a helpful error pointing you here.
377
379
 
378
380
  `gateway` is optional for catalog routing — when unset, requests use your account's `"default"` AI Gateway. Set `gateway: { id: "…" }` (here or per call) to use a specific gateway.
379
381
 
@@ -385,7 +387,7 @@ One plugin per **wire format** serves every provider of that format. The `openai
385
387
 
386
388
  The registry covers every provider in the [AI Gateway provider directory](https://developers.cloudflare.com/ai-gateway/usage/providers/) — OpenAI, Anthropic, Google AI Studio, Google Vertex AI, xAI/Grok, Groq, DeepSeek, Mistral, Perplexity, Cerebras, OpenRouter, Cohere, Baseten, Parallel, Azure OpenAI, Amazon Bedrock, HuggingFace, Replicate, Fal, Ideogram, Cartesia, Deepgram, ElevenLabs (plus Fireworks) — so `createGatewayFetch` can auto-detect them from the request URL.
387
389
 
388
- **Coverage maturity varies** (the whole feature is experimental). Only the unified-billing run-catalog providers — OpenAI, Anthropic, Google, xAI/Grok, Groq, Alibaba/Qwen, MiniMax — are exercised end-to-end against a live gateway. The remaining registry entries (BYOK gateway-path providers like DeepSeek/Mistral/Perplexity/Cerebras/OpenRouter/Fireworks, and bring-your-own-provider-only ones like Cohere/Baseten/Parallel/Azure OpenAI/Bedrock/HuggingFace/Replicate/Fal/Ideogram/Cartesia/Deepgram/ElevenLabs) are registry-level wiring (gateway id, host pattern, endpoint transform) that is **not yet live-verified** — the routing is in place, but a provider's exact request shape may need adjustment. Please file issues for any that misbehave.
390
+ **Coverage maturity varies** (the whole feature is experimental). Only the unified-billing run-catalog providers — OpenAI, Anthropic, Google, xAI/Grok, Groq, DeepSeek, Alibaba/Qwen, MiniMax — are exercised end-to-end against a live gateway. The remaining registry entries (BYOK gateway-path providers like Mistral/Perplexity/Cerebras/OpenRouter/Fireworks, and bring-your-own-provider-only ones like Cohere/Baseten/Parallel/Azure OpenAI/Bedrock/HuggingFace/Replicate/Fal/Ideogram/Cartesia/Deepgram/ElevenLabs) are registry-level wiring (gateway id, host pattern, endpoint transform) that is **not yet live-verified** — the routing is in place, but a provider's exact request shape may need adjustment. Please file issues for any that misbehave.
389
391
 
390
392
  > **Run-path wire format is per-provider — not always OpenAI.** On the resumable run path (`env.AI.run`), Cloudflare's unified catalog **normalizes most providers to OpenAI chat-completions** (so `google/…` is parsed with the `openai` plugin on the run path, even though the gateway path uses the native `google` plugin), but **passes Anthropic through natively** — so `anthropic/…` uses the `anthropic` plugin on both paths. In practice: include `openai` for the openai-wire run-path providers (openai, google, xai/grok, groq), and `anthropic` to use `anthropic/…`. The native `google` plugin is only needed if you force google onto the **gateway path**. If a plugin a transport needs is missing, the delegate throws a `GatewayDelegateError` naming it.
391
393
 
@@ -398,13 +400,13 @@ The transport is chosen automatically from the options you pass:
398
400
  | **run** (default) | `env.AI.run(...)` | ✅ | ❌ | ❌ | Unified billing |
399
401
  | **gateway** | `env.AI.gateway(id).run([])` | ❌ | ✅ | ✅ | BYOK / stored key |
400
402
 
401
- Run-catalog providers (OpenAI, Anthropic, Google, xAI, Groq, plus the unified-catalog chat providers Alibaba/Qwen and MiniMax) default to the resumable **run path**. BYOK-only providers (deepseek, mistral, perplexity, …) always use the **gateway path**. Asking for an impossible combination (e.g. `resume: true` with `fallback.mode: "server"`) throws a `GatewayDelegateError`.
403
+ Run-catalog providers (OpenAI, Anthropic, Google, xAI, Groq, DeepSeek, plus the unified-catalog chat providers Alibaba/Qwen and MiniMax) default to the resumable **run path**. BYOK-only providers (mistral, perplexity, cerebras, …) always use the **gateway path**. Asking for an impossible combination (e.g. `resume: true` with `fallback.mode: "server"`) throws a `GatewayDelegateError`.
402
404
 
403
405
  > Alibaba and MiniMax are **run-path only** — they're on the unified catalog but not the native gateway directory, so there's no gateway path. Requesting `transport: "gateway"`, caching, or server-side fallback on them throws a clear `GatewayDelegateError` at build time (rather than failing upstream); use the default run path or `fallback.mode: "client"`.
404
406
 
405
407
  ### BYOK (bring your own key)
406
408
 
407
- On the gateway path, set `byok: true` and supply the upstream key via `extraHeaders`:
409
+ Set `byok: true` to forward your own upstream key via `extraHeaders`. BYOK is a gateway-path feature, so it forces the gateway path even for a run-catalog provider like DeepSeek (resume isn't available on that leg):
408
410
 
409
411
  ```ts
410
412
  streamText({
@@ -1,4 +1,4 @@
1
- import { a as ProviderPlugin } from "./gateway-delegate-BAALxuBO.mjs";
1
+ import { a as ProviderPlugin } from "./gateway-delegate-CAX7trdL.mjs";
2
2
 
3
3
  //#region src/anthropic.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { LanguageModelV3 } from "@ai-sdk/provider";
1
+ import { LanguageModelV4 } from "@ai-sdk/provider";
2
2
 
3
3
  //#region ../gateway-core/dist/index.d.mts
4
4
  //#region src/errors.d.ts
@@ -49,10 +49,21 @@ declare class GatewayDelegateError extends Error {
49
49
  *
50
50
  * Slugs mirror the AI Gateway provider directory
51
51
  * (developers.cloudflare.com/ai-gateway/usage/providers/); endpoint transforms
52
- * mirror `ai-gateway-provider`'s provider table. `runCatalog` / `billing` flags
53
- * follow the documented unified-billing list (OpenAI, Anthropic, Google AI
54
- * Studio, Google Vertex, xAI/Grok, Groq) and are otherwise conservative the
55
- * e2e suite confirms them live, since resume is undocumented upstream.
52
+ * mirror `ai-gateway-provider`'s provider table.
53
+ *
54
+ * `runCatalog` marks providers whose models Cloudflare actually serves on the
55
+ * unified-billing `env.AI.run` path (resumable, `cf-aig-run-id`). Membership is
56
+ * NOT "any OpenAI-wire provider" — it's empirically what the run router accepts:
57
+ * the headline unified providers (OpenAI, Anthropic, Google AI Studio, xAI, Groq),
58
+ * the DashScope/MiniMax run-only providers, and `deepseek/*` (issue #596). Within
59
+ * a run-catalog provider, unified-billing eligibility is still decided per-MODEL
60
+ * (e.g. `deepseek/deepseek-v4-pro` is unified while `deepseek/deepseek-chat`
61
+ * returns a clear "use BYOK" signal). Everything else — the OpenAI-wire long tail
62
+ * (mistral, perplexity, cerebras, openrouter, fireworks), the provider-native
63
+ * `wireFormat`-less providers, and Vertex — is `runCatalog:false` and reached via
64
+ * the BYOK gateway path. `env.AI.run` distinguishes the two cleanly: `7003
65
+ * model-not-found` for off-catalog slugs vs `2021 use-BYOK` for a recognized
66
+ * BYOK-only model. All of this is guarded live by the e2e run-path membership probe.
56
67
  */
57
68
  /** Response wire format the slug delegate can parse with a built-in `@ai-sdk/*` provider. */
58
69
  type WireFormat = "openai" | "anthropic" | "google";
@@ -169,7 +180,7 @@ declare function createResumableStream(options: ResumableStreamOptions): Readabl
169
180
  /**
170
181
  * Shared, framework-agnostic Workers AI helpers.
171
182
  *
172
- * These are the pieces that `workers-ai-provider` (native `LanguageModelV3`) and
183
+ * These are the pieces that `workers-ai-provider` (native `LanguageModelV4`) and
173
184
  * `@cloudflare/tanstack-ai` (OpenAI-SDK shim) both need: the SSE byte decoder,
174
185
  * message normalization for the binding's stricter schema, response-text
175
186
  * extraction across WAI's response shapes, and the gpt-oss forced-tool-call
@@ -269,7 +280,7 @@ interface FallbackLeg {
269
280
  /** The model slug this leg dispatches. */
270
281
  slug: string;
271
282
  /** The built AI SDK model. */
272
- model: LanguageModelV3;
283
+ model: LanguageModelV4;
273
284
  /** Transport the leg uses. */
274
285
  transport: Transport;
275
286
  }
@@ -282,7 +293,7 @@ interface FallbackLeg {
282
293
  * produced a stream). Errors that surface *mid-stream* — after content has
283
294
  * already been emitted — are not recoverable here and propagate as-is.
284
295
  */
285
- declare function createClientFallbackModel(legs: FallbackLeg[]): LanguageModelV3;
296
+ declare function createClientFallbackModel(legs: FallbackLeg[]): LanguageModelV4;
286
297
  //#endregion
287
298
  //#region src/gateway-delegate.d.ts
288
299
  /**
@@ -351,7 +362,7 @@ interface ProviderPlugin {
351
362
  modelId: string;
352
363
  fetch: typeof globalThis.fetch;
353
364
  baseURL?: string;
354
- }): LanguageModelV3;
365
+ }): LanguageModelV4;
355
366
  }
356
367
  type Transport = "run" | "gateway";
357
368
  interface FallbackOptions {
@@ -446,4 +457,4 @@ interface Selection {
446
457
  declare function selectTransport(opts: DelegateCallOptions, resumeExplicitlyTrue: boolean, runCatalog?: boolean, gatewayAvailable?: boolean): Selection;
447
458
  //#endregion
448
459
  export { createResumableStream as C, wireableProviders as E, WireFormat as S, findProviderBySlug as T, GATEWAY_PROVIDERS as _, ProviderPlugin as a, ResumableStreamOptions as b, selectTransport as c, FallbackAttempt as d, GatewayErrorCode as f, Billing as g, WorkersAIGatewayError as h, ParsedSlug as i, FallbackLeg as l, WorkersAIFallbackError as m, DispatchInfo as n, Transport as o, GatewayErrorContext as p, FallbackOptions as r, parseSlug as s, DelegateCallOptions as t, createClientFallbackModel as u, GatewayDelegateError as v, detectProviderByUrl as w, ResumeExpiredPolicy as x, GatewayProviderInfo as y };
449
- //# sourceMappingURL=gateway-delegate-BAALxuBO.d.mts.map
460
+ //# sourceMappingURL=gateway-delegate-CAX7trdL.d.mts.map
@@ -246,8 +246,8 @@ const GATEWAY_PROVIDERS = [
246
246
  gatewayProviderId: "deepseek",
247
247
  wireFormat: "openai",
248
248
  baseURL: "https://api.deepseek.com",
249
- runCatalog: false,
250
- billing: "byok",
249
+ runCatalog: true,
250
+ billing: "unified",
251
251
  authHeaders: ["authorization"],
252
252
  hostPattern: DEEPSEEK_HOST,
253
253
  transformEndpoint: hostStrip(DEEPSEEK_HOST)
@@ -557,7 +557,7 @@ function createResumableStream(options) {
557
557
  /**
558
558
  * Shared, framework-agnostic Workers AI helpers.
559
559
  *
560
- * These are the pieces that `workers-ai-provider` (native `LanguageModelV3`) and
560
+ * These are the pieces that `workers-ai-provider` (native `LanguageModelV4`) and
561
561
  * `@cloudflare/tanstack-ai` (OpenAI-SDK shim) both need: the SSE byte decoder,
562
562
  * message normalization for the binding's stricter schema, response-text
563
563
  * extraction across WAI's response shapes, and the gpt-oss forced-tool-call
@@ -972,4 +972,4 @@ function createGatewayProvider(factory, config) {
972
972
  //#endregion
973
973
  export { GatewayDelegateError as C, headersToObject as S, detectProviderByUrl as _, WORKERS_AI_ERROR_CODE_TO_STATUS as a, asText as b, parseWorkersAIErrorCode as c, isForcedToolChoice as d, normalizeMessagesForBinding as f, GATEWAY_PROVIDERS as g, createResumableStream as h, WorkersAIGatewayError as i, SSEDecoder as l, processText as m, createGatewayProvider as n, isAbortError as o, parseLeakedToolCalls as p, WorkersAIFallbackError as r, messageOf as s, createGatewayFetch as t, getToolNames as u, findProviderBySlug as v, _defineProperty as w, buildGatewayEntry as x, wireableProviders as y };
974
974
 
975
- //# sourceMappingURL=gateway-provider-BjPLZLob.mjs.map
975
+ //# sourceMappingURL=gateway-provider-BIZ2bimW.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gateway-provider-BIZ2bimW.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 `LanguageModelV4`) 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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"}
@@ -1,2 +1,2 @@
1
- import { n as createGatewayProvider, t as createGatewayFetch } from "./gateway-provider-BjPLZLob.mjs";
1
+ import { n as createGatewayProvider, t as createGatewayFetch } from "./gateway-provider-BIZ2bimW.mjs";
2
2
  export { createGatewayFetch, createGatewayProvider };
package/dist/google.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as ProviderPlugin } from "./gateway-delegate-BAALxuBO.mjs";
1
+ import { a as ProviderPlugin } from "./gateway-delegate-CAX7trdL.mjs";
2
2
 
3
3
  //#region src/google.d.ts
4
4
  /**
package/dist/google.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { createGoogleGenerativeAI } from "@ai-sdk/google";
1
+ import { createGoogle } from "@ai-sdk/google";
2
2
  //#region src/google.ts
3
3
  /**
4
4
  * Google (Gemini) provider plugin for the gateway delegate. Pass to
@@ -9,7 +9,7 @@ import { createGoogleGenerativeAI } from "@ai-sdk/google";
9
9
  */
10
10
  const google = {
11
11
  wireFormat: "google",
12
- create: ({ modelId, fetch, baseURL }) => createGoogleGenerativeAI({
12
+ create: ({ modelId, fetch, baseURL }) => createGoogle({
13
13
  apiKey: "unused",
14
14
  fetch,
15
15
  ...baseURL ? { baseURL } : {}
@@ -1 +1 @@
1
- {"version":3,"file":"google.mjs","names":[],"sources":["../src/google.ts"],"sourcesContent":["import { createGoogleGenerativeAI } from \"@ai-sdk/google\";\nimport type { ProviderPlugin } from \"./gateway-delegate\";\n\n/**\n * Google (Gemini) provider plugin for the gateway delegate. Pass to\n * `createGatewayDelegate({ providers: [google] })` to handle `\"google/<model>\"`\n * (Google AI Studio) and `\"google-vertex/<model>\"` slugs.\n *\n * Requires `@ai-sdk/google` (an optional peer dependency — install it yourself).\n */\nexport const google: ProviderPlugin = {\n\twireFormat: \"google\",\n\tcreate: ({ modelId, fetch, baseURL }) =>\n\t\t// apiKey is a placeholder — the gateway handles auth (unified billing / BYOK)\n\t\t// and the delegate strips the x-goog-api-key header on the gateway path.\n\t\tcreateGoogleGenerativeAI({ apiKey: \"unused\", fetch, ...(baseURL ? { baseURL } : {}) })(\n\t\t\tmodelId,\n\t\t),\n};\n"],"mappings":";;;;;;;;;AAUA,MAAa,SAAyB;CACrC,YAAY;CACZ,SAAS,EAAE,SAAS,OAAO,cAG1B,yBAAyB;EAAE,QAAQ;EAAU;EAAO,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;CAAG,CAAC,CAAC,CACrF,OACD;AACF"}
1
+ {"version":3,"file":"google.mjs","names":[],"sources":["../src/google.ts"],"sourcesContent":["import { createGoogle } from \"@ai-sdk/google\";\nimport type { ProviderPlugin } from \"./gateway-delegate\";\n\n/**\n * Google (Gemini) provider plugin for the gateway delegate. Pass to\n * `createGatewayDelegate({ providers: [google] })` to handle `\"google/<model>\"`\n * (Google AI Studio) and `\"google-vertex/<model>\"` slugs.\n *\n * Requires `@ai-sdk/google` (an optional peer dependency — install it yourself).\n */\nexport const google: ProviderPlugin = {\n\twireFormat: \"google\",\n\tcreate: ({ modelId, fetch, baseURL }) =>\n\t\t// apiKey is a placeholder — the gateway handles auth (unified billing / BYOK)\n\t\t// and the delegate strips the x-goog-api-key header on the gateway path.\n\t\tcreateGoogle({ apiKey: \"unused\", fetch, ...(baseURL ? { baseURL } : {}) })(modelId),\n};\n"],"mappings":";;;;;;;;;AAUA,MAAa,SAAyB;CACrC,YAAY;CACZ,SAAS,EAAE,SAAS,OAAO,cAG1B,aAAa;EAAE,QAAQ;EAAU;EAAO,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;CAAG,CAAC,CAAC,CAAC,OAAO;AACpF"}
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
- import { C as createResumableStream, E as wireableProviders, S as WireFormat, T as findProviderBySlug, _ as GATEWAY_PROVIDERS, a as ProviderPlugin, b as ResumableStreamOptions, c as selectTransport, d as FallbackAttempt, f as GatewayErrorCode, g as Billing, h as WorkersAIGatewayError, i as ParsedSlug, l as FallbackLeg, m as WorkersAIFallbackError, n as DispatchInfo, o as Transport, p as GatewayErrorContext, r as FallbackOptions, s as parseSlug, t as DelegateCallOptions, u as createClientFallbackModel, v as GatewayDelegateError, w as detectProviderByUrl, x as ResumeExpiredPolicy, y as GatewayProviderInfo } from "./gateway-delegate-BAALxuBO.mjs";
1
+ import { C as createResumableStream, E as wireableProviders, S as WireFormat, T as findProviderBySlug, _ as GATEWAY_PROVIDERS, a as ProviderPlugin, b as ResumableStreamOptions, c as selectTransport, d as FallbackAttempt, f as GatewayErrorCode, g as Billing, h as WorkersAIGatewayError, i as ParsedSlug, l as FallbackLeg, m as WorkersAIFallbackError, n as DispatchInfo, o as Transport, p as GatewayErrorContext, r as FallbackOptions, s as parseSlug, t as DelegateCallOptions, u as createClientFallbackModel, v as GatewayDelegateError, w as detectProviderByUrl, x as ResumeExpiredPolicy, y as GatewayProviderInfo } from "./gateway-delegate-CAX7trdL.mjs";
2
2
  import { GatewayFetchConfig, createGatewayFetch, createGatewayProvider } from "./gateway-provider.mjs";
3
- import { EmbeddingModelV3, EmbeddingModelV3CallOptions, EmbeddingModelV3Result, ImageModelV3, LanguageModelV3, RerankingModelV3, SpeechModelV3, TranscriptionModelV3 } from "@ai-sdk/provider";
3
+ import { EmbeddingModelV4, EmbeddingModelV4CallOptions, EmbeddingModelV4Result, ImageModelV4, LanguageModelV4, RerankingModelV4, SpeechModelV4, TranscriptionModelV4 } from "@ai-sdk/provider";
4
4
 
5
5
  //#region src/aisearch-chat-settings.d.ts
6
6
  type AISearchChatSettings = {
@@ -65,8 +65,8 @@ type AISearchChatConfig = {
65
65
  binding: AutoRAG;
66
66
  gateway?: GatewayOptions;
67
67
  };
68
- declare class AISearchChatLanguageModel implements LanguageModelV3 {
69
- readonly specificationVersion = "v3";
68
+ declare class AISearchChatLanguageModel implements LanguageModelV4 {
69
+ readonly specificationVersion = "v4";
70
70
  readonly defaultObjectGenerationMode = "json";
71
71
  readonly supportedUrls: Record<string, RegExp[]> | PromiseLike<Record<string, RegExp[]>>;
72
72
  readonly modelId: TextGenerationModels;
@@ -80,8 +80,8 @@ declare class AISearchChatLanguageModel implements LanguageModelV3 {
80
80
  * Flattens the conversation into a single string for aiSearch.
81
81
  */
82
82
  private buildQuery;
83
- doGenerate(options: Parameters<LanguageModelV3["doGenerate"]>[0]): Promise<Awaited<ReturnType<LanguageModelV3["doGenerate"]>>>;
84
- doStream(options: Parameters<LanguageModelV3["doStream"]>[0]): Promise<Awaited<ReturnType<LanguageModelV3["doStream"]>>>;
83
+ doGenerate(options: Parameters<LanguageModelV4["doGenerate"]>[0]): Promise<Awaited<ReturnType<LanguageModelV4["doGenerate"]>>>;
84
+ doStream(options: Parameters<LanguageModelV4["doStream"]>[0]): Promise<Awaited<ReturnType<LanguageModelV4["doStream"]>>>;
85
85
  }
86
86
  //#endregion
87
87
  //#region src/workersai-embedding-model.d.ts
@@ -99,8 +99,8 @@ type WorkersAIEmbeddingSettings = {
99
99
  */
100
100
  [key: string]: unknown;
101
101
  };
102
- declare class WorkersAIEmbeddingModel implements EmbeddingModelV3 {
103
- readonly specificationVersion = "v3";
102
+ declare class WorkersAIEmbeddingModel implements EmbeddingModelV4 {
103
+ readonly specificationVersion = "v4";
104
104
  readonly modelId: EmbeddingModels;
105
105
  private readonly config;
106
106
  private readonly settings;
@@ -111,7 +111,7 @@ declare class WorkersAIEmbeddingModel implements EmbeddingModelV3 {
111
111
  doEmbed({
112
112
  values,
113
113
  abortSignal
114
- }: EmbeddingModelV3CallOptions): Promise<EmbeddingModelV3Result>;
114
+ }: EmbeddingModelV4CallOptions): Promise<EmbeddingModelV4Result>;
115
115
  }
116
116
  //#endregion
117
117
  //#region src/workersai-chat-settings.d.ts
@@ -163,8 +163,8 @@ type WorkersAIChatConfig = {
163
163
  gateway?: GatewayOptions; /** True when using a real Workers AI binding (not the REST shim). */
164
164
  isBinding: boolean;
165
165
  };
166
- declare class WorkersAIChatLanguageModel implements LanguageModelV3 {
167
- readonly specificationVersion = "v3";
166
+ declare class WorkersAIChatLanguageModel implements LanguageModelV4 {
167
+ readonly specificationVersion = "v4";
168
168
  readonly defaultObjectGenerationMode = "json";
169
169
  readonly supportedUrls: Record<string, RegExp[]> | PromiseLike<Record<string, RegExp[]>>;
170
170
  readonly modelId: TextGenerationModels;
@@ -190,6 +190,11 @@ declare class WorkersAIChatLanguageModel implements LanguageModelV3 {
190
190
  *
191
191
  * `reasoning_effort: null` is a valid value ("disable reasoning"), so we
192
192
  * check `!== undefined` rather than truthiness.
193
+ *
194
+ * The unified `reasoning` call option (spec v4) is mapped onto
195
+ * `reasoning_effort` between the two: an explicit per-call
196
+ * `providerOptions["workers-ai"].reasoning_effort` wins, then the unified
197
+ * option, then settings.
193
198
  */
194
199
  private buildRunInputs;
195
200
  /**
@@ -211,8 +216,8 @@ declare class WorkersAIChatLanguageModel implements LanguageModelV3 {
211
216
  * place so callers can observe the reinterpretation.
212
217
  */
213
218
  private extractContent;
214
- doGenerate(options: Parameters<LanguageModelV3["doGenerate"]>[0]): Promise<Awaited<ReturnType<LanguageModelV3["doGenerate"]>>>;
215
- doStream(options: Parameters<LanguageModelV3["doStream"]>[0]): Promise<Awaited<ReturnType<LanguageModelV3["doStream"]>>>;
219
+ doGenerate(options: Parameters<LanguageModelV4["doGenerate"]>[0]): Promise<Awaited<ReturnType<LanguageModelV4["doGenerate"]>>>;
220
+ doStream(options: Parameters<LanguageModelV4["doStream"]>[0]): Promise<Awaited<ReturnType<LanguageModelV4["doStream"]>>>;
216
221
  }
217
222
  //#endregion
218
223
  //#region src/workersai-image-settings.d.ts
@@ -226,11 +231,11 @@ type WorkersAIImageConfig = {
226
231
  binding: Ai;
227
232
  gateway?: GatewayOptions;
228
233
  };
229
- declare class WorkersAIImageModel implements ImageModelV3 {
234
+ declare class WorkersAIImageModel implements ImageModelV4 {
230
235
  readonly modelId: ImageGenerationModels;
231
236
  readonly settings: WorkersAIImageSettings;
232
237
  readonly config: WorkersAIImageConfig;
233
- readonly specificationVersion = "v3";
238
+ readonly specificationVersion = "v4";
234
239
  get maxImagesPerCall(): number;
235
240
  get provider(): string;
236
241
  constructor(modelId: ImageGenerationModels, settings: WorkersAIImageSettings, config: WorkersAIImageConfig);
@@ -241,7 +246,7 @@ declare class WorkersAIImageModel implements ImageModelV3 {
241
246
  aspectRatio,
242
247
  seed,
243
248
  abortSignal
244
- }: Parameters<ImageModelV3["doGenerate"]>[0]): Promise<Awaited<ReturnType<ImageModelV3["doGenerate"]>>>;
249
+ }: Parameters<ImageModelV4["doGenerate"]>[0]): Promise<Awaited<ReturnType<ImageModelV4["doGenerate"]>>>;
245
250
  }
246
251
  //#endregion
247
252
  //#region src/workersai-transcription-settings.d.ts
@@ -288,20 +293,20 @@ type WorkersAITranscriptionConfig = {
288
293
  credentials?: CreateRunConfig;
289
294
  };
290
295
  /**
291
- * Workers AI transcription model implementing the AI SDK's `TranscriptionModelV3` interface.
296
+ * Workers AI transcription model implementing the AI SDK's `TranscriptionModelV4` interface.
292
297
  *
293
298
  * Supports:
294
299
  * - Whisper models (`@cf/openai/whisper`, `whisper-tiny-en`, `whisper-large-v3-turbo`)
295
300
  * - Deepgram Nova-3 (`@cf/deepgram/nova-3`) — uses a different input/output format
296
301
  */
297
- declare class WorkersAITranscriptionModel implements TranscriptionModelV3 {
302
+ declare class WorkersAITranscriptionModel implements TranscriptionModelV4 {
298
303
  readonly modelId: TranscriptionModels;
299
304
  readonly settings: WorkersAITranscriptionSettings;
300
305
  readonly config: WorkersAITranscriptionConfig;
301
- readonly specificationVersion = "v3";
306
+ readonly specificationVersion = "v4";
302
307
  get provider(): string;
303
308
  constructor(modelId: TranscriptionModels, settings: WorkersAITranscriptionSettings, config: WorkersAITranscriptionConfig);
304
- doGenerate(options: Parameters<TranscriptionModelV3["doGenerate"]>[0]): Promise<Awaited<ReturnType<TranscriptionModelV3["doGenerate"]>>>;
309
+ doGenerate(options: Parameters<TranscriptionModelV4["doGenerate"]>[0]): Promise<Awaited<ReturnType<TranscriptionModelV4["doGenerate"]>>>;
305
310
  private runWhisper;
306
311
  private normalizeWhisperResponse;
307
312
  private runNova3;
@@ -318,19 +323,19 @@ type WorkersAISpeechConfig = {
318
323
  gateway?: GatewayOptions;
319
324
  };
320
325
  /**
321
- * Workers AI speech (text-to-speech) model implementing the AI SDK's `SpeechModelV3` interface.
326
+ * Workers AI speech (text-to-speech) model implementing the AI SDK's `SpeechModelV4` interface.
322
327
  *
323
328
  * Currently supports Deepgram Aura-1 (`@cf/deepgram/aura-1`).
324
329
  * The model accepts `{ text, voice?, speed? }` and returns raw audio bytes.
325
330
  */
326
- declare class WorkersAISpeechModel implements SpeechModelV3 {
331
+ declare class WorkersAISpeechModel implements SpeechModelV4 {
327
332
  readonly modelId: SpeechModels;
328
333
  readonly settings: WorkersAISpeechSettings;
329
334
  readonly config: WorkersAISpeechConfig;
330
- readonly specificationVersion = "v3";
335
+ readonly specificationVersion = "v4";
331
336
  get provider(): string;
332
337
  constructor(modelId: SpeechModels, settings: WorkersAISpeechSettings, config: WorkersAISpeechConfig);
333
- doGenerate(options: Parameters<SpeechModelV3["doGenerate"]>[0]): Promise<Awaited<ReturnType<SpeechModelV3["doGenerate"]>>>;
338
+ doGenerate(options: Parameters<SpeechModelV4["doGenerate"]>[0]): Promise<Awaited<ReturnType<SpeechModelV4["doGenerate"]>>>;
334
339
  }
335
340
  //#endregion
336
341
  //#region src/workersai-reranking-settings.d.ts
@@ -343,7 +348,7 @@ type WorkersAIRerankingConfig = {
343
348
  gateway?: GatewayOptions;
344
349
  };
345
350
  /**
346
- * Workers AI reranking model implementing the AI SDK's `RerankingModelV3` interface.
351
+ * Workers AI reranking model implementing the AI SDK's `RerankingModelV4` interface.
347
352
  *
348
353
  * Supports BGE reranker models (`@cf/baai/bge-reranker-base`, `bge-reranker-v2-m3`).
349
354
  *
@@ -351,14 +356,14 @@ type WorkersAIRerankingConfig = {
351
356
  * - Input: `{ query, contexts: [{ text }], top_k? }`
352
357
  * - Output: `{ response: [{ id, score }] }`
353
358
  */
354
- declare class WorkersAIRerankingModel implements RerankingModelV3 {
359
+ declare class WorkersAIRerankingModel implements RerankingModelV4 {
355
360
  readonly modelId: RerankingModels;
356
361
  readonly settings: WorkersAIRerankingSettings;
357
362
  readonly config: WorkersAIRerankingConfig;
358
- readonly specificationVersion = "v3";
363
+ readonly specificationVersion = "v4";
359
364
  get provider(): string;
360
365
  constructor(modelId: RerankingModels, settings: WorkersAIRerankingSettings, config: WorkersAIRerankingConfig);
361
- doRerank(options: Parameters<RerankingModelV3["doRerank"]>[0]): Promise<Awaited<ReturnType<RerankingModelV3["doRerank"]>>>;
366
+ doRerank(options: Parameters<RerankingModelV4["doRerank"]>[0]): Promise<Awaited<ReturnType<RerankingModelV4["doRerank"]>>>;
362
367
  }
363
368
  //#endregion
364
369
  //#region src/autorag-chat-language-model.d.ts