workers-ai-provider 3.3.1 → 4.0.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 +23 -2
- package/dist/anthropic.d.mts +5 -1
- package/dist/anthropic.mjs +4 -0
- package/dist/anthropic.mjs.map +1 -1
- package/dist/{gateway-delegate-D_zkIp5r.d.mts → gateway-delegate-DYjgGAa-.d.mts} +9 -6
- package/dist/{gateway-provider-CQU-v2IO.mjs → gateway-provider-BQj8ZnKv.mjs} +14 -2
- package/dist/{gateway-provider-CQU-v2IO.mjs.map → gateway-provider-BQj8ZnKv.mjs.map} +1 -1
- package/dist/gateway-provider.d.mts +12 -0
- package/dist/gateway-provider.mjs +1 -1
- package/dist/google.d.mts +5 -1
- package/dist/google.mjs +6 -2
- package/dist/google.mjs.map +1 -1
- package/dist/index.d.mts +70 -31
- package/dist/index.mjs +113 -41
- package/dist/index.mjs.map +1 -1
- package/dist/openai.d.mts +8 -3
- package/dist/openai.mjs +7 -2
- package/dist/openai.mjs.map +1 -1
- package/package.json +11 -11
- package/src/aisearch-chat-language-model.ts +10 -10
- package/src/anthropic.ts +4 -0
- package/src/client-fallback.ts +14 -11
- package/src/convert-to-workersai-chat-messages.ts +69 -30
- package/src/gateway-delegate.ts +12 -12
- package/src/gateway-provider.ts +12 -0
- package/src/google.ts +6 -4
- package/src/index.ts +38 -4
- package/src/map-workersai-finish-reason.ts +2 -2
- package/src/map-workersai-usage.ts +4 -4
- package/src/openai.ts +7 -2
- package/src/streaming.ts +18 -18
- package/src/utils.ts +8 -8
- package/src/workersai-chat-language-model.ts +64 -14
- package/src/workersai-embedding-model.ts +6 -6
- package/src/workersai-image-model.ts +6 -6
- package/src/workersai-reranking-model.ts +9 -9
- package/src/workersai-speech-model.ts +7 -7
- package/src/workersai-transcription-model.ts +11 -11
package/dist/openai.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as ProviderPlugin } from "./gateway-delegate-
|
|
1
|
+
import { a as ProviderPlugin } from "./gateway-delegate-DYjgGAa-.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/openai.d.ts
|
|
4
4
|
/**
|
|
@@ -11,8 +11,13 @@ 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:
|
|
15
|
-
* defaults to the Responses API, which the AI Gateway run catalog
|
|
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.
|
|
17
|
+
*
|
|
18
|
+
* @deprecated Pass the vendor's own model to `createAI` from
|
|
19
|
+
* `agents/models/ai-sdk` instead of a plugin plus a slug:
|
|
20
|
+
* `ai(createOpenAI({ apiKey: "cloudflare" }).chat("gpt-5.4"))`.
|
|
16
21
|
*/
|
|
17
22
|
declare const openai: ProviderPlugin;
|
|
18
23
|
//#endregion
|
package/dist/openai.mjs
CHANGED
|
@@ -10,8 +10,13 @@ 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:
|
|
14
|
-
* defaults to the Responses API, which the AI Gateway run catalog
|
|
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.
|
|
16
|
+
*
|
|
17
|
+
* @deprecated Pass the vendor's own model to `createAI` from
|
|
18
|
+
* `agents/models/ai-sdk` instead of a plugin plus a slug:
|
|
19
|
+
* `ai(createOpenAI({ apiKey: "cloudflare" }).chat("gpt-5.4"))`.
|
|
15
20
|
*/
|
|
16
21
|
const openai = {
|
|
17
22
|
wireFormat: "openai",
|
package/dist/openai.mjs.map
CHANGED
|
@@ -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:
|
|
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 *\n * @deprecated Pass the vendor's own model to `createAI` from\n * `agents/models/ai-sdk` instead of a plugin plus a slug:\n * `ai(createOpenAI({ apiKey: \"cloudflare\" }).chat(\"gpt-5.4\"))`.\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":";;;;;;;;;;;;;;;;;;;;AAqBA,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
|
+
"version": "4.0.1",
|
|
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": "^
|
|
57
|
-
"@ai-sdk/google": "^
|
|
58
|
-
"@ai-sdk/openai": "^
|
|
59
|
-
"@ai-sdk/provider": "^
|
|
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": "^
|
|
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": "^
|
|
67
|
-
"@ai-sdk/google": "^
|
|
68
|
-
"@ai-sdk/openai": "^
|
|
69
|
-
"@ai-sdk/provider": "^
|
|
70
|
-
"ai": "^
|
|
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 {
|
|
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
|
|
17
|
-
readonly specificationVersion = "
|
|
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<
|
|
47
|
-
const warnings:
|
|
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<
|
|
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<
|
|
82
|
-
): Promise<Awaited<ReturnType<
|
|
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<
|
|
113
|
-
): Promise<Awaited<ReturnType<
|
|
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
|
|
package/src/anthropic.ts
CHANGED
|
@@ -7,6 +7,10 @@ import type { ProviderPlugin } from "./gateway-delegate";
|
|
|
7
7
|
* `"anthropic/<model>"` slugs.
|
|
8
8
|
*
|
|
9
9
|
* Requires `@ai-sdk/anthropic` (an optional peer dependency — install it yourself).
|
|
10
|
+
*
|
|
11
|
+
* @deprecated Pass the vendor's own model to `createAI` from
|
|
12
|
+
* `agents/models/ai-sdk` instead of a plugin plus a slug:
|
|
13
|
+
* `ai(createAnthropic({ apiKey: "cloudflare" })("claude-opus-4-8"))`.
|
|
10
14
|
*/
|
|
11
15
|
export const anthropic: ProviderPlugin = {
|
|
12
16
|
wireFormat: "anthropic",
|
package/src/client-fallback.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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:
|
|
15
|
+
model: LanguageModelV4;
|
|
16
16
|
/** Transport the leg uses. */
|
|
17
17
|
transport: Transport;
|
|
18
18
|
}
|
|
@@ -25,14 +25,17 @@ export interface FallbackLeg {
|
|
|
25
25
|
* Fallback triggers on `doGenerate`/`doStream` rejection (the dispatch never
|
|
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
|
+
*
|
|
29
|
+
* @deprecated Use the `fallback` option of `createAI` from
|
|
30
|
+
* `agents/models/ai-sdk`: `ai(primary, { fallback: [secondary, "@cf/…"] })`.
|
|
28
31
|
*/
|
|
29
|
-
export function createClientFallbackModel(legs: FallbackLeg[]):
|
|
32
|
+
export function createClientFallbackModel(legs: FallbackLeg[]): LanguageModelV4 {
|
|
30
33
|
if (legs.length === 0) {
|
|
31
34
|
throw new Error("createClientFallbackModel requires at least one model leg.");
|
|
32
35
|
}
|
|
33
36
|
const primary = legs[0].model;
|
|
34
37
|
|
|
35
|
-
async function attempt<T>(run: (model:
|
|
38
|
+
async function attempt<T>(run: (model: LanguageModelV4) => PromiseLike<T>): Promise<T> {
|
|
36
39
|
const attempts: FallbackAttempt[] = [];
|
|
37
40
|
for (const leg of legs) {
|
|
38
41
|
try {
|
|
@@ -54,16 +57,16 @@ export function createClientFallbackModel(legs: FallbackLeg[]): LanguageModelV3
|
|
|
54
57
|
}
|
|
55
58
|
|
|
56
59
|
return {
|
|
57
|
-
specificationVersion: "
|
|
60
|
+
specificationVersion: "v4",
|
|
58
61
|
provider: primary.provider,
|
|
59
62
|
modelId: primary.modelId,
|
|
60
63
|
supportedUrls: primary.supportedUrls,
|
|
61
64
|
doGenerate(
|
|
62
|
-
options:
|
|
63
|
-
): PromiseLike<
|
|
65
|
+
options: LanguageModelV4CallOptions,
|
|
66
|
+
): PromiseLike<LanguageModelV4GenerateResult> {
|
|
64
67
|
return attempt((m) => m.doGenerate(options));
|
|
65
68
|
},
|
|
66
|
-
doStream(options:
|
|
69
|
+
doStream(options: LanguageModelV4CallOptions): PromiseLike<LanguageModelV4StreamResult> {
|
|
67
70
|
return attempt((m) => m.doStream(options));
|
|
68
71
|
},
|
|
69
72
|
};
|
|
@@ -1,45 +1,72 @@
|
|
|
1
|
-
import type {
|
|
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
|
|
7
|
+
* Normalise a tagged `SharedV4FileData` value to a Uint8Array.
|
|
8
8
|
*
|
|
9
9
|
* Handles:
|
|
10
|
-
* -
|
|
11
|
-
*
|
|
12
|
-
* -
|
|
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(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
|
|
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:
|
|
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: {
|
package/src/gateway-delegate.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
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
|
-
}):
|
|
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):
|
|
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:
|
|
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
|
-
}):
|
|
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:
|
|
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:
|
|
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:
|
|
908
|
+
return (winnerModel[method] as (o: LanguageModelV4CallOptions) => Promise<unknown>)(
|
|
909
909
|
options,
|
|
910
910
|
);
|
|
911
911
|
};
|
|
912
912
|
|
|
913
913
|
return {
|
|
914
|
-
specificationVersion: "
|
|
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<
|
|
919
|
+
return dispatch("doGenerate", options) as ReturnType<LanguageModelV4["doGenerate"]>;
|
|
920
920
|
},
|
|
921
921
|
doStream(options) {
|
|
922
|
-
return dispatch("doStream", options) as ReturnType<
|
|
922
|
+
return dispatch("doStream", options) as ReturnType<LanguageModelV4["doStream"]>;
|
|
923
923
|
},
|
|
924
|
-
} as
|
|
924
|
+
} as LanguageModelV4;
|
|
925
925
|
}
|
package/src/gateway-provider.ts
CHANGED
|
@@ -56,6 +56,12 @@ interface AiGatewayRunner {
|
|
|
56
56
|
* A `fetch` that dispatches the wrapped provider's request through AI Gateway.
|
|
57
57
|
* Detects the gateway provider id from the request URL (or uses `config.provider`),
|
|
58
58
|
* strips the provider host to the endpoint path, and forwards the body verbatim.
|
|
59
|
+
*
|
|
60
|
+
* @deprecated Route the vendor's model with `createAI` from
|
|
61
|
+
* `agents/models/ai-sdk`: `ai(model)` for language models, `ai.routed(model)`
|
|
62
|
+
* for embedding, image, speech and transcription models, on AI Gateway's
|
|
63
|
+
* provider-native path. `vendorKey: "request"` forwards the vendor key, as
|
|
64
|
+
* `byok: true` does here.
|
|
59
65
|
*/
|
|
60
66
|
export function createGatewayFetch(config: GatewayFetchConfig): typeof globalThis.fetch {
|
|
61
67
|
if (!config?.binding) {
|
|
@@ -130,6 +136,12 @@ export function createGatewayFetch(config: GatewayFetchConfig): typeof globalThi
|
|
|
130
136
|
* });
|
|
131
137
|
* const model = openai("gpt-5");
|
|
132
138
|
* ```
|
|
139
|
+
*
|
|
140
|
+
* @deprecated Route the vendor's model with `createAI` from
|
|
141
|
+
* `agents/models/ai-sdk`: `ai(model)` for language models, `ai.routed(model)`
|
|
142
|
+
* for embedding, image, speech and transcription models, on AI Gateway's
|
|
143
|
+
* provider-native path. `vendorKey: "request"` forwards the vendor key, as
|
|
144
|
+
* `byok: true` does here.
|
|
133
145
|
*/
|
|
134
146
|
export function createGatewayProvider<T>(
|
|
135
147
|
factory: (opts: { apiKey?: string; baseURL?: string; fetch: typeof globalThis.fetch }) => T,
|
package/src/google.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createGoogle } from "@ai-sdk/google";
|
|
2
2
|
import type { ProviderPlugin } from "./gateway-delegate";
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -7,13 +7,15 @@ import type { ProviderPlugin } from "./gateway-delegate";
|
|
|
7
7
|
* (Google AI Studio) and `"google-vertex/<model>"` slugs.
|
|
8
8
|
*
|
|
9
9
|
* Requires `@ai-sdk/google` (an optional peer dependency — install it yourself).
|
|
10
|
+
*
|
|
11
|
+
* @deprecated Pass the vendor's own model to `createAI` from
|
|
12
|
+
* `agents/models/ai-sdk` instead of a plugin plus a slug:
|
|
13
|
+
* `ai(createGoogle({ apiKey: "cloudflare" })("gemini-2.5-flash"))`.
|
|
10
14
|
*/
|
|
11
15
|
export const google: ProviderPlugin = {
|
|
12
16
|
wireFormat: "google",
|
|
13
17
|
create: ({ modelId, fetch, baseURL }) =>
|
|
14
18
|
// apiKey is a placeholder — the gateway handles auth (unified billing / BYOK)
|
|
15
19
|
// and the delegate strips the x-goog-api-key header on the gateway path.
|
|
16
|
-
|
|
17
|
-
modelId,
|
|
18
|
-
),
|
|
20
|
+
createGoogle({ apiKey: "unused", fetch, ...(baseURL ? { baseURL } : {}) })(modelId),
|
|
19
21
|
};
|
package/src/index.ts
CHANGED
|
@@ -276,6 +276,23 @@ export interface WorkersAI {
|
|
|
276
276
|
|
|
277
277
|
/**
|
|
278
278
|
* Create a Workers AI provider instance.
|
|
279
|
+
*
|
|
280
|
+
* @deprecated Use `createAI` from `agents/models/ai-sdk`, with the binding or
|
|
281
|
+
* with an account id and API token (credentials mode's `apiKey`):
|
|
282
|
+
*
|
|
283
|
+
* ```ts
|
|
284
|
+
* import { createAI } from "agents/models/ai-sdk";
|
|
285
|
+
* const ai = createAI({ binding: env.AI }); // or { accountId, apiToken }
|
|
286
|
+
* ai("@cf/zai-org/glm-4.7-flash"); // was workersai("@cf/…")
|
|
287
|
+
* ai("anthropic/claude-opus-4.8"); // was "anthropic/…" + providers; the catalog's spelling
|
|
288
|
+
* ai("dynamic/support"); // dynamic routes, as before
|
|
289
|
+
* ai(createAnthropic({ apiKey: "cloudflare" })("claude-opus-4-8")); // a vendor's own model
|
|
290
|
+
* ai.embedding("@cf/baai/bge-base-en-v1.5"); // .image/.speech/.transcription/.reranking alike
|
|
291
|
+
* ```
|
|
292
|
+
*
|
|
293
|
+
* `vendorKey`, `byokAlias` and `zdr` cover BYOK, and through the binding a
|
|
294
|
+
* catalog stream resumes after a dropped connection. For AI Search, use
|
|
295
|
+
* `ai-search-provider`.
|
|
279
296
|
*/
|
|
280
297
|
export function createWorkersAI(options: WorkersAISettings): WorkersAI {
|
|
281
298
|
if (!options.binding && !("accountId" in options && "apiKey" in options)) {
|
|
@@ -508,7 +525,7 @@ export function createWorkersAI(options: WorkersAISettings): WorkersAI {
|
|
|
508
525
|
"catalog",
|
|
509
526
|
);
|
|
510
527
|
}
|
|
511
|
-
// The delegate returns a `
|
|
528
|
+
// The delegate returns a `LanguageModelV4` built by the configured plugin.
|
|
512
529
|
// It's structurally compatible with the AI SDK consumers this provider is
|
|
513
530
|
// used with; the cast keeps the public return type unchanged.
|
|
514
531
|
return getDelegate(modelId)(
|
|
@@ -600,10 +617,22 @@ export function createWorkersAI(options: WorkersAISettings): WorkersAI {
|
|
|
600
617
|
// AI Search (formerly AutoRAG)
|
|
601
618
|
// ---------------------------------------------------------------------------
|
|
602
619
|
|
|
620
|
+
/**
|
|
621
|
+
* @deprecated Use `createAISearchNamespace` from `ai-search-provider`, over the
|
|
622
|
+
* `ai_search_namespaces` binding that replaces `env.AI.autorag()`:
|
|
623
|
+
* `createAISearchNamespace({ binding: env.AI_SEARCH }).get("my-instance").chat()`.
|
|
624
|
+
* @see https://developers.cloudflare.com/ai-search/api/migration/workers-binding/
|
|
625
|
+
*/
|
|
603
626
|
export type AISearchSettings = {
|
|
604
627
|
binding: AutoRAG;
|
|
605
628
|
};
|
|
606
629
|
|
|
630
|
+
/**
|
|
631
|
+
* @deprecated Use `createAISearchNamespace` from `ai-search-provider`, over the
|
|
632
|
+
* `ai_search_namespaces` binding that replaces `env.AI.autorag()`:
|
|
633
|
+
* `createAISearchNamespace({ binding: env.AI_SEARCH }).get("my-instance").chat()`.
|
|
634
|
+
* @see https://developers.cloudflare.com/ai-search/api/migration/workers-binding/
|
|
635
|
+
*/
|
|
607
636
|
export interface AISearchProvider {
|
|
608
637
|
(settings?: AISearchChatSettings): AISearchChatLanguageModel;
|
|
609
638
|
/**
|
|
@@ -616,7 +645,11 @@ export interface AISearchProvider {
|
|
|
616
645
|
* Create an AI Search provider instance.
|
|
617
646
|
*
|
|
618
647
|
* AI Search (formerly AutoRAG) is Cloudflare's managed search service.
|
|
619
|
-
*
|
|
648
|
+
*
|
|
649
|
+
* @deprecated Use `createAISearchNamespace` from `ai-search-provider`, over the
|
|
650
|
+
* `ai_search_namespaces` binding that replaces `env.AI.autorag()`:
|
|
651
|
+
* `createAISearchNamespace({ binding: env.AI_SEARCH }).get("my-instance").chat()`.
|
|
652
|
+
* @see https://developers.cloudflare.com/ai-search/api/migration/workers-binding/
|
|
620
653
|
*/
|
|
621
654
|
export function createAISearch(
|
|
622
655
|
options: AISearchSettings,
|
|
@@ -662,8 +695,9 @@ export type AutoRAGProvider = AISearchProvider;
|
|
|
662
695
|
let autoRAGWarned = false;
|
|
663
696
|
|
|
664
697
|
/**
|
|
665
|
-
* @deprecated Use `
|
|
666
|
-
*
|
|
698
|
+
* @deprecated Use `createAISearchNamespace` from `ai-search-provider`. AutoRAG
|
|
699
|
+
* has been renamed to AI Search.
|
|
700
|
+
* @see https://developers.cloudflare.com/ai-search/api/migration/workers-binding/
|
|
667
701
|
*/
|
|
668
702
|
export function createAutoRAG(options: AISearchSettings): AISearchProvider {
|
|
669
703
|
if (!autoRAGWarned) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
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
|
-
):
|
|
12
|
+
): LanguageModelV4FinishReason {
|
|
13
13
|
let finishReason: string | null | undefined;
|
|
14
14
|
|
|
15
15
|
if (
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { LanguageModelV4Usage } from "@ai-sdk/provider";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Map Workers AI usage data to the AI SDK
|
|
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
|
-
):
|
|
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
|
|
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,13 @@ 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:
|
|
15
|
-
* defaults to the Responses API, which the AI Gateway run catalog
|
|
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.
|
|
17
|
+
*
|
|
18
|
+
* @deprecated Pass the vendor's own model to `createAI` from
|
|
19
|
+
* `agents/models/ai-sdk` instead of a plugin plus a slug:
|
|
20
|
+
* `ai(createOpenAI({ apiKey: "cloudflare" }).chat("gpt-5.4"))`.
|
|
16
21
|
*/
|
|
17
22
|
export const openai: ProviderPlugin = {
|
|
18
23
|
wireFormat: "openai",
|