workers-ai-provider 0.7.5 → 2.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 +30 -0
- package/dist/chunk-H3ZBSMAH.js +300 -0
- package/dist/chunk-H3ZBSMAH.js.map +1 -0
- package/dist/chunk-LOLDRYLH.js +35 -0
- package/dist/chunk-LOLDRYLH.js.map +1 -0
- package/dist/index.d.ts +17 -15
- package/dist/index.js +12666 -259
- package/dist/index.js.map +1 -1
- package/dist/token-4SRL5WJU.js +63 -0
- package/dist/token-4SRL5WJU.js.map +1 -0
- package/dist/token-util-24B4MTMT.js +6 -0
- package/dist/token-util-24B4MTMT.js.map +1 -0
- package/package.json +5 -5
- package/src/autorag-chat-language-model.ts +76 -54
- package/src/convert-to-workersai-chat-messages.ts +14 -12
- package/src/index.ts +9 -5
- package/src/map-workersai-finish-reason.ts +2 -2
- package/src/map-workersai-usage.ts +3 -2
- package/src/streaming.ts +53 -15
- package/src/utils.ts +14 -21
- package/src/workers-ai-embedding-model.ts +11 -9
- package/src/workersai-chat-language-model.ts +139 -69
- package/src/workersai-error.ts +1 -1
- package/src/workersai-image-model.ts +6 -6
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type EmbeddingModelV2, TooManyEmbeddingValuesForCallError } from "@ai-sdk/provider";
|
|
2
2
|
import type { StringLike } from "./utils";
|
|
3
3
|
import type { EmbeddingModels } from "./workersai-models";
|
|
4
4
|
|
|
@@ -19,12 +19,12 @@ export type WorkersAIEmbeddingSettings = {
|
|
|
19
19
|
[key: string]: StringLike;
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
-
export class WorkersAIEmbeddingModel implements
|
|
22
|
+
export class WorkersAIEmbeddingModel implements EmbeddingModelV2<string> {
|
|
23
23
|
/**
|
|
24
24
|
* Semantic version of the {@link EmbeddingModelV1} specification implemented
|
|
25
25
|
* by this class. It never changes.
|
|
26
26
|
*/
|
|
27
|
-
readonly specificationVersion = "
|
|
27
|
+
readonly specificationVersion = "v2";
|
|
28
28
|
readonly modelId: EmbeddingModels;
|
|
29
29
|
private readonly config: WorkersAIEmbeddingConfig;
|
|
30
30
|
private readonly settings: WorkersAIEmbeddingSettings;
|
|
@@ -38,7 +38,7 @@ export class WorkersAIEmbeddingModel implements EmbeddingModelV1<string> {
|
|
|
38
38
|
|
|
39
39
|
get maxEmbeddingsPerCall(): number {
|
|
40
40
|
// https://developers.cloudflare.com/workers-ai/platform/limits/#text-embeddings
|
|
41
|
-
const maxEmbeddingsPerCall =
|
|
41
|
+
const maxEmbeddingsPerCall = 3000;
|
|
42
42
|
return this.settings.maxEmbeddingsPerCall ?? maxEmbeddingsPerCall;
|
|
43
43
|
}
|
|
44
44
|
|
|
@@ -58,8 +58,8 @@ export class WorkersAIEmbeddingModel implements EmbeddingModelV1<string> {
|
|
|
58
58
|
|
|
59
59
|
async doEmbed({
|
|
60
60
|
values,
|
|
61
|
-
}: Parameters<
|
|
62
|
-
Awaited<ReturnType<
|
|
61
|
+
}: Parameters<EmbeddingModelV2<string>["doEmbed"]>[0]): Promise<
|
|
62
|
+
Awaited<ReturnType<EmbeddingModelV2<string>["doEmbed"]>>
|
|
63
63
|
> {
|
|
64
64
|
if (values.length > this.maxEmbeddingsPerCall) {
|
|
65
65
|
throw new TooManyEmbeddingValuesForCallError({
|
|
@@ -74,15 +74,17 @@ export class WorkersAIEmbeddingModel implements EmbeddingModelV1<string> {
|
|
|
74
74
|
|
|
75
75
|
const response = await this.config.binding.run(
|
|
76
76
|
this.modelId,
|
|
77
|
-
// @ts-ignore: Error introduced with "@cloudflare/workers-types": "^4.20250617.0"
|
|
78
77
|
{
|
|
79
78
|
text: values,
|
|
80
79
|
},
|
|
81
|
-
{
|
|
80
|
+
{
|
|
81
|
+
gateway: this.config.gateway ?? gateway,
|
|
82
|
+
...passthroughOptions,
|
|
83
|
+
tags: [],
|
|
84
|
+
},
|
|
82
85
|
);
|
|
83
86
|
|
|
84
87
|
return {
|
|
85
|
-
// @ts-ignore: Error introduced with "@cloudflare/workers-types": "^4.20250617.0"
|
|
86
88
|
embeddings: response.data,
|
|
87
89
|
};
|
|
88
90
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
UnsupportedFunctionalityError,
|
|
1
|
+
import type {
|
|
2
|
+
LanguageModelV2,
|
|
3
|
+
LanguageModelV2CallWarning,
|
|
4
|
+
LanguageModelV2StreamPart,
|
|
6
5
|
} from "@ai-sdk/provider";
|
|
6
|
+
import { generateId } from "ai";
|
|
7
7
|
import { convertToWorkersAIChatMessages } from "./convert-to-workersai-chat-messages";
|
|
8
8
|
import { mapWorkersAIFinishReason } from "./map-workersai-finish-reason";
|
|
9
9
|
import { mapWorkersAIUsage } from "./map-workersai-usage";
|
|
@@ -23,10 +23,14 @@ type WorkersAIChatConfig = {
|
|
|
23
23
|
gateway?: GatewayOptions;
|
|
24
24
|
};
|
|
25
25
|
|
|
26
|
-
export class WorkersAIChatLanguageModel implements
|
|
27
|
-
readonly specificationVersion = "
|
|
26
|
+
export class WorkersAIChatLanguageModel implements LanguageModelV2 {
|
|
27
|
+
readonly specificationVersion = "v2";
|
|
28
28
|
readonly defaultObjectGenerationMode = "json";
|
|
29
29
|
|
|
30
|
+
readonly supportedUrls: Record<string, RegExp[]> | PromiseLike<Record<string, RegExp[]>> = {
|
|
31
|
+
// Empty
|
|
32
|
+
};
|
|
33
|
+
|
|
30
34
|
readonly modelId: TextGenerationModels;
|
|
31
35
|
readonly settings: WorkersAIChatSettings;
|
|
32
36
|
|
|
@@ -47,17 +51,19 @@ export class WorkersAIChatLanguageModel implements LanguageModelV1 {
|
|
|
47
51
|
}
|
|
48
52
|
|
|
49
53
|
private getArgs({
|
|
50
|
-
|
|
51
|
-
|
|
54
|
+
responseFormat,
|
|
55
|
+
tools,
|
|
56
|
+
toolChoice,
|
|
57
|
+
maxOutputTokens,
|
|
52
58
|
temperature,
|
|
53
59
|
topP,
|
|
54
60
|
frequencyPenalty,
|
|
55
61
|
presencePenalty,
|
|
56
62
|
seed,
|
|
57
|
-
}: Parameters<
|
|
58
|
-
const type =
|
|
63
|
+
}: Parameters<LanguageModelV2["doGenerate"]>[0]) {
|
|
64
|
+
const type = responseFormat?.type ?? "text";
|
|
59
65
|
|
|
60
|
-
const warnings:
|
|
66
|
+
const warnings: LanguageModelV2CallWarning[] = [];
|
|
61
67
|
|
|
62
68
|
if (frequencyPenalty != null) {
|
|
63
69
|
warnings.push({
|
|
@@ -75,7 +81,7 @@ export class WorkersAIChatLanguageModel implements LanguageModelV1 {
|
|
|
75
81
|
|
|
76
82
|
const baseArgs = {
|
|
77
83
|
// standardized settings:
|
|
78
|
-
max_tokens:
|
|
84
|
+
max_tokens: maxOutputTokens,
|
|
79
85
|
// model id:
|
|
80
86
|
model: this.modelId,
|
|
81
87
|
random_seed: seed,
|
|
@@ -87,19 +93,22 @@ export class WorkersAIChatLanguageModel implements LanguageModelV1 {
|
|
|
87
93
|
};
|
|
88
94
|
|
|
89
95
|
switch (type) {
|
|
90
|
-
case "
|
|
96
|
+
case "text": {
|
|
91
97
|
return {
|
|
92
|
-
args: {
|
|
98
|
+
args: {
|
|
99
|
+
...baseArgs,
|
|
100
|
+
...prepareToolsAndToolChoice(tools, toolChoice),
|
|
101
|
+
},
|
|
93
102
|
warnings,
|
|
94
103
|
};
|
|
95
104
|
}
|
|
96
105
|
|
|
97
|
-
case "
|
|
106
|
+
case "json": {
|
|
98
107
|
return {
|
|
99
108
|
args: {
|
|
100
109
|
...baseArgs,
|
|
101
110
|
response_format: {
|
|
102
|
-
json_schema:
|
|
111
|
+
json_schema: responseFormat?.type === "json" && responseFormat.schema,
|
|
103
112
|
type: "json_schema",
|
|
104
113
|
},
|
|
105
114
|
tools: undefined,
|
|
@@ -108,25 +117,6 @@ export class WorkersAIChatLanguageModel implements LanguageModelV1 {
|
|
|
108
117
|
};
|
|
109
118
|
}
|
|
110
119
|
|
|
111
|
-
case "object-tool": {
|
|
112
|
-
return {
|
|
113
|
-
args: {
|
|
114
|
-
...baseArgs,
|
|
115
|
-
tool_choice: "any",
|
|
116
|
-
tools: [{ function: mode.tool, type: "function" }],
|
|
117
|
-
},
|
|
118
|
-
warnings,
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// @ts-expect-error - this is unreachable code
|
|
123
|
-
// TODO: fixme
|
|
124
|
-
case "object-grammar": {
|
|
125
|
-
throw new UnsupportedFunctionalityError({
|
|
126
|
-
functionality: "object-grammar mode",
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
|
|
130
120
|
default: {
|
|
131
121
|
const exhaustiveCheck = type satisfies never;
|
|
132
122
|
throw new Error(`Unsupported type: ${exhaustiveCheck}`);
|
|
@@ -135,8 +125,8 @@ export class WorkersAIChatLanguageModel implements LanguageModelV1 {
|
|
|
135
125
|
}
|
|
136
126
|
|
|
137
127
|
async doGenerate(
|
|
138
|
-
options: Parameters<
|
|
139
|
-
): Promise<Awaited<ReturnType<
|
|
128
|
+
options: Parameters<LanguageModelV2["doGenerate"]>[0],
|
|
129
|
+
): Promise<Awaited<ReturnType<LanguageModelV2["doGenerate"]>>> {
|
|
140
130
|
const { args, warnings } = this.getArgs(options);
|
|
141
131
|
|
|
142
132
|
// biome-ignore lint/correctness/noUnusedVariables: this needs to be destructured
|
|
@@ -166,29 +156,51 @@ export class WorkersAIChatLanguageModel implements LanguageModelV1 {
|
|
|
166
156
|
// @ts-expect-error response_format not yet added to types
|
|
167
157
|
response_format: args.response_format,
|
|
168
158
|
},
|
|
169
|
-
{
|
|
159
|
+
{
|
|
160
|
+
gateway: this.config.gateway ?? gateway,
|
|
161
|
+
...passthroughOptions,
|
|
162
|
+
tags: [],
|
|
163
|
+
},
|
|
170
164
|
);
|
|
171
165
|
|
|
172
166
|
if (output instanceof ReadableStream) {
|
|
173
167
|
throw new Error("This shouldn't happen");
|
|
174
168
|
}
|
|
175
169
|
|
|
170
|
+
const reasoningContent = (output as any)?.choices?.[0]?.message?.reasoning_content;
|
|
171
|
+
|
|
176
172
|
return {
|
|
177
173
|
finishReason: mapWorkersAIFinishReason(output),
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
//
|
|
183
|
-
|
|
174
|
+
// TODO: rawCall and rawResponse- not sure
|
|
175
|
+
// rawCall: { rawPrompt: messages, rawSettings: args },
|
|
176
|
+
// rawResponse: { body: output },
|
|
177
|
+
// maybe this?
|
|
178
|
+
// providerMetadata: {
|
|
179
|
+
// prompt: messages,
|
|
180
|
+
// settings: args,
|
|
181
|
+
// response: output,
|
|
182
|
+
// },
|
|
183
|
+
content: [
|
|
184
|
+
...(reasoningContent
|
|
185
|
+
? [{ type: "reasoning" as const, text: reasoningContent }]
|
|
186
|
+
: []),
|
|
187
|
+
{
|
|
188
|
+
type: "text",
|
|
189
|
+
text: processText(output) ?? "",
|
|
190
|
+
},
|
|
191
|
+
...processToolCalls(output),
|
|
192
|
+
],
|
|
193
|
+
|
|
194
|
+
// @ts-expect-error: Missing types
|
|
195
|
+
reasoningText: reasoningContent,
|
|
184
196
|
usage: mapWorkersAIUsage(output),
|
|
185
197
|
warnings,
|
|
186
198
|
};
|
|
187
199
|
}
|
|
188
200
|
|
|
189
201
|
async doStream(
|
|
190
|
-
options: Parameters<
|
|
191
|
-
): Promise<Awaited<ReturnType<
|
|
202
|
+
options: Parameters<LanguageModelV2["doStream"]>[0],
|
|
203
|
+
): Promise<Awaited<ReturnType<LanguageModelV2["doStream"]>>> {
|
|
192
204
|
const { args, warnings } = this.getArgs(options);
|
|
193
205
|
|
|
194
206
|
// Extract image from messages if present
|
|
@@ -204,29 +216,57 @@ export class WorkersAIChatLanguageModel implements LanguageModelV1 {
|
|
|
204
216
|
throw new Error("This shouldn't happen");
|
|
205
217
|
}
|
|
206
218
|
|
|
219
|
+
// Track start/delta/end IDs per v5 streaming protocol
|
|
220
|
+
let textId: string | null = null;
|
|
221
|
+
let reasoningId: string | null = null;
|
|
222
|
+
|
|
207
223
|
return {
|
|
208
|
-
rawCall: { rawPrompt: messages, rawSettings: args },
|
|
209
|
-
stream: new ReadableStream<
|
|
224
|
+
// rawCall: { rawPrompt: messages, rawSettings: args },
|
|
225
|
+
stream: new ReadableStream<LanguageModelV2StreamPart>({
|
|
210
226
|
async start(controller) {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
227
|
+
// Emit the stream-start part with warnings
|
|
228
|
+
controller.enqueue({
|
|
229
|
+
type: "stream-start",
|
|
230
|
+
warnings: warnings as LanguageModelV2CallWarning[],
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
for (const contentPart of response.content) {
|
|
234
|
+
if (contentPart.type === "text") {
|
|
235
|
+
if (!textId) {
|
|
236
|
+
textId = generateId();
|
|
237
|
+
controller.enqueue({ type: "text-start", id: textId });
|
|
238
|
+
}
|
|
219
239
|
controller.enqueue({
|
|
220
|
-
|
|
221
|
-
|
|
240
|
+
delta: contentPart.text,
|
|
241
|
+
type: "text-delta",
|
|
242
|
+
id: textId,
|
|
222
243
|
});
|
|
223
244
|
}
|
|
245
|
+
if (contentPart.type === "tool-call") {
|
|
246
|
+
controller.enqueue(contentPart);
|
|
247
|
+
}
|
|
248
|
+
if (contentPart.type === "reasoning") {
|
|
249
|
+
if (!reasoningId) {
|
|
250
|
+
reasoningId = generateId();
|
|
251
|
+
controller.enqueue({
|
|
252
|
+
type: "reasoning-start",
|
|
253
|
+
id: reasoningId,
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
controller.enqueue({
|
|
257
|
+
type: "reasoning-delta",
|
|
258
|
+
delta: contentPart.text,
|
|
259
|
+
id: generateId(),
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
if (reasoningId) {
|
|
264
|
+
controller.enqueue({ type: "reasoning-end", id: reasoningId });
|
|
265
|
+
reasoningId = null;
|
|
224
266
|
}
|
|
225
|
-
if (
|
|
226
|
-
controller.enqueue({
|
|
227
|
-
|
|
228
|
-
textDelta: response.reasoning,
|
|
229
|
-
});
|
|
267
|
+
if (textId) {
|
|
268
|
+
controller.enqueue({ type: "text-end", id: textId });
|
|
269
|
+
textId = null;
|
|
230
270
|
}
|
|
231
271
|
controller.enqueue({
|
|
232
272
|
finishReason: mapWorkersAIFinishReason(response),
|
|
@@ -236,7 +276,6 @@ export class WorkersAIChatLanguageModel implements LanguageModelV1 {
|
|
|
236
276
|
controller.close();
|
|
237
277
|
},
|
|
238
278
|
}),
|
|
239
|
-
warnings,
|
|
240
279
|
};
|
|
241
280
|
}
|
|
242
281
|
|
|
@@ -265,17 +304,48 @@ export class WorkersAIChatLanguageModel implements LanguageModelV1 {
|
|
|
265
304
|
// @ts-expect-error response_format not yet added to types
|
|
266
305
|
response_format: args.response_format,
|
|
267
306
|
},
|
|
268
|
-
{
|
|
307
|
+
{
|
|
308
|
+
gateway: this.config.gateway ?? gateway,
|
|
309
|
+
...passthroughOptions,
|
|
310
|
+
tags: [],
|
|
311
|
+
},
|
|
269
312
|
);
|
|
270
313
|
|
|
271
314
|
if (!(response instanceof ReadableStream)) {
|
|
272
315
|
throw new Error("This shouldn't happen");
|
|
273
316
|
}
|
|
274
317
|
|
|
318
|
+
// Create a new stream that first emits the stream-start part with warnings,
|
|
319
|
+
// then pipes through the rest of the response stream
|
|
320
|
+
const stream = new ReadableStream<LanguageModelV2StreamPart>({
|
|
321
|
+
start(controller) {
|
|
322
|
+
// Emit the stream-start part with warnings
|
|
323
|
+
controller.enqueue({
|
|
324
|
+
type: "stream-start",
|
|
325
|
+
warnings: warnings as LanguageModelV2CallWarning[],
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
// Pipe the rest of the response stream
|
|
329
|
+
const reader = getMappedStream(new Response(response)).getReader();
|
|
330
|
+
|
|
331
|
+
function push() {
|
|
332
|
+
reader.read().then(({ done, value }) => {
|
|
333
|
+
if (done) {
|
|
334
|
+
controller.close();
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
controller.enqueue(value);
|
|
338
|
+
push();
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
push();
|
|
342
|
+
},
|
|
343
|
+
});
|
|
344
|
+
|
|
275
345
|
return {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
346
|
+
stream,
|
|
347
|
+
// TODO: not sure about rawCalls
|
|
348
|
+
// rawCall: { rawPrompt: messages, rawSettings: args },
|
|
279
349
|
};
|
|
280
350
|
}
|
|
281
351
|
}
|
package/src/workersai-error.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ImageModelV2, ImageModelV2CallWarning } from "@ai-sdk/provider";
|
|
2
2
|
import type { WorkersAIImageConfig } from "./workersai-image-config";
|
|
3
3
|
import type { WorkersAIImageSettings } from "./workersai-image-settings";
|
|
4
4
|
import type { ImageGenerationModels } from "./workersai-models";
|
|
5
5
|
|
|
6
|
-
export class WorkersAIImageModel implements
|
|
7
|
-
readonly specificationVersion = "
|
|
6
|
+
export class WorkersAIImageModel implements ImageModelV2 {
|
|
7
|
+
readonly specificationVersion = "v2";
|
|
8
8
|
|
|
9
9
|
get maxImagesPerCall(): number {
|
|
10
10
|
return this.settings.maxImagesPerCall ?? 1;
|
|
@@ -27,12 +27,12 @@ export class WorkersAIImageModel implements ImageModelV1 {
|
|
|
27
27
|
seed,
|
|
28
28
|
// headers,
|
|
29
29
|
// abortSignal,
|
|
30
|
-
}: Parameters<
|
|
31
|
-
Awaited<ReturnType<
|
|
30
|
+
}: Parameters<ImageModelV2["doGenerate"]>[0]): Promise<
|
|
31
|
+
Awaited<ReturnType<ImageModelV2["doGenerate"]>>
|
|
32
32
|
> {
|
|
33
33
|
const { width, height } = getDimensionsFromSizeString(size);
|
|
34
34
|
|
|
35
|
-
const warnings: Array<
|
|
35
|
+
const warnings: Array<ImageModelV2CallWarning> = [];
|
|
36
36
|
|
|
37
37
|
if (aspectRatio != null) {
|
|
38
38
|
warnings.push({
|