workers-ai-provider 3.2.1 → 3.3.1

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
@@ -2,6 +2,10 @@
2
2
 
3
3
  [Workers AI](https://developers.cloudflare.com/workers-ai/) provider for the [AI SDK](https://sdk.vercel.ai/). Run Cloudflare's models for chat, embeddings, image generation, transcription, text-to-speech, reranking, and [AI Search](https://developers.cloudflare.com/ai-search/) — all from a single provider. It can also route **third-party** models (OpenAI, Anthropic, Google, …) through [AI Gateway](https://developers.cloudflare.com/ai-gateway/) — see [Third-party models](#third-party-models-via-ai-gateway).
4
4
 
5
+ > 📚 In-depth guides and the AI Gateway **delegate** reference (unified catalog,
6
+ > resumable streaming _(coming soon)_, server-side fallback) live in
7
+ > [`docs/workers-ai-provider`](../../docs/workers-ai-provider/README.md).
8
+
5
9
  ## Quick start
6
10
 
7
11
  ```bash
@@ -333,7 +337,7 @@ Streaming works the same way — use `streamText` instead of `generateText`.
333
337
 
334
338
  > **⚠️ Experimental.** Everything in this section (routing third-party models via `createWorkersAI({ providers })`, the provider plugins, the registry, the resume layer, and `createGatewayFetch`/`createGatewayProvider`) is a new and substantial addition — well beyond the package's original job of wrapping Workers AI. Treat the whole surface as experimental: APIs may change, and several behaviors depend on undocumented AI Gateway internals (the `cf-aig-run-id` resume buffer, per-provider run-path wire formats). It does **not** affect the stable Workers AI / AI Search APIs above. Bug reports and feedback are very welcome.
335
339
 
336
- Route **third-party** catalog models — OpenAI, Anthropic, Google, xAI/Grok, Groq, and the OpenAI-compatible long tail — through [AI Gateway](https://developers.cloudflare.com/ai-gateway/) using the same `env.AI` binding, with resumable streaming, BYOK, caching, and fallback.
340
+ Route **third-party** catalog models — OpenAI, Anthropic, Google, xAI/Grok, Groq, and the OpenAI-compatible long tail — through [AI Gateway](https://developers.cloudflare.com/ai-gateway/) using the same `env.AI` binding, with resumable streaming _(coming soon)_, BYOK, caching, and fallback.
337
341
 
338
342
  Install only the wire-format plugins you actually use. They're **optional** peer dependencies:
339
343
 
@@ -360,7 +364,7 @@ const workersai = createWorkersAI({
360
364
  // gateway unless you set one, e.g. gateway: { id: "my-gateway" }.
361
365
  });
362
366
 
363
- workersai("@cf/meta/llama-3.1-8b-instruct"); // Workers AI (unchanged)
367
+ workersai("@cf/zai-org/glm-5.2"); // Workers AI (unchanged)
364
368
 
365
369
  const result = streamText({
366
370
  model: workersai("openai/gpt-5", { resume: true }), // routed through AI Gateway
@@ -369,7 +373,7 @@ const result = streamText({
369
373
  // result.response.headers["cf-aig-run-id"] is set — resume from there.
370
374
  ```
371
375
 
372
- 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.
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 `@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.
373
377
 
374
378
  `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.
375
379
 
@@ -381,7 +385,7 @@ One plugin per **wire format** serves every provider of that format. The `openai
381
385
 
382
386
  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.
383
387
 
384
- **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.
388
+ **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.
385
389
 
386
390
  > **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.
387
391
 
@@ -389,18 +393,18 @@ The registry covers every provider in the [AI Gateway provider directory](https:
389
393
 
390
394
  The transport is chosen automatically from the options you pass:
391
395
 
392
- | Transport | Backed by | Resume (`cf-aig-run-id`) | Caching | Server fallback | Billing |
393
- | ----------------- | ---------------------------- | ------------------------ | ------- | --------------- | ----------------- |
394
- | **run** (default) | `env.AI.run(...)` | ✅ | ❌ | ❌ | Unified billing |
395
- | **gateway** | `env.AI.gateway(id).run([])` | ❌ | ✅ | ✅ | BYOK / stored key |
396
+ | Transport | Backed by | Resume _(coming soon)_ (`cf-aig-run-id`) | Caching | Server fallback | Billing |
397
+ | ----------------- | ---------------------------- | ---------------------------------------- | ------- | --------------- | ----------------- |
398
+ | **run** (default) | `env.AI.run(...)` | ✅ | ❌ | ❌ | Unified billing |
399
+ | **gateway** | `env.AI.gateway(id).run([])` | ❌ | ✅ | ✅ | BYOK / stored key |
396
400
 
397
- 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`.
401
+ 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`.
398
402
 
399
403
  > 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"`.
400
404
 
401
405
  ### BYOK (bring your own key)
402
406
 
403
- On the gateway path, set `byok: true` and supply the upstream key via `extraHeaders`:
407
+ 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):
404
408
 
405
409
  ```ts
406
410
  streamText({
@@ -447,6 +451,11 @@ workersai("openai/gpt-5", {
447
451
 
448
452
  ### Resume after disconnect
449
453
 
454
+ > **🚧 Coming soon.** Resumable streaming is not generally available yet — the AI
455
+ > Gateway resume backend is still rolling out. The options here are in place so
456
+ > you can adopt them early, but treat resume as experimental until the rollout
457
+ > completes.
458
+
450
459
  The run path wraps the response stream so a transient mid-stream drop reconnects through the gateway resume endpoint transparently. For cross-invocation recovery (e.g. a Durable Object re-attaching after eviction), persist `{ runId, eventOffset }` via `onDispatch` + `onProgress` and re-attach with `createResumableStream`:
451
460
 
452
461
  ```ts
@@ -482,15 +491,15 @@ The provider id is detected from the request URL (or pass `provider` explicitly)
482
491
 
483
492
  ### `createWorkersAI(options)`
484
493
 
485
- | Option | Type | Description |
486
- | ----------------- | ------------------------------- | ------------------------------------------------------------------------------------------------- |
487
- | `binding` | `Ai` | Workers AI binding (`env.AI`). Use this OR credentials. |
488
- | `accountId` | `string` | Cloudflare account ID. Required with `apiKey`. |
489
- | `apiKey` | `string` | Cloudflare API token. Required with `accountId`. |
490
- | `gateway` | `GatewayOptions` | Optional [AI Gateway](https://developers.cloudflare.com/ai-gateway/) config. |
491
- | `providers` | `ProviderPlugin[]` | _Experimental._ Wire-format plugins that enable routing `"<provider>/<model>"` slugs via gateway. |
492
- | `resume` | `boolean` | _Experimental._ Default resume behavior for gateway-routed catalog models. Defaults to `true`. |
493
- | `onResumeExpired` | `"error"` \| `"accept-partial"` | _Experimental._ Default policy when the gateway resume buffer expires. Defaults to `"error"`. |
494
+ | Option | Type | Description |
495
+ | ----------------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------ |
496
+ | `binding` | `Ai` | Workers AI binding (`env.AI`). Use this OR credentials. |
497
+ | `accountId` | `string` | Cloudflare account ID. Required with `apiKey`. |
498
+ | `apiKey` | `string` | Cloudflare API token. Required with `accountId`. |
499
+ | `gateway` | `GatewayOptions` | Optional [AI Gateway](https://developers.cloudflare.com/ai-gateway/) config. |
500
+ | `providers` | `ProviderPlugin[]` | _Experimental._ Wire-format plugins that enable routing `"<provider>/<model>"` slugs via gateway. |
501
+ | `resume` | `boolean` | _Experimental — coming soon._ Default resume behavior for gateway-routed catalog models. Defaults to `true`. |
502
+ | `onResumeExpired` | `"error"` \| `"accept-partial"` | _Experimental — coming soon._ Default policy when the gateway resume buffer expires. Defaults to `"error"`. |
494
503
 
495
504
  Returns a provider with model factories. Each factory accepts an optional second argument for per-model settings:
496
505
 
@@ -1,4 +1,4 @@
1
- import { o as ProviderPlugin } from "./gateway-delegate-BfaUTwDZ.mjs";
1
+ import { a as ProviderPlugin } from "./gateway-delegate-D_zkIp5r.mjs";
2
2
 
3
3
  //#region src/anthropic.d.ts
4
4
  /**
@@ -1,5 +1,35 @@
1
1
  import { LanguageModelV3 } from "@ai-sdk/provider";
2
2
 
3
+ //#region ../gateway-core/dist/index.d.mts
4
+ //#region src/errors.d.ts
5
+ /**
6
+ * Error type shared by the gateway delegate and the resumable-stream engine.
7
+ *
8
+ * Lives in `@cloudflare/gateway-core` because the resume engine (here) and the
9
+ * delegate (in `workers-ai-provider`) both throw it. Note: since each consumer
10
+ * inlines this source into its own bundle, `instanceof GatewayDelegateError`
11
+ * only matches within a single package's bundle — match on `.name`/`.kind`
12
+ * across package boundaries.
13
+ */
14
+ type GatewayDelegateErrorKind = "config" | "dispatch" | "provider" | "resume-expired";
15
+ declare class GatewayDelegateError extends Error {
16
+ readonly kind: GatewayDelegateErrorKind;
17
+ readonly cause?: unknown;
18
+ constructor(kind: GatewayDelegateErrorKind, message: string, cause?: unknown);
19
+ } //#endregion
20
+ //#region src/gateway-fetch.d.ts
21
+ /**
22
+ * Shared AI Gateway dispatch primitives: the `cf-aig-*` header builder, the
23
+ * provider-key / hop-by-hop header strip, body decoding, and universal-endpoint
24
+ * entry construction.
25
+ *
26
+ * These are consumed by `workers-ai-provider` (the gateway-path `createGatewayFetch`
27
+ * and the delegate's `makeGatewayFetch`/`makeRunFetch`) and by `@cloudflare/tanstack-ai`
28
+ * (its REST/binding `createGatewayFetch`), so there's a single place that knows how
29
+ * to translate caching/metadata/log options into gateway headers.
30
+ */
31
+ /** Metadata values the gateway accepts (`bigint` is serialized to a string). */
32
+ //#endregion
3
33
  //#region src/gateway-providers.d.ts
4
34
  /**
5
35
  * Registry of Cloudflare AI Gateway providers.
@@ -19,10 +49,21 @@ import { LanguageModelV3 } from "@ai-sdk/provider";
19
49
  *
20
50
  * Slugs mirror the AI Gateway provider directory
21
51
  * (developers.cloudflare.com/ai-gateway/usage/providers/); endpoint transforms
22
- * mirror `ai-gateway-provider`'s provider table. `runCatalog` / `billing` flags
23
- * follow the documented unified-billing list (OpenAI, Anthropic, Google AI
24
- * Studio, Google Vertex, xAI/Grok, Groq) and are otherwise conservative the
25
- * 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.
26
67
  */
27
68
  /** Response wire format the slug delegate can parse with a built-in `@ai-sdk/*` provider. */
28
69
  type WireFormat = "openai" | "anthropic" | "google";
@@ -92,8 +133,7 @@ declare function findProviderBySlug(resolverKey: string): GatewayProviderInfo |
92
133
  /** Detect the gateway provider from a wrapped provider's request URL (BYOG). */
93
134
  declare function detectProviderByUrl(url: string): GatewayProviderInfo | undefined;
94
135
  /** All slug keys with a built-in parser (auto-wireable by the slug delegate). */
95
- declare function wireableProviders(): GatewayProviderInfo[];
96
- //#endregion
136
+ declare function wireableProviders(): GatewayProviderInfo[]; //#endregion
97
137
  //#region src/resumable-stream.d.ts
98
138
  type ResumeExpiredPolicy = "error" | "accept-partial";
99
139
  interface ResumableStreamOptions {
@@ -127,8 +167,35 @@ interface ResumableStreamOptions {
127
167
  * re-attach (throttle your own writes — this can fire per chunk).
128
168
  */
129
169
  onProgress?: (eventOffset: number) => void;
170
+ /**
171
+ * Abort signal for the consuming request. When it aborts (or the downstream
172
+ * consumer cancels the wrapped stream), the engine stops **without**
173
+ * reconnecting — an intentional cancel must never trigger a resume reconnect.
174
+ * The signal is also forwarded to the resume fetch.
175
+ */
176
+ signal?: AbortSignal;
130
177
  }
131
- declare function createResumableStream(options: ResumableStreamOptions): ReadableStream<Uint8Array>;
178
+ declare function createResumableStream(options: ResumableStreamOptions): ReadableStream<Uint8Array>; //#endregion
179
+ //#region src/workers-ai.d.ts
180
+ /**
181
+ * Shared, framework-agnostic Workers AI helpers.
182
+ *
183
+ * These are the pieces that `workers-ai-provider` (native `LanguageModelV3`) and
184
+ * `@cloudflare/tanstack-ai` (OpenAI-SDK shim) both need: the SSE byte decoder,
185
+ * message normalization for the binding's stricter schema, response-text
186
+ * extraction across WAI's response shapes, and the gpt-oss forced-tool-call
187
+ * salvage.
188
+ *
189
+ * IMPORTANT — id/dependency decoupling: nothing here depends on the `ai` package
190
+ * or mints framework tool-call ids. `parseLeakedToolCalls` returns neutral
191
+ * `{ toolName, input }` records; each consumer assigns its own ids and adapts to
192
+ * its own tool-call shape. This keeps `gateway-core` free of an `ai` dependency.
193
+ */
194
+ /**
195
+ * TransformStream that decodes a raw byte stream into SSE `data:` payloads.
196
+ * Each output chunk is the string content after `data: ` (one per SSE event),
197
+ * with line buffering for partial chunks.
198
+ */
132
199
  //#endregion
133
200
  //#region src/errors.d.ts
134
201
  /**
@@ -340,6 +407,20 @@ interface DelegateCallOptions {
340
407
  * delegate strips provider auth headers so unified billing applies.
341
408
  */
342
409
  byok?: boolean;
410
+ /**
411
+ * Gateway path only: BYOK stored-key alias to authenticate with
412
+ * (`cf-aig-byok-alias`). Selects a non-`default` key you configured for the
413
+ * provider on the gateway. Independent of `byok` (which controls whether the
414
+ * caller's own provider auth header is forwarded vs. stripped).
415
+ */
416
+ byokAlias?: string;
417
+ /**
418
+ * Per-request Zero Data Retention override (`cf-aig-zdr`), Unified Billing
419
+ * only: `true` forces ZDR-capable upstreams, `false` disables it for this
420
+ * request. Overrides the gateway-level ZDR default. Applied on both transports
421
+ * (run path: passed through gateway options as a header; gateway path: entry header).
422
+ */
423
+ zdr?: boolean;
343
424
  /** Override the delegate's gateway for this model. */
344
425
  gateway?: GatewayOptions | string;
345
426
  /**
@@ -374,12 +455,6 @@ interface Selection {
374
455
  * requested.
375
456
  */
376
457
  declare function selectTransport(opts: DelegateCallOptions, resumeExplicitlyTrue: boolean, runCatalog?: boolean, gatewayAvailable?: boolean): Selection;
377
- type GatewayDelegateErrorKind = "config" | "dispatch" | "provider" | "resume-expired";
378
- declare class GatewayDelegateError extends Error {
379
- readonly kind: GatewayDelegateErrorKind;
380
- readonly cause?: unknown;
381
- constructor(kind: GatewayDelegateErrorKind, message: string, cause?: unknown);
382
- }
383
458
  //#endregion
384
- export { WireFormat as C, wireableProviders as E, GatewayProviderInfo as S, findProviderBySlug as T, ResumableStreamOptions as _, ParsedSlug as a, Billing as b, parseSlug as c, createClientFallbackModel as d, FallbackAttempt as f, WorkersAIGatewayError as g, WorkersAIFallbackError as h, GatewayDelegateError as i, selectTransport as l, GatewayErrorContext as m, DispatchInfo as n, ProviderPlugin as o, GatewayErrorCode as p, FallbackOptions as r, Transport as s, DelegateCallOptions as t, FallbackLeg as u, ResumeExpiredPolicy as v, detectProviderByUrl as w, GATEWAY_PROVIDERS as x, createResumableStream as y };
385
- //# sourceMappingURL=gateway-delegate-BfaUTwDZ.d.mts.map
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 };
460
+ //# sourceMappingURL=gateway-delegate-D_zkIp5r.d.mts.map