workers-ai-provider 3.3.1 → 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/dist/openai.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as ProviderPlugin } from "./gateway-delegate-D_zkIp5r.mjs";
1
+ import { a as ProviderPlugin } from "./gateway-delegate-CAX7trdL.mjs";
2
2
 
3
3
  //#region src/openai.d.ts
4
4
  /**
@@ -11,8 +11,9 @@ import { a as ProviderPlugin } from "./gateway-delegate-D_zkIp5r.mjs";
11
11
  *
12
12
  * Requires `@ai-sdk/openai` (an optional peer dependency — install it yourself).
13
13
  *
14
- * Uses `.chat()` (Chat Completions) deliberately: AI SDK v6's bare `openai()`
15
- * defaults to the Responses API, which the AI Gateway run catalog does not serve.
14
+ * Uses `.chat()` (Chat Completions) deliberately: the bare `openai()` call
15
+ * (AI SDK v6+) defaults to the Responses API, which the AI Gateway run catalog
16
+ * does not serve.
16
17
  */
17
18
  declare const openai: ProviderPlugin;
18
19
  //#endregion
package/dist/openai.mjs CHANGED
@@ -10,8 +10,9 @@ import { createOpenAI } from "@ai-sdk/openai";
10
10
  *
11
11
  * Requires `@ai-sdk/openai` (an optional peer dependency — install it yourself).
12
12
  *
13
- * Uses `.chat()` (Chat Completions) deliberately: AI SDK v6's bare `openai()`
14
- * defaults to the Responses API, which the AI Gateway run catalog does not serve.
13
+ * Uses `.chat()` (Chat Completions) deliberately: the bare `openai()` call
14
+ * (AI SDK v6+) defaults to the Responses API, which the AI Gateway run catalog
15
+ * does not serve.
15
16
  */
16
17
  const openai = {
17
18
  wireFormat: "openai",
@@ -1 +1 @@
1
- {"version":3,"file":"openai.mjs","names":[],"sources":["../src/openai.ts"],"sourcesContent":["import { createOpenAI } from \"@ai-sdk/openai\";\nimport type { ProviderPlugin } from \"./gateway-delegate\";\n\n/**\n * OpenAI-wire provider plugin for the gateway delegate. Pass to\n * `createGatewayDelegate({ providers: [openai] })` to handle every\n * OpenAI-compatible provider in one go — `openai/…`, plus the OpenAI-compatible\n * long tail (`deepseek/…`, `xai/…`, `groq/…`, `mistral/…`, `perplexity/…`,\n * `openrouter/…`, `cohere/…`, …). The registry routes each slug to its gateway\n * provider id; this plugin only supplies the response parser.\n *\n * Requires `@ai-sdk/openai` (an optional peer dependency — install it yourself).\n *\n * Uses `.chat()` (Chat Completions) deliberately: AI SDK v6's bare `openai()`\n * defaults to the Responses API, which the AI Gateway run catalog does not serve.\n */\nexport const openai: ProviderPlugin = {\n\twireFormat: \"openai\",\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 Authorization header on the gateway path.\n\t\t// baseURL (set by the registry for non-OpenAI openai-wire providers) makes\n\t\t// the generated URL host-strip to the right gateway-native endpoint.\n\t\tcreateOpenAI({ apiKey: \"unused\", fetch, ...(baseURL ? { baseURL } : {}) }).chat(modelId),\n};\n"],"mappings":";;;;;;;;;;;;;;;AAgBA,MAAa,SAAyB;CACrC,YAAY;CACZ,SAAS,EAAE,SAAS,OAAO,cAK1B,aAAa;EAAE,QAAQ;EAAU;EAAO,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;CAAG,CAAC,CAAC,CAAC,KAAK,OAAO;AACzF"}
1
+ {"version":3,"file":"openai.mjs","names":[],"sources":["../src/openai.ts"],"sourcesContent":["import { createOpenAI } from \"@ai-sdk/openai\";\nimport type { ProviderPlugin } from \"./gateway-delegate\";\n\n/**\n * OpenAI-wire provider plugin for the gateway delegate. Pass to\n * `createGatewayDelegate({ providers: [openai] })` to handle every\n * OpenAI-compatible provider in one go — `openai/…`, plus the OpenAI-compatible\n * long tail (`deepseek/…`, `xai/…`, `groq/…`, `mistral/…`, `perplexity/…`,\n * `openrouter/…`, `cohere/…`, …). The registry routes each slug to its gateway\n * provider id; this plugin only supplies the response parser.\n *\n * Requires `@ai-sdk/openai` (an optional peer dependency — install it yourself).\n *\n * Uses `.chat()` (Chat Completions) deliberately: the bare `openai()` call\n * (AI SDK v6+) defaults to the Responses API, which the AI Gateway run catalog\n * does not serve.\n */\nexport const openai: ProviderPlugin = {\n\twireFormat: \"openai\",\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 Authorization header on the gateway path.\n\t\t// baseURL (set by the registry for non-OpenAI openai-wire providers) makes\n\t\t// the generated URL host-strip to the right gateway-native endpoint.\n\t\tcreateOpenAI({ apiKey: \"unused\", fetch, ...(baseURL ? { baseURL } : {}) }).chat(modelId),\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAiBA,MAAa,SAAyB;CACrC,YAAY;CACZ,SAAS,EAAE,SAAS,OAAO,cAK1B,aAAa;EAAE,QAAQ;EAAU;EAAO,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;CAAG,CAAC,CAAC,CAAC,KAAK,OAAO;AACzF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "workers-ai-provider",
3
- "version": "3.3.1",
3
+ "version": "4.0.0",
4
4
  "description": "Workers AI Provider for the vercel AI SDK",
5
5
  "keywords": [
6
6
  "ai",
@@ -53,21 +53,21 @@
53
53
  "./package.json": "./package.json"
54
54
  },
55
55
  "devDependencies": {
56
- "@ai-sdk/anthropic": "^3.0.84",
57
- "@ai-sdk/google": "^3.0.0",
58
- "@ai-sdk/openai": "^3.0.71",
59
- "@ai-sdk/provider": "^3.0.10",
56
+ "@ai-sdk/anthropic": "^4.0.5",
57
+ "@ai-sdk/google": "^4.0.6",
58
+ "@ai-sdk/openai": "^4.0.5",
59
+ "@ai-sdk/provider": "^4.0.1",
60
60
  "@cloudflare/workers-types": "^4.20260628.1",
61
- "ai": "^6.0.204",
61
+ "ai": "^7.0.11",
62
62
  "zod": "^4.4.3",
63
63
  "@cloudflare/gateway-core": "0.0.0"
64
64
  },
65
65
  "peerDependencies": {
66
- "@ai-sdk/anthropic": "^3.0.0",
67
- "@ai-sdk/google": "^3.0.0",
68
- "@ai-sdk/openai": "^3.0.0",
69
- "@ai-sdk/provider": "^3.0.0",
70
- "ai": "^6.0.0"
66
+ "@ai-sdk/anthropic": "^4.0.0",
67
+ "@ai-sdk/google": "^4.0.0",
68
+ "@ai-sdk/openai": "^4.0.0",
69
+ "@ai-sdk/provider": "^4.0.0",
70
+ "ai": "^7.0.0"
71
71
  },
72
72
  "peerDependenciesMeta": {
73
73
  "@ai-sdk/anthropic": {
@@ -1,4 +1,4 @@
1
- import type { LanguageModelV3, SharedV3Warning } from "@ai-sdk/provider";
1
+ import type { LanguageModelV4, SharedV4Warning } from "@ai-sdk/provider";
2
2
 
3
3
  import type { AISearchChatSettings } from "./aisearch-chat-settings";
4
4
  import { convertToWorkersAIChatMessages } from "./convert-to-workersai-chat-messages";
@@ -13,8 +13,8 @@ type AISearchChatConfig = {
13
13
  gateway?: GatewayOptions;
14
14
  };
15
15
 
16
- export class AISearchChatLanguageModel implements LanguageModelV3 {
17
- readonly specificationVersion = "v3";
16
+ export class AISearchChatLanguageModel implements LanguageModelV4 {
17
+ readonly specificationVersion = "v4";
18
18
  readonly defaultObjectGenerationMode = "json";
19
19
 
20
20
  readonly supportedUrls: Record<string, RegExp[]> | PromiseLike<Record<string, RegExp[]>> = {};
@@ -43,8 +43,8 @@ export class AISearchChatLanguageModel implements LanguageModelV3 {
43
43
  frequencyPenalty,
44
44
  presencePenalty,
45
45
  responseFormat,
46
- }: Parameters<LanguageModelV3["doGenerate"]>[0]): SharedV3Warning[] {
47
- const warnings: SharedV3Warning[] = [];
46
+ }: Parameters<LanguageModelV4["doGenerate"]>[0]): SharedV4Warning[] {
47
+ const warnings: SharedV4Warning[] = [];
48
48
 
49
49
  if (tools != null && tools.length > 0) {
50
50
  console.warn(
@@ -72,14 +72,14 @@ export class AISearchChatLanguageModel implements LanguageModelV3 {
72
72
  * Build the search query from messages.
73
73
  * Flattens the conversation into a single string for aiSearch.
74
74
  */
75
- private buildQuery(prompt: Parameters<LanguageModelV3["doGenerate"]>[0]["prompt"]): string {
75
+ private buildQuery(prompt: Parameters<LanguageModelV4["doGenerate"]>[0]["prompt"]): string {
76
76
  const { messages } = convertToWorkersAIChatMessages(prompt);
77
77
  return messages.map(({ content, role }) => `${role}: ${content}`).join("\n\n");
78
78
  }
79
79
 
80
80
  async doGenerate(
81
- options: Parameters<LanguageModelV3["doGenerate"]>[0],
82
- ): Promise<Awaited<ReturnType<LanguageModelV3["doGenerate"]>>> {
81
+ options: Parameters<LanguageModelV4["doGenerate"]>[0],
82
+ ): Promise<Awaited<ReturnType<LanguageModelV4["doGenerate"]>>> {
83
83
  const warnings = this.getWarnings(options);
84
84
  const query = this.buildQuery(options.prompt);
85
85
 
@@ -109,8 +109,8 @@ export class AISearchChatLanguageModel implements LanguageModelV3 {
109
109
  }
110
110
 
111
111
  async doStream(
112
- options: Parameters<LanguageModelV3["doStream"]>[0],
113
- ): Promise<Awaited<ReturnType<LanguageModelV3["doStream"]>>> {
112
+ options: Parameters<LanguageModelV4["doStream"]>[0],
113
+ ): Promise<Awaited<ReturnType<LanguageModelV4["doStream"]>>> {
114
114
  const warnings = this.getWarnings(options);
115
115
  const query = this.buildQuery(options.prompt);
116
116
 
@@ -1,8 +1,8 @@
1
1
  import type {
2
- LanguageModelV3,
3
- LanguageModelV3CallOptions,
4
- LanguageModelV3GenerateResult,
5
- LanguageModelV3StreamResult,
2
+ LanguageModelV4,
3
+ LanguageModelV4CallOptions,
4
+ LanguageModelV4GenerateResult,
5
+ LanguageModelV4StreamResult,
6
6
  } from "@ai-sdk/provider";
7
7
  import { type FallbackAttempt, WorkersAIFallbackError, WorkersAIGatewayError } from "./errors";
8
8
  import type { Transport } from "./gateway-delegate";
@@ -12,7 +12,7 @@ export interface FallbackLeg {
12
12
  /** The model slug this leg dispatches. */
13
13
  slug: string;
14
14
  /** The built AI SDK model. */
15
- model: LanguageModelV3;
15
+ model: LanguageModelV4;
16
16
  /** Transport the leg uses. */
17
17
  transport: Transport;
18
18
  }
@@ -26,13 +26,13 @@ export interface FallbackLeg {
26
26
  * produced a stream). Errors that surface *mid-stream* — after content has
27
27
  * already been emitted — are not recoverable here and propagate as-is.
28
28
  */
29
- export function createClientFallbackModel(legs: FallbackLeg[]): LanguageModelV3 {
29
+ export function createClientFallbackModel(legs: FallbackLeg[]): LanguageModelV4 {
30
30
  if (legs.length === 0) {
31
31
  throw new Error("createClientFallbackModel requires at least one model leg.");
32
32
  }
33
33
  const primary = legs[0].model;
34
34
 
35
- async function attempt<T>(run: (model: LanguageModelV3) => PromiseLike<T>): Promise<T> {
35
+ async function attempt<T>(run: (model: LanguageModelV4) => PromiseLike<T>): Promise<T> {
36
36
  const attempts: FallbackAttempt[] = [];
37
37
  for (const leg of legs) {
38
38
  try {
@@ -54,16 +54,16 @@ export function createClientFallbackModel(legs: FallbackLeg[]): LanguageModelV3
54
54
  }
55
55
 
56
56
  return {
57
- specificationVersion: "v3",
57
+ specificationVersion: "v4",
58
58
  provider: primary.provider,
59
59
  modelId: primary.modelId,
60
60
  supportedUrls: primary.supportedUrls,
61
61
  doGenerate(
62
- options: LanguageModelV3CallOptions,
63
- ): PromiseLike<LanguageModelV3GenerateResult> {
62
+ options: LanguageModelV4CallOptions,
63
+ ): PromiseLike<LanguageModelV4GenerateResult> {
64
64
  return attempt((m) => m.doGenerate(options));
65
65
  },
66
- doStream(options: LanguageModelV3CallOptions): PromiseLike<LanguageModelV3StreamResult> {
66
+ doStream(options: LanguageModelV4CallOptions): PromiseLike<LanguageModelV4StreamResult> {
67
67
  return attempt((m) => m.doStream(options));
68
68
  },
69
69
  };
@@ -1,45 +1,72 @@
1
- import type { LanguageModelV3DataContent, LanguageModelV3Prompt } from "@ai-sdk/provider";
1
+ import type { LanguageModelV4Prompt, SharedV4FileData } from "@ai-sdk/provider";
2
2
  import { UnsupportedFunctionalityError } from "@ai-sdk/provider";
3
3
  import { toWorkersAIToolCallId } from "./utils";
4
4
  import type { WorkersAIContentPart, WorkersAIChatPrompt } from "./workersai-chat-prompt";
5
5
 
6
6
  /**
7
- * Normalise any LanguageModelV3DataContent value to a Uint8Array.
7
+ * Normalise a tagged `SharedV4FileData` value to a Uint8Array.
8
8
  *
9
9
  * Handles:
10
- * - Uint8Array → returned as-is
11
- * - string → decoded from base64 (with or without data-URL prefix)
12
- * - URL → not supported (Workers AI needs raw bytes, not a reference)
10
+ * - { type: 'data' } Uint8Array returned as-is; string decoded from
11
+ * base64 (with or without data-URL prefix)
12
+ * - { type: 'url' } → not supported (Workers AI needs raw bytes, not a reference)
13
+ * - { type: 'reference' } → not supported (Workers AI has no file store to resolve it)
14
+ * - { type: 'text' } → not supported for image parts
13
15
  */
14
- function toUint8Array(data: LanguageModelV3DataContent): Uint8Array | null {
15
- if (data instanceof Uint8Array) {
16
- return data;
17
- }
18
-
19
- if (typeof data === "string") {
20
- let base64 = data;
21
- if (base64.startsWith("data:")) {
22
- const commaIndex = base64.indexOf(",");
23
- if (commaIndex >= 0) {
24
- base64 = base64.slice(commaIndex + 1);
16
+ function toUint8Array(fileData: SharedV4FileData): Uint8Array | null {
17
+ switch (fileData.type) {
18
+ case "data": {
19
+ const data = fileData.data;
20
+ if (data instanceof Uint8Array) {
21
+ return data;
22
+ }
23
+ let base64 = data;
24
+ if (base64.startsWith("data:")) {
25
+ const commaIndex = base64.indexOf(",");
26
+ if (commaIndex >= 0) {
27
+ base64 = base64.slice(commaIndex + 1);
28
+ }
29
+ }
30
+ const binaryString = atob(base64);
31
+ const bytes = new Uint8Array(binaryString.length);
32
+ for (let i = 0; i < binaryString.length; i++) {
33
+ bytes[i] = binaryString.charCodeAt(i);
25
34
  }
35
+ return bytes;
26
36
  }
27
- const binaryString = atob(base64);
28
- const bytes = new Uint8Array(binaryString.length);
29
- for (let i = 0; i < binaryString.length; i++) {
30
- bytes[i] = binaryString.charCodeAt(i);
37
+
38
+ case "url": {
39
+ throw new Error(
40
+ "URL image sources are not supported by Workers AI. " +
41
+ "Provide image data as a Uint8Array or base64 string instead.",
42
+ );
31
43
  }
32
- return bytes;
33
- }
34
44
 
35
- if (data instanceof URL) {
36
- throw new Error(
37
- "URL image sources are not supported by Workers AI. " +
38
- "Provide image data as a Uint8Array or base64 string instead.",
39
- );
40
- }
45
+ case "reference": {
46
+ throw new UnsupportedFunctionalityError({
47
+ functionality: "file-part-provider-reference",
48
+ message:
49
+ "Provider file references are not supported by Workers AI. " +
50
+ "Provide image data as a Uint8Array or base64 string instead.",
51
+ });
52
+ }
41
53
 
42
- return null;
54
+ case "text": {
55
+ throw new UnsupportedFunctionalityError({
56
+ functionality: "file-part-inline-text",
57
+ message:
58
+ "Inline text file parts are not supported by Workers AI chat. " +
59
+ "Pass text as a regular text part instead.",
60
+ });
61
+ }
62
+
63
+ default: {
64
+ const exhaustiveCheck = fileData satisfies never;
65
+ throw new Error(
66
+ `Unsupported file data type: ${(exhaustiveCheck as { type: string }).type}`,
67
+ );
68
+ }
69
+ }
43
70
  }
44
71
 
45
72
  function assertImageMediaType(mediaType: string | undefined): string {
@@ -76,7 +103,7 @@ function uint8ArrayToBase64(bytes: Uint8Array): string {
76
103
  return btoa(binary);
77
104
  }
78
105
 
79
- export function convertToWorkersAIChatMessages(prompt: LanguageModelV3Prompt): {
106
+ export function convertToWorkersAIChatMessages(prompt: LanguageModelV4Prompt): {
80
107
  messages: WorkersAIChatPrompt;
81
108
  } {
82
109
  const messages: WorkersAIChatPrompt = [];
@@ -164,6 +191,18 @@ export function convertToWorkersAIChatMessages(prompt: LanguageModelV3Prompt): {
164
191
  break;
165
192
  }
166
193
 
194
+ case "reasoning-file": {
195
+ // Files inside reasoning traces (new in spec v4) cannot be
196
+ // replayed to Workers AI - no action needed
197
+ break;
198
+ }
199
+
200
+ case "custom": {
201
+ // Provider-specific custom parts (new in spec v4) from other
202
+ // providers are not replayable to Workers AI - no action needed
203
+ break;
204
+ }
205
+
167
206
  case "tool-call": {
168
207
  toolCalls.push({
169
208
  function: {
@@ -1,4 +1,4 @@
1
- import type { LanguageModelV3, LanguageModelV3CallOptions } from "@ai-sdk/provider";
1
+ import type { LanguageModelV4, LanguageModelV4CallOptions } from "@ai-sdk/provider";
2
2
  import {
3
3
  asText,
4
4
  buildGatewayEntry,
@@ -154,7 +154,7 @@ export interface ProviderPlugin {
154
154
  modelId: string;
155
155
  fetch: typeof globalThis.fetch;
156
156
  baseURL?: string;
157
- }): LanguageModelV3;
157
+ }): LanguageModelV4;
158
158
  }
159
159
 
160
160
  // ---------------------------------------------------------------------------
@@ -401,7 +401,7 @@ export interface GatewayDelegateConfig {
401
401
  }
402
402
 
403
403
  export interface GatewayDelegate {
404
- (slug: string, options?: DelegateCallOptions): LanguageModelV3;
404
+ (slug: string, options?: DelegateCallOptions): LanguageModelV4;
405
405
  }
406
406
 
407
407
  /**
@@ -431,7 +431,7 @@ export function createGatewayDelegate(config: GatewayDelegateConfig): GatewayDel
431
431
  const buildOne = (
432
432
  slug: string,
433
433
  options: DelegateCallOptions,
434
- ): { model: LanguageModelV3; transport: Transport } => {
434
+ ): { model: LanguageModelV4; transport: Transport } => {
435
435
  const parsed = parseSlug(slug);
436
436
  const info = resolveProvider(slug, parsed);
437
437
 
@@ -816,7 +816,7 @@ function makeServerFallbackModel(params: {
816
816
  opts: DelegateCallOptions;
817
817
  selection: Selection;
818
818
  callOptions: DelegateCallOptions;
819
- }): LanguageModelV3 {
819
+ }): LanguageModelV4 {
820
820
  const { binding, gatewayId, gatewayOptions, legs, opts, selection, callOptions } = params;
821
821
  const first = legs[0]!;
822
822
 
@@ -834,7 +834,7 @@ function makeServerFallbackModel(params: {
834
834
 
835
835
  const dispatch = async (
836
836
  method: "doGenerate" | "doStream",
837
- options: LanguageModelV3CallOptions,
837
+ options: LanguageModelV4CallOptions,
838
838
  ): Promise<unknown> => {
839
839
  // 1) Capture each leg's native request without hitting the network.
840
840
  const entries: GatewayEntry[] = [];
@@ -854,7 +854,7 @@ function makeServerFallbackModel(params: {
854
854
  ...(leg.info.baseURL ? { baseURL: leg.info.baseURL } : {}),
855
855
  });
856
856
  try {
857
- await (model[method] as (o: LanguageModelV3CallOptions) => Promise<unknown>)(
857
+ await (model[method] as (o: LanguageModelV4CallOptions) => Promise<unknown>)(
858
858
  options,
859
859
  );
860
860
  } catch (e) {
@@ -905,21 +905,21 @@ function makeServerFallbackModel(params: {
905
905
  fetch: (async () => resp) as typeof globalThis.fetch,
906
906
  ...(winner.info.baseURL ? { baseURL: winner.info.baseURL } : {}),
907
907
  });
908
- return (winnerModel[method] as (o: LanguageModelV3CallOptions) => Promise<unknown>)(
908
+ return (winnerModel[method] as (o: LanguageModelV4CallOptions) => Promise<unknown>)(
909
909
  options,
910
910
  );
911
911
  };
912
912
 
913
913
  return {
914
- specificationVersion: "v3",
914
+ specificationVersion: "v4",
915
915
  provider: refModel.provider,
916
916
  modelId: refModel.modelId,
917
917
  supportedUrls: refModel.supportedUrls,
918
918
  doGenerate(options) {
919
- return dispatch("doGenerate", options) as ReturnType<LanguageModelV3["doGenerate"]>;
919
+ return dispatch("doGenerate", options) as ReturnType<LanguageModelV4["doGenerate"]>;
920
920
  },
921
921
  doStream(options) {
922
- return dispatch("doStream", options) as ReturnType<LanguageModelV3["doStream"]>;
922
+ return dispatch("doStream", options) as ReturnType<LanguageModelV4["doStream"]>;
923
923
  },
924
- } as LanguageModelV3;
924
+ } as LanguageModelV4;
925
925
  }
package/src/google.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { createGoogleGenerativeAI } from "@ai-sdk/google";
1
+ import { createGoogle } from "@ai-sdk/google";
2
2
  import type { ProviderPlugin } from "./gateway-delegate";
3
3
 
4
4
  /**
@@ -13,7 +13,5 @@ export const google: ProviderPlugin = {
13
13
  create: ({ modelId, fetch, baseURL }) =>
14
14
  // apiKey is a placeholder — the gateway handles auth (unified billing / BYOK)
15
15
  // and the delegate strips the x-goog-api-key header on the gateway path.
16
- createGoogleGenerativeAI({ apiKey: "unused", fetch, ...(baseURL ? { baseURL } : {}) })(
17
- modelId,
18
- ),
16
+ createGoogle({ apiKey: "unused", fetch, ...(baseURL ? { baseURL } : {}) })(modelId),
19
17
  };
package/src/index.ts CHANGED
@@ -508,7 +508,7 @@ export function createWorkersAI(options: WorkersAISettings): WorkersAI {
508
508
  "catalog",
509
509
  );
510
510
  }
511
- // The delegate returns a `LanguageModelV3` built by the configured plugin.
511
+ // The delegate returns a `LanguageModelV4` built by the configured plugin.
512
512
  // It's structurally compatible with the AI SDK consumers this provider is
513
513
  // used with; the cast keeps the public return type unchanged.
514
514
  return getDelegate(modelId)(
@@ -1,4 +1,4 @@
1
- import type { LanguageModelV3FinishReason } from "@ai-sdk/provider";
1
+ import type { LanguageModelV4FinishReason } from "@ai-sdk/provider";
2
2
 
3
3
  /**
4
4
  * Map a Workers AI finish reason to the AI SDK unified finish reason.
@@ -9,7 +9,7 @@ import type { LanguageModelV3FinishReason } from "@ai-sdk/provider";
9
9
  */
10
10
  export function mapWorkersAIFinishReason(
11
11
  finishReasonOrResponse: string | null | undefined | Record<string, unknown>,
12
- ): LanguageModelV3FinishReason {
12
+ ): LanguageModelV4FinishReason {
13
13
  let finishReason: string | null | undefined;
14
14
 
15
15
  if (
@@ -1,7 +1,7 @@
1
- import type { LanguageModelV3Usage } from "@ai-sdk/provider";
1
+ import type { LanguageModelV4Usage } from "@ai-sdk/provider";
2
2
 
3
3
  /**
4
- * Map Workers AI usage data to the AI SDK V3 usage format.
4
+ * Map Workers AI usage data to the AI SDK v4 usage format.
5
5
  * Accepts any object that may have a `usage` property with token counts.
6
6
  *
7
7
  * Workers AI mirrors the OpenAI usage shape, including
@@ -11,7 +11,7 @@ import type { LanguageModelV3Usage } from "@ai-sdk/provider";
11
11
  */
12
12
  export function mapWorkersAIUsage(
13
13
  output: Record<string, unknown> | AiTextGenerationOutput | AiTextToImageOutput,
14
- ): LanguageModelV3Usage {
14
+ ): LanguageModelV4Usage {
15
15
  const usage = (
16
16
  output as {
17
17
  usage?: {
@@ -30,7 +30,7 @@ export function mapWorkersAIUsage(
30
30
  const cachedTokens = usage.prompt_tokens_details?.cached_tokens;
31
31
 
32
32
  // Clamp at 0 in case the provider ever reports cached_tokens > prompt_tokens;
33
- // the v3 spec expects non-negative counts.
33
+ // the v4 spec expects non-negative counts.
34
34
  const noCache =
35
35
  cachedTokens !== undefined ? Math.max(0, promptTokens - cachedTokens) : undefined;
36
36
 
package/src/openai.ts CHANGED
@@ -11,8 +11,9 @@ import type { ProviderPlugin } from "./gateway-delegate";
11
11
  *
12
12
  * Requires `@ai-sdk/openai` (an optional peer dependency — install it yourself).
13
13
  *
14
- * Uses `.chat()` (Chat Completions) deliberately: AI SDK v6's bare `openai()`
15
- * defaults to the Responses API, which the AI Gateway run catalog does not serve.
14
+ * Uses `.chat()` (Chat Completions) deliberately: the bare `openai()` call
15
+ * (AI SDK v6+) defaults to the Responses API, which the AI Gateway run catalog
16
+ * does not serve.
16
17
  */
17
18
  export const openai: ProviderPlugin = {
18
19
  wireFormat: "openai",
package/src/streaming.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type {
2
- LanguageModelV3FinishReason,
3
- LanguageModelV3StreamPart,
4
- LanguageModelV3Usage,
2
+ LanguageModelV4FinishReason,
3
+ LanguageModelV4StreamPart,
4
+ LanguageModelV4Usage,
5
5
  } from "@ai-sdk/provider";
6
6
  import { SSEDecoder } from "@cloudflare/gateway-core";
7
7
  import { generateId } from "ai";
@@ -15,16 +15,16 @@ import {
15
15
  } from "./utils";
16
16
 
17
17
  /**
18
- * Prepend a stream-start event to an existing LanguageModelV3 stream.
18
+ * Prepend a stream-start event to an existing LanguageModelV4 stream.
19
19
  * Uses pipeThrough for proper backpressure and error propagation.
20
20
  */
21
21
  export function prependStreamStart(
22
- source: ReadableStream<LanguageModelV3StreamPart>,
23
- warnings: LanguageModelV3StreamPart extends { type: "stream-start" } ? never : unknown,
24
- ): ReadableStream<LanguageModelV3StreamPart> {
22
+ source: ReadableStream<LanguageModelV4StreamPart>,
23
+ warnings: LanguageModelV4StreamPart extends { type: "stream-start" } ? never : unknown,
24
+ ): ReadableStream<LanguageModelV4StreamPart> {
25
25
  let sentStart = false;
26
26
  return source.pipeThrough(
27
- new TransformStream<LanguageModelV3StreamPart, LanguageModelV3StreamPart>({
27
+ new TransformStream<LanguageModelV4StreamPart, LanguageModelV4StreamPart>({
28
28
  transform(chunk, controller) {
29
29
  if (!sentStart) {
30
30
  sentStart = true;
@@ -59,7 +59,7 @@ function isNullFinalizationChunk(tc: Record<string, unknown>): boolean {
59
59
  }
60
60
 
61
61
  /**
62
- * Maps a Workers AI SSE stream into AI SDK V3 LanguageModelV3StreamPart events.
62
+ * Maps a Workers AI SSE stream into AI SDK LanguageModelV4StreamPart events.
63
63
  *
64
64
  * Uses a TransformStream pipeline for proper backpressure — chunks are emitted
65
65
  * one at a time as the downstream consumer pulls, not buffered eagerly.
@@ -74,7 +74,7 @@ export function getMappedStream(
74
74
  tools: Array<{ function: { name?: string } }> | undefined;
75
75
  toolChoice: unknown;
76
76
  },
77
- ): ReadableStream<LanguageModelV3StreamPart> {
77
+ ): ReadableStream<LanguageModelV4StreamPart> {
78
78
  const rawStream =
79
79
  response instanceof ReadableStream
80
80
  ? response
@@ -97,7 +97,7 @@ export function getMappedStream(
97
97
  let anyToolCallStarted = false;
98
98
 
99
99
  // State shared across the transform
100
- let usage: LanguageModelV3Usage = {
100
+ let usage: LanguageModelV4Usage = {
101
101
  outputTokens: { total: 0, text: undefined, reasoning: undefined },
102
102
  inputTokens: {
103
103
  total: 0,
@@ -109,7 +109,7 @@ export function getMappedStream(
109
109
  };
110
110
  let textId: string | null = null;
111
111
  let reasoningId: string | null = null;
112
- let finishReason: LanguageModelV3FinishReason | null = null;
112
+ let finishReason: LanguageModelV4FinishReason | null = null;
113
113
  let receivedDone = false;
114
114
  let receivedAnyData = false;
115
115
 
@@ -125,9 +125,9 @@ export function getMappedStream(
125
125
  // Step 1: Decode bytes into SSE lines
126
126
  const sseStream = rawStream.pipeThrough(new SSEDecoder());
127
127
 
128
- // Step 2: Transform SSE events into LanguageModelV3StreamPart
128
+ // Step 2: Transform SSE events into LanguageModelV4StreamPart
129
129
  return sseStream.pipeThrough(
130
- new TransformStream<string, LanguageModelV3StreamPart>({
130
+ new TransformStream<string, LanguageModelV4StreamPart>({
131
131
  transform(data, controller) {
132
132
  if (!data || data === "[DONE]") {
133
133
  if (data === "[DONE]") receivedDone = true;
@@ -315,12 +315,12 @@ export function getMappedStream(
315
315
 
316
316
  // Detect premature termination
317
317
  const effectiveFinishReason = salvagedToolCalls
318
- ? ({ unified: "tool-calls", raw: "stop" } as LanguageModelV3FinishReason)
318
+ ? ({ unified: "tool-calls", raw: "stop" } as LanguageModelV4FinishReason)
319
319
  : !receivedDone && receivedAnyData && !finishReason
320
320
  ? ({
321
321
  unified: "error",
322
322
  raw: "stream-truncated",
323
- } as LanguageModelV3FinishReason)
323
+ } as LanguageModelV4FinishReason)
324
324
  : (finishReason ?? { unified: "stop", raw: "stop" });
325
325
 
326
326
  controller.enqueue({
@@ -337,7 +337,7 @@ export function getMappedStream(
337
337
  */
338
338
  function closeToolCall(
339
339
  index: number,
340
- controller: TransformStreamDefaultController<LanguageModelV3StreamPart>,
340
+ controller: TransformStreamDefaultController<LanguageModelV4StreamPart>,
341
341
  ) {
342
342
  const tc = activeToolCalls.get(index);
343
343
  if (!tc || closedToolCalls.has(index)) return;
@@ -367,7 +367,7 @@ export function getMappedStream(
367
367
  */
368
368
  function emitToolCallDeltas(
369
369
  toolCalls: Record<string, unknown>[],
370
- controller: TransformStreamDefaultController<LanguageModelV3StreamPart>,
370
+ controller: TransformStreamDefaultController<LanguageModelV4StreamPart>,
371
371
  ) {
372
372
  for (const tc of toolCalls) {
373
373
  if (isNullFinalizationChunk(tc)) {