@runpod/ai-sdk-provider 0.7.0 → 0.8.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/CHANGELOG.md +17 -2
- package/README.md +41 -19
- package/dist/index.d.mts +25 -12
- package/dist/index.d.ts +25 -12
- package/dist/index.js +75 -64
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +64 -54
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @runpod/ai-sdk-provider
|
|
2
2
|
|
|
3
|
+
## 0.8.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 9514d33: Improve error message extraction from Runpod API responses. Users now see actual error messages from the API instead of generic fallbacks like "Unknown error". The error handler extracts nested JSON messages from image API errors and properly surfaces all error details.
|
|
8
|
+
|
|
9
|
+
## 0.8.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- 2394ad6: Accept any model ID string and automatically derive endpoints for unknown models instead of throwing validation errors. Known models use hardcoded endpoint mappings. Added support for IBM Granite models.
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- 9520f2a: chore: removed deep-cogito
|
|
18
|
+
|
|
3
19
|
## 0.7.0
|
|
4
20
|
|
|
5
21
|
### Minor Changes
|
|
@@ -90,6 +106,5 @@
|
|
|
90
106
|
### Minor Changes
|
|
91
107
|
|
|
92
108
|
- 4fa63d7: first release of the Runpod provider for the AI SDK
|
|
93
|
-
- generateText for
|
|
94
|
-
- deep-cogito/deep-cogito-v2-llama-70b
|
|
109
|
+
- generateText for llms
|
|
95
110
|
- qwen/qwen3-32b-awq
|
package/README.md
CHANGED
|
@@ -75,7 +75,7 @@ import { runpod } from '@runpod/ai-sdk-provider';
|
|
|
75
75
|
import { generateText } from 'ai';
|
|
76
76
|
|
|
77
77
|
const { text } = await generateText({
|
|
78
|
-
model: runpod('
|
|
78
|
+
model: runpod('qwen/qwen3-32b-awq'),
|
|
79
79
|
prompt: 'What is the capital of Germany?',
|
|
80
80
|
});
|
|
81
81
|
```
|
|
@@ -93,7 +93,7 @@ import { runpod } from '@runpod/ai-sdk-provider';
|
|
|
93
93
|
import { streamText } from 'ai';
|
|
94
94
|
|
|
95
95
|
const { textStream } = await streamText({
|
|
96
|
-
model: runpod('
|
|
96
|
+
model: runpod('qwen/qwen3-32b-awq'),
|
|
97
97
|
prompt:
|
|
98
98
|
'Write a short poem about artificial intelligence in exactly 4 lines.',
|
|
99
99
|
temperature: 0.7,
|
|
@@ -106,16 +106,15 @@ for await (const delta of textStream) {
|
|
|
106
106
|
|
|
107
107
|
### Model Capabilities
|
|
108
108
|
|
|
109
|
-
| Model ID
|
|
110
|
-
|
|
|
111
|
-
| `
|
|
112
|
-
| `qwen/qwen3-32b-awq` | 32B parameter multilingual model with strong reasoning capabilities | ✅ | ❌ | ✅ | Standard reasoning events |
|
|
109
|
+
| Model ID | Description | Streaming | Object Generation | Tool Usage | Reasoning Notes |
|
|
110
|
+
| -------------------- | ------------------------------------------------------------------- | --------- | ----------------- | ---------- | ------------------------- |
|
|
111
|
+
| `qwen/qwen3-32b-awq` | 32B parameter multilingual model with strong reasoning capabilities | ✅ | ❌ | ✅ | Standard reasoning events |
|
|
113
112
|
|
|
114
113
|
### Chat Conversations
|
|
115
114
|
|
|
116
115
|
```ts
|
|
117
116
|
const { text } = await generateText({
|
|
118
|
-
model: runpod('
|
|
117
|
+
model: runpod('qwen/qwen3-32b-awq'),
|
|
119
118
|
messages: [
|
|
120
119
|
{ role: 'system', content: 'You are a helpful assistant.' },
|
|
121
120
|
{ role: 'user', content: 'What is the capital of France?' },
|
|
@@ -130,7 +129,7 @@ import { generateText, tool } from 'ai';
|
|
|
130
129
|
import { z } from 'zod';
|
|
131
130
|
|
|
132
131
|
const { text, toolCalls } = await generateText({
|
|
133
|
-
model: runpod('
|
|
132
|
+
model: runpod('qwen/qwen3-32b-awq'),
|
|
134
133
|
prompt: 'What is the weather like in San Francisco?',
|
|
135
134
|
tools: {
|
|
136
135
|
getWeather: tool({
|
|
@@ -231,6 +230,7 @@ writeFileSync('landscape.jpg', image.uint8Array);
|
|
|
231
230
|
| `black-forest-labs/flux-1-kontext-dev` | Context-aware image generation | 1:1, 4:3, 3:4 |
|
|
232
231
|
| `qwen/qwen-image` | Text-to-image generation | 1:1, 4:3, 3:4 |
|
|
233
232
|
| `qwen/qwen-image-edit` | Image editing (prompt-guided) | 1:1, 4:3, 3:4 |
|
|
233
|
+
| `nano-banana-edit` | Image editing (multi-image) | 1:1, 4:3, 3:4 |
|
|
234
234
|
|
|
235
235
|
**Note**: The provider uses strict validation for image parameters. Unsupported aspect ratios (like `16:9`, `9:16`, `3:2`, `2:3`) will throw an `InvalidArgumentError` with a clear message about supported alternatives.
|
|
236
236
|
|
|
@@ -280,6 +280,27 @@ const { image } = await generateImage({
|
|
|
280
280
|
});
|
|
281
281
|
```
|
|
282
282
|
|
|
283
|
+
```ts
|
|
284
|
+
// Example: Combine multiple images using Nano Banana edit
|
|
285
|
+
const { image } = await generateImage({
|
|
286
|
+
model: runpod.imageModel('nano-banana-edit'),
|
|
287
|
+
prompt:
|
|
288
|
+
'Combine these four images into a single realistic 3D character scene.',
|
|
289
|
+
// Defaults to 1:1; you can also set size: '1328x1328' or aspectRatio: '4:3'
|
|
290
|
+
providerOptions: {
|
|
291
|
+
runpod: {
|
|
292
|
+
images: [
|
|
293
|
+
'https://image.runpod.ai/uploads/0bz_xzhuLq/a2166199-5bd5-496b-b9ab-a8bae3f73bdc.jpg',
|
|
294
|
+
'https://image.runpod.ai/uploads/Yw86rhY6xi/2ff8435f-f416-4096-9a4d-2f8c838b2d53.jpg',
|
|
295
|
+
'https://image.runpod.ai/uploads/bpCCX9zLY8/3bc27605-6f9a-40ad-83e9-c29bed45fed9.jpg',
|
|
296
|
+
'https://image.runpod.ai/uploads/LPHEY6pyHp/f950ceb8-fafa-4800-bdf1-fd3fd684d843.jpg',
|
|
297
|
+
],
|
|
298
|
+
enable_safety_checker: true,
|
|
299
|
+
},
|
|
300
|
+
},
|
|
301
|
+
});
|
|
302
|
+
```
|
|
303
|
+
|
|
283
304
|
### Advanced Configuration
|
|
284
305
|
|
|
285
306
|
```ts
|
|
@@ -322,19 +343,20 @@ const { image } = await generateImage({
|
|
|
322
343
|
|
|
323
344
|
Runpod image models support flexible provider options through the `providerOptions.runpod` object:
|
|
324
345
|
|
|
325
|
-
| Option | Type
|
|
326
|
-
| ----------------------- |
|
|
327
|
-
| `negative_prompt` | `string`
|
|
328
|
-
| `enable_safety_checker` | `boolean`
|
|
329
|
-
| `image` | `string`
|
|
330
|
-
| `
|
|
331
|
-
| `
|
|
332
|
-
| `
|
|
333
|
-
| `
|
|
334
|
-
| `
|
|
346
|
+
| Option | Type | Default | Description |
|
|
347
|
+
| ----------------------- | ---------- | ------- | ------------------------------------------------------------------------ |
|
|
348
|
+
| `negative_prompt` | `string` | `""` | Text describing what you don't want in the image |
|
|
349
|
+
| `enable_safety_checker` | `boolean` | `true` | Enable content safety filtering |
|
|
350
|
+
| `image` | `string` | - | Single input image: URL or base64 data URI (Flux Kontext) |
|
|
351
|
+
| `images` | `string[]` | - | Multiple input images (e.g., for `nano-banana-edit` multi-image editing) |
|
|
352
|
+
| `num_inference_steps` | `number` | Auto | Number of denoising steps (Flux: 4 for schnell, 28 for others) |
|
|
353
|
+
| `guidance` | `number` | Auto | Guidance scale for prompt adherence (Flux: 7 for schnell, 2 for others) |
|
|
354
|
+
| `output_format` | `string` | `"png"` | Output image format ("png" or "jpg") |
|
|
355
|
+
| `maxPollAttempts` | `number` | `60` | Maximum polling attempts for async generation |
|
|
356
|
+
| `pollIntervalMillis` | `number` | `5000` | Polling interval in milliseconds (5 seconds) |
|
|
335
357
|
|
|
336
358
|
## About Runpod
|
|
337
359
|
|
|
338
360
|
[Runpod](https://runpod.io) is the foundation for developers to build, deploy, and scale custom AI systems.
|
|
339
361
|
|
|
340
|
-
Beyond some of the public endpoints you've seen above (+ more generative media APIs), Runpod offers
|
|
362
|
+
Beyond some of the public endpoints you've seen above (+ more generative media APIs), Runpod offers private [serverless endpoints](https://docs.runpod.io/serverless/overview) / [pods](https://docs.runpod.io/pods/overview) / [instant clusters](https://docs.runpod.io/instant-clusters), so that you can train, fine-tune or run any open-source or private model on your terms.
|
package/dist/index.d.mts
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import { LanguageModelV2, ImageModelV2 } from '@ai-sdk/provider';
|
|
2
2
|
import { FetchFunction } from '@ai-sdk/provider-utils';
|
|
3
3
|
export { OpenAICompatibleErrorData as RunpodErrorData } from '@ai-sdk/openai-compatible';
|
|
4
|
-
|
|
5
|
-
type RunpodChatModelId = 'deep-cogito/deep-cogito-v2-llama-70b' | 'qwen/qwen3-32b-awq' | (string & {});
|
|
6
|
-
|
|
7
|
-
type RunpodCompletionModelId = 'deep-cogito/deep-cogito-v2-llama-70b' | 'qwen/qwen3-32b-awq' | (string & {});
|
|
8
|
-
|
|
9
|
-
type RunpodImageModelId = 'qwen/qwen-image' | 'qwen/qwen-image-edit' | 'bytedance/seedream-3.0' | 'bytedance/seedream-4.0' | 'bytedance/seedream-4.0-edit' | 'black-forest-labs/flux-1-kontext-dev' | 'black-forest-labs/flux-1-schnell' | 'black-forest-labs/flux-1-dev';
|
|
4
|
+
import { z } from 'zod';
|
|
10
5
|
|
|
11
6
|
interface RunpodProviderSettings {
|
|
12
7
|
/**
|
|
@@ -32,25 +27,43 @@ interface RunpodProvider {
|
|
|
32
27
|
/**
|
|
33
28
|
Creates a model for text generation.
|
|
34
29
|
*/
|
|
35
|
-
(modelId:
|
|
30
|
+
(modelId: string): LanguageModelV2;
|
|
36
31
|
/**
|
|
37
32
|
Creates a chat model for text generation.
|
|
38
33
|
*/
|
|
39
|
-
chatModel(modelId:
|
|
34
|
+
chatModel(modelId: string): LanguageModelV2;
|
|
40
35
|
/**
|
|
41
36
|
Creates a chat model for text generation.
|
|
42
37
|
*/
|
|
43
|
-
languageModel(modelId:
|
|
38
|
+
languageModel(modelId: string): LanguageModelV2;
|
|
44
39
|
/**
|
|
45
40
|
Creates a completion model for text generation.
|
|
46
41
|
*/
|
|
47
|
-
completionModel(modelId:
|
|
42
|
+
completionModel(modelId: string): LanguageModelV2;
|
|
48
43
|
/**
|
|
49
44
|
Creates an image model for image generation.
|
|
50
45
|
*/
|
|
51
|
-
imageModel(modelId:
|
|
46
|
+
imageModel(modelId: string): ImageModelV2;
|
|
52
47
|
}
|
|
53
48
|
declare function createRunpod(options?: RunpodProviderSettings): RunpodProvider;
|
|
54
49
|
declare const runpod: RunpodProvider;
|
|
55
50
|
|
|
56
|
-
|
|
51
|
+
type RunpodChatModelId = 'qwen/qwen3-32b-awq' | (string & {});
|
|
52
|
+
|
|
53
|
+
type RunpodCompletionModelId = 'qwen/qwen3-32b-awq' | (string & {});
|
|
54
|
+
|
|
55
|
+
type RunpodImageModelId = 'qwen/qwen-image' | 'qwen/qwen-image-edit' | 'bytedance/seedream-3.0' | 'bytedance/seedream-4.0' | 'bytedance/seedream-4.0-edit' | 'black-forest-labs/flux-1-kontext-dev' | 'black-forest-labs/flux-1-schnell' | 'black-forest-labs/flux-1-dev' | 'nano-banana-edit';
|
|
56
|
+
|
|
57
|
+
declare const runpodImageErrorSchema: z.ZodObject<{
|
|
58
|
+
error: z.ZodOptional<z.ZodString>;
|
|
59
|
+
message: z.ZodOptional<z.ZodString>;
|
|
60
|
+
}, "strip", z.ZodTypeAny, {
|
|
61
|
+
error?: string | undefined;
|
|
62
|
+
message?: string | undefined;
|
|
63
|
+
}, {
|
|
64
|
+
error?: string | undefined;
|
|
65
|
+
message?: string | undefined;
|
|
66
|
+
}>;
|
|
67
|
+
type RunpodImageErrorData = z.infer<typeof runpodImageErrorSchema>;
|
|
68
|
+
|
|
69
|
+
export { type RunpodChatModelId, type RunpodCompletionModelId, type RunpodImageErrorData, type RunpodImageModelId, type RunpodProvider, type RunpodProviderSettings, createRunpod, runpod };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import { LanguageModelV2, ImageModelV2 } from '@ai-sdk/provider';
|
|
2
2
|
import { FetchFunction } from '@ai-sdk/provider-utils';
|
|
3
3
|
export { OpenAICompatibleErrorData as RunpodErrorData } from '@ai-sdk/openai-compatible';
|
|
4
|
-
|
|
5
|
-
type RunpodChatModelId = 'deep-cogito/deep-cogito-v2-llama-70b' | 'qwen/qwen3-32b-awq' | (string & {});
|
|
6
|
-
|
|
7
|
-
type RunpodCompletionModelId = 'deep-cogito/deep-cogito-v2-llama-70b' | 'qwen/qwen3-32b-awq' | (string & {});
|
|
8
|
-
|
|
9
|
-
type RunpodImageModelId = 'qwen/qwen-image' | 'qwen/qwen-image-edit' | 'bytedance/seedream-3.0' | 'bytedance/seedream-4.0' | 'bytedance/seedream-4.0-edit' | 'black-forest-labs/flux-1-kontext-dev' | 'black-forest-labs/flux-1-schnell' | 'black-forest-labs/flux-1-dev';
|
|
4
|
+
import { z } from 'zod';
|
|
10
5
|
|
|
11
6
|
interface RunpodProviderSettings {
|
|
12
7
|
/**
|
|
@@ -32,25 +27,43 @@ interface RunpodProvider {
|
|
|
32
27
|
/**
|
|
33
28
|
Creates a model for text generation.
|
|
34
29
|
*/
|
|
35
|
-
(modelId:
|
|
30
|
+
(modelId: string): LanguageModelV2;
|
|
36
31
|
/**
|
|
37
32
|
Creates a chat model for text generation.
|
|
38
33
|
*/
|
|
39
|
-
chatModel(modelId:
|
|
34
|
+
chatModel(modelId: string): LanguageModelV2;
|
|
40
35
|
/**
|
|
41
36
|
Creates a chat model for text generation.
|
|
42
37
|
*/
|
|
43
|
-
languageModel(modelId:
|
|
38
|
+
languageModel(modelId: string): LanguageModelV2;
|
|
44
39
|
/**
|
|
45
40
|
Creates a completion model for text generation.
|
|
46
41
|
*/
|
|
47
|
-
completionModel(modelId:
|
|
42
|
+
completionModel(modelId: string): LanguageModelV2;
|
|
48
43
|
/**
|
|
49
44
|
Creates an image model for image generation.
|
|
50
45
|
*/
|
|
51
|
-
imageModel(modelId:
|
|
46
|
+
imageModel(modelId: string): ImageModelV2;
|
|
52
47
|
}
|
|
53
48
|
declare function createRunpod(options?: RunpodProviderSettings): RunpodProvider;
|
|
54
49
|
declare const runpod: RunpodProvider;
|
|
55
50
|
|
|
56
|
-
|
|
51
|
+
type RunpodChatModelId = 'qwen/qwen3-32b-awq' | (string & {});
|
|
52
|
+
|
|
53
|
+
type RunpodCompletionModelId = 'qwen/qwen3-32b-awq' | (string & {});
|
|
54
|
+
|
|
55
|
+
type RunpodImageModelId = 'qwen/qwen-image' | 'qwen/qwen-image-edit' | 'bytedance/seedream-3.0' | 'bytedance/seedream-4.0' | 'bytedance/seedream-4.0-edit' | 'black-forest-labs/flux-1-kontext-dev' | 'black-forest-labs/flux-1-schnell' | 'black-forest-labs/flux-1-dev' | 'nano-banana-edit';
|
|
56
|
+
|
|
57
|
+
declare const runpodImageErrorSchema: z.ZodObject<{
|
|
58
|
+
error: z.ZodOptional<z.ZodString>;
|
|
59
|
+
message: z.ZodOptional<z.ZodString>;
|
|
60
|
+
}, "strip", z.ZodTypeAny, {
|
|
61
|
+
error?: string | undefined;
|
|
62
|
+
message?: string | undefined;
|
|
63
|
+
}, {
|
|
64
|
+
error?: string | undefined;
|
|
65
|
+
message?: string | undefined;
|
|
66
|
+
}>;
|
|
67
|
+
type RunpodImageErrorData = z.infer<typeof runpodImageErrorSchema>;
|
|
68
|
+
|
|
69
|
+
export { type RunpodChatModelId, type RunpodCompletionModelId, type RunpodImageErrorData, type RunpodImageModelId, type RunpodProvider, type RunpodProviderSettings, createRunpod, runpod };
|
package/dist/index.js
CHANGED
|
@@ -27,12 +27,45 @@ module.exports = __toCommonJS(index_exports);
|
|
|
27
27
|
|
|
28
28
|
// src/runpod-provider.ts
|
|
29
29
|
var import_openai_compatible = require("@ai-sdk/openai-compatible");
|
|
30
|
-
var
|
|
30
|
+
var import_provider_utils3 = require("@ai-sdk/provider-utils");
|
|
31
31
|
|
|
32
32
|
// src/runpod-image-model.ts
|
|
33
|
-
var
|
|
33
|
+
var import_provider_utils2 = require("@ai-sdk/provider-utils");
|
|
34
34
|
var import_provider = require("@ai-sdk/provider");
|
|
35
|
+
var import_zod2 = require("zod");
|
|
36
|
+
|
|
37
|
+
// src/runpod-error.ts
|
|
35
38
|
var import_zod = require("zod");
|
|
39
|
+
var import_provider_utils = require("@ai-sdk/provider-utils");
|
|
40
|
+
var runpodImageErrorSchema = import_zod.z.object({
|
|
41
|
+
error: import_zod.z.string().optional(),
|
|
42
|
+
message: import_zod.z.string().optional()
|
|
43
|
+
});
|
|
44
|
+
var runpodImageFailedResponseHandler = (0, import_provider_utils.createJsonErrorResponseHandler)({
|
|
45
|
+
errorSchema: runpodImageErrorSchema,
|
|
46
|
+
errorToMessage: (data) => {
|
|
47
|
+
if (data.message) {
|
|
48
|
+
return data.message;
|
|
49
|
+
}
|
|
50
|
+
if (data.error) {
|
|
51
|
+
const lastBraceIndex = data.error.lastIndexOf("{");
|
|
52
|
+
if (lastBraceIndex !== -1) {
|
|
53
|
+
try {
|
|
54
|
+
const jsonStr = data.error.substring(lastBraceIndex);
|
|
55
|
+
const nestedError = JSON.parse(jsonStr);
|
|
56
|
+
if (nestedError.message && typeof nestedError.message === "string") {
|
|
57
|
+
return nestedError.message;
|
|
58
|
+
}
|
|
59
|
+
} catch {
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return data.error;
|
|
63
|
+
}
|
|
64
|
+
return "Unknown Runpod error";
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// src/runpod-image-model.ts
|
|
36
69
|
var SUPPORTED_ASPECT_RATIOS = {
|
|
37
70
|
"1:1": "1328*1328",
|
|
38
71
|
// ✅ Native support
|
|
@@ -119,17 +152,14 @@ var RunpodImageModel = class {
|
|
|
119
152
|
seed,
|
|
120
153
|
providerOptions.runpod
|
|
121
154
|
);
|
|
122
|
-
const { value: response, responseHeaders } = await (0,
|
|
155
|
+
const { value: response, responseHeaders } = await (0, import_provider_utils2.postJsonToApi)({
|
|
123
156
|
url: `${this.config.baseURL}/runsync`,
|
|
124
|
-
headers: (0,
|
|
157
|
+
headers: (0, import_provider_utils2.combineHeaders)(this.config.headers(), headers),
|
|
125
158
|
body: {
|
|
126
159
|
input: inputPayload
|
|
127
160
|
},
|
|
128
|
-
failedResponseHandler:
|
|
129
|
-
|
|
130
|
-
errorToMessage: (data) => data.error ?? "Unknown error"
|
|
131
|
-
}),
|
|
132
|
-
successfulResponseHandler: (0, import_provider_utils.createJsonResponseHandler)(
|
|
161
|
+
failedResponseHandler: runpodImageFailedResponseHandler,
|
|
162
|
+
successfulResponseHandler: (0, import_provider_utils2.createJsonResponseHandler)(
|
|
133
163
|
runpodImageResponseSchema
|
|
134
164
|
),
|
|
135
165
|
abortSignal,
|
|
@@ -193,13 +223,10 @@ var RunpodImageModel = class {
|
|
|
193
223
|
}
|
|
194
224
|
}
|
|
195
225
|
async downloadImage(imageUrl, abortSignal) {
|
|
196
|
-
const { value: imageData } = await (0,
|
|
226
|
+
const { value: imageData } = await (0, import_provider_utils2.getFromApi)({
|
|
197
227
|
url: imageUrl,
|
|
198
|
-
successfulResponseHandler: (0,
|
|
199
|
-
failedResponseHandler:
|
|
200
|
-
errorSchema: runpodImageErrorSchema,
|
|
201
|
-
errorToMessage: (data) => data.error ?? "Failed to download image"
|
|
202
|
-
}),
|
|
228
|
+
successfulResponseHandler: (0, import_provider_utils2.createBinaryResponseHandler)(),
|
|
229
|
+
failedResponseHandler: runpodImageFailedResponseHandler,
|
|
203
230
|
abortSignal,
|
|
204
231
|
fetch: this.config.fetch
|
|
205
232
|
});
|
|
@@ -212,16 +239,13 @@ var RunpodImageModel = class {
|
|
|
212
239
|
if (abortSignal?.aborted) {
|
|
213
240
|
throw new Error("Image generation was aborted");
|
|
214
241
|
}
|
|
215
|
-
const { value: statusResponse } = await (0,
|
|
242
|
+
const { value: statusResponse } = await (0, import_provider_utils2.getFromApi)({
|
|
216
243
|
url: `${this.config.baseURL}/status/${jobId}`,
|
|
217
244
|
headers: this.config.headers(),
|
|
218
|
-
successfulResponseHandler: (0,
|
|
245
|
+
successfulResponseHandler: (0, import_provider_utils2.createJsonResponseHandler)(
|
|
219
246
|
runpodImageStatusSchema
|
|
220
247
|
),
|
|
221
|
-
failedResponseHandler:
|
|
222
|
-
errorSchema: runpodImageErrorSchema,
|
|
223
|
-
errorToMessage: (data) => data.error ?? "Failed to check job status"
|
|
224
|
-
}),
|
|
248
|
+
failedResponseHandler: runpodImageFailedResponseHandler,
|
|
225
249
|
abortSignal,
|
|
226
250
|
fetch: this.config.fetch
|
|
227
251
|
});
|
|
@@ -282,40 +306,36 @@ var RunpodImageModel = class {
|
|
|
282
306
|
};
|
|
283
307
|
}
|
|
284
308
|
};
|
|
285
|
-
var runpodImageResponseSchema =
|
|
286
|
-
id:
|
|
287
|
-
status:
|
|
288
|
-
delayTime:
|
|
289
|
-
executionTime:
|
|
290
|
-
output:
|
|
291
|
-
cost:
|
|
292
|
-
result:
|
|
309
|
+
var runpodImageResponseSchema = import_zod2.z.object({
|
|
310
|
+
id: import_zod2.z.string(),
|
|
311
|
+
status: import_zod2.z.enum(["COMPLETED", "IN_QUEUE", "IN_PROGRESS", "FAILED"]),
|
|
312
|
+
delayTime: import_zod2.z.number().optional(),
|
|
313
|
+
executionTime: import_zod2.z.number().optional(),
|
|
314
|
+
output: import_zod2.z.object({
|
|
315
|
+
cost: import_zod2.z.number().optional(),
|
|
316
|
+
result: import_zod2.z.string().optional(),
|
|
293
317
|
// URL to the generated image (Qwen format)
|
|
294
|
-
image_url:
|
|
318
|
+
image_url: import_zod2.z.string().optional()
|
|
295
319
|
// URL to the generated image (Flux format)
|
|
296
320
|
}).optional()
|
|
297
321
|
// Optional for IN_QUEUE/IN_PROGRESS responses
|
|
298
322
|
});
|
|
299
|
-
var runpodImageStatusSchema =
|
|
300
|
-
id:
|
|
301
|
-
status:
|
|
302
|
-
output:
|
|
303
|
-
cost:
|
|
304
|
-
result:
|
|
305
|
-
image_url:
|
|
323
|
+
var runpodImageStatusSchema = import_zod2.z.object({
|
|
324
|
+
id: import_zod2.z.string(),
|
|
325
|
+
status: import_zod2.z.enum(["COMPLETED", "IN_QUEUE", "IN_PROGRESS", "FAILED"]),
|
|
326
|
+
output: import_zod2.z.object({
|
|
327
|
+
cost: import_zod2.z.number().optional(),
|
|
328
|
+
result: import_zod2.z.string().optional(),
|
|
329
|
+
image_url: import_zod2.z.string().optional()
|
|
306
330
|
}).optional(),
|
|
307
|
-
error:
|
|
331
|
+
error: import_zod2.z.string().optional()
|
|
308
332
|
// Error message if FAILED
|
|
309
333
|
});
|
|
310
|
-
var runpodImageErrorSchema = import_zod.z.object({
|
|
311
|
-
error: import_zod.z.string(),
|
|
312
|
-
message: import_zod.z.string().optional()
|
|
313
|
-
});
|
|
314
334
|
|
|
315
335
|
// src/runpod-provider.ts
|
|
316
336
|
var MODEL_ID_TO_ENDPOINT_URL = {
|
|
317
|
-
"
|
|
318
|
-
"
|
|
337
|
+
"qwen/qwen3-32b-awq": "https://api.runpod.ai/v2/qwen3-32b-awq/openai/v1",
|
|
338
|
+
"ibm-granite/granite-4.0-h-small": "https://api.runpod.ai/v2/granite-4-0-h-small/openai/v1"
|
|
319
339
|
};
|
|
320
340
|
var IMAGE_MODEL_ID_TO_ENDPOINT_URL = {
|
|
321
341
|
"qwen/qwen-image": "https://api.runpod.ai/v2/qwen-image-t2i",
|
|
@@ -326,15 +346,20 @@ var IMAGE_MODEL_ID_TO_ENDPOINT_URL = {
|
|
|
326
346
|
"bytedance/seedream-4.0-edit": "https://api.runpod.ai/v2/seedream-v4-edit",
|
|
327
347
|
"black-forest-labs/flux-1-kontext-dev": "https://api.runpod.ai/v2/black-forest-labs-flux-1-kontext-dev",
|
|
328
348
|
"black-forest-labs/flux-1-schnell": "https://api.runpod.ai/v2/black-forest-labs-flux-1-schnell",
|
|
329
|
-
"black-forest-labs/flux-1-dev": "https://api.runpod.ai/v2/black-forest-labs-flux-1-dev"
|
|
349
|
+
"black-forest-labs/flux-1-dev": "https://api.runpod.ai/v2/black-forest-labs-flux-1-dev",
|
|
350
|
+
// Nano Banana (edit only)
|
|
351
|
+
"nano-banana-edit": "https://api.runpod.ai/v2/nano-banana-edit"
|
|
330
352
|
};
|
|
331
353
|
var MODEL_ID_TO_OPENAI_NAME = {
|
|
332
|
-
"deep-cogito/deep-cogito-v2-llama-70b": "deepcogito/cogito-v2-preview-llama-70B",
|
|
333
354
|
"qwen/qwen3-32b-awq": "Qwen/Qwen3-32B-AWQ"
|
|
334
355
|
};
|
|
356
|
+
function deriveEndpointURL(modelId) {
|
|
357
|
+
const normalized = modelId.replace(/\//g, "-");
|
|
358
|
+
return `https://api.runpod.ai/v2/${normalized}/openai/v1`;
|
|
359
|
+
}
|
|
335
360
|
function createRunpod(options = {}) {
|
|
336
361
|
const getHeaders = () => ({
|
|
337
|
-
Authorization: `Bearer ${(0,
|
|
362
|
+
Authorization: `Bearer ${(0, import_provider_utils3.loadApiKey)({
|
|
338
363
|
apiKey: options.apiKey,
|
|
339
364
|
environmentVariableName: "RUNPOD_API_KEY",
|
|
340
365
|
description: "Runpod"
|
|
@@ -360,18 +385,11 @@ function createRunpod(options = {}) {
|
|
|
360
385
|
if (options.baseURL) {
|
|
361
386
|
baseURL = options.baseURL;
|
|
362
387
|
} else {
|
|
363
|
-
baseURL = MODEL_ID_TO_ENDPOINT_URL[modelId];
|
|
364
|
-
if (!baseURL) {
|
|
365
|
-
throw new Error(
|
|
366
|
-
`Unsupported Runpod model: ${modelId}. Supported models: ${Object.keys(
|
|
367
|
-
MODEL_ID_TO_ENDPOINT_URL
|
|
368
|
-
).join(", ")}. Or provide a custom baseURL.`
|
|
369
|
-
);
|
|
370
|
-
}
|
|
388
|
+
baseURL = MODEL_ID_TO_ENDPOINT_URL[modelId] || deriveEndpointURL(modelId);
|
|
371
389
|
}
|
|
372
390
|
return {
|
|
373
391
|
provider: `runpod.${modelType}`,
|
|
374
|
-
url: ({ path }) => `${(0,
|
|
392
|
+
url: ({ path }) => `${(0, import_provider_utils3.withoutTrailingSlash)(baseURL)}${path}`,
|
|
375
393
|
headers: getHeaders,
|
|
376
394
|
fetch: runpodFetch
|
|
377
395
|
};
|
|
@@ -395,14 +413,7 @@ function createRunpod(options = {}) {
|
|
|
395
413
|
if (options.baseURL) {
|
|
396
414
|
baseURL = options.baseURL;
|
|
397
415
|
} else {
|
|
398
|
-
baseURL = IMAGE_MODEL_ID_TO_ENDPOINT_URL[modelId];
|
|
399
|
-
if (!baseURL) {
|
|
400
|
-
throw new Error(
|
|
401
|
-
`Unsupported Runpod image model: ${modelId}. Supported models: ${Object.keys(
|
|
402
|
-
IMAGE_MODEL_ID_TO_ENDPOINT_URL
|
|
403
|
-
).join(", ")}. Or provide a custom baseURL.`
|
|
404
|
-
);
|
|
405
|
-
}
|
|
416
|
+
baseURL = IMAGE_MODEL_ID_TO_ENDPOINT_URL[modelId] || deriveEndpointURL(modelId);
|
|
406
417
|
}
|
|
407
418
|
return new RunpodImageModel(modelId, {
|
|
408
419
|
provider: "runpod.image",
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/runpod-provider.ts","../src/runpod-image-model.ts"],"sourcesContent":["export { createRunpod, runpod } from './runpod-provider';\nexport type { RunpodProvider, RunpodProviderSettings } from './runpod-provider';\nexport type { RunpodChatModelId } from './runpod-chat-options';\nexport type { RunpodCompletionModelId } from './runpod-completion-options';\nexport type { RunpodImageModelId } from './runpod-image-options';\nexport type { OpenAICompatibleErrorData as RunpodErrorData } from '@ai-sdk/openai-compatible';\n","import { LanguageModelV2, ImageModelV2 } from '@ai-sdk/provider';\nimport {\n OpenAICompatibleChatLanguageModel,\n OpenAICompatibleCompletionLanguageModel,\n} from '@ai-sdk/openai-compatible';\nimport {\n FetchFunction,\n loadApiKey,\n withoutTrailingSlash,\n} from '@ai-sdk/provider-utils';\nimport { RunpodChatModelId } from './runpod-chat-options';\nimport { RunpodCompletionModelId } from './runpod-completion-options';\nimport { RunpodImageModelId } from './runpod-image-options';\nimport { RunpodImageModel } from './runpod-image-model';\n\nexport interface RunpodProviderSettings {\n /**\nRunpod API key.\n*/\n apiKey?: string;\n /**\nCustom base URL for Runpod API. Use this to point to custom endpoints or different Runpod deployments.\nExample: 'https://api.runpod.ai/v2/your-endpoint-id/openai/v1'\n*/\n baseURL?: string;\n /**\nCustom headers to include in the requests.\n*/\n headers?: Record<string, string>;\n /**\nCustom fetch implementation. You can use it as a middleware to intercept requests,\nor to provide a custom fetch implementation for e.g. testing.\n*/\n fetch?: FetchFunction;\n}\n\nexport interface RunpodProvider {\n /**\nCreates a model for text generation.\n*/\n (modelId: RunpodChatModelId): LanguageModelV2;\n\n /**\nCreates a chat model for text generation.\n*/\n chatModel(modelId: RunpodChatModelId): LanguageModelV2;\n\n /**\nCreates a chat model for text generation.\n*/\n languageModel(modelId: RunpodChatModelId): LanguageModelV2;\n\n /**\nCreates a completion model for text generation.\n*/\n completionModel(modelId: RunpodCompletionModelId): LanguageModelV2;\n\n /**\nCreates an image model for image generation.\n*/\n imageModel(modelId: RunpodImageModelId): ImageModelV2;\n}\n\n// Mapping of Runpod model IDs to their endpoint URLs\nconst MODEL_ID_TO_ENDPOINT_URL: Record<string, string> = {\n 'deep-cogito/deep-cogito-v2-llama-70b':\n 'https://api.runpod.ai/v2/deep-cogito-v2-llama-70b/openai/v1',\n 'qwen/qwen3-32b-awq': 'https://api.runpod.ai/v2/qwen3-32b-awq/openai/v1',\n};\n\n// Mapping of Runpod image model IDs to their endpoint URLs\nconst IMAGE_MODEL_ID_TO_ENDPOINT_URL: Record<string, string> = {\n 'qwen/qwen-image': 'https://api.runpod.ai/v2/qwen-image-t2i',\n 'qwen/qwen-image-edit': 'https://api.runpod.ai/v2/qwen-image-edit',\n 'bytedance/seedream-3.0': 'https://api.runpod.ai/v2/seedream-3-0-t2i',\n // Seadream v4 (t2i and edit)\n 'bytedance/seedream-4.0': 'https://api.runpod.ai/v2/seedream-v4-t2i',\n 'bytedance/seedream-4.0-edit': 'https://api.runpod.ai/v2/seedream-v4-edit',\n 'black-forest-labs/flux-1-kontext-dev':\n 'https://api.runpod.ai/v2/black-forest-labs-flux-1-kontext-dev',\n 'black-forest-labs/flux-1-schnell':\n 'https://api.runpod.ai/v2/black-forest-labs-flux-1-schnell',\n 'black-forest-labs/flux-1-dev':\n 'https://api.runpod.ai/v2/black-forest-labs-flux-1-dev',\n};\n\n// Mapping of Runpod model IDs to their OpenAI model names\nconst MODEL_ID_TO_OPENAI_NAME: Record<string, string> = {\n 'deep-cogito/deep-cogito-v2-llama-70b':\n 'deepcogito/cogito-v2-preview-llama-70B',\n 'qwen/qwen3-32b-awq': 'Qwen/Qwen3-32B-AWQ',\n};\n\nexport function createRunpod(\n options: RunpodProviderSettings = {}\n): RunpodProvider {\n const getHeaders = () => ({\n Authorization: `Bearer ${loadApiKey({\n apiKey: options.apiKey,\n environmentVariableName: 'RUNPOD_API_KEY',\n description: 'Runpod',\n })}`,\n ...options.headers,\n });\n\n const runpodFetch: FetchFunction = async (url, requestInit) => {\n if (requestInit?.body) {\n try {\n const body = JSON.parse(requestInit.body as string);\n if (body.stream === true && !body.stream_options) {\n body.stream_options = { include_usage: true };\n requestInit.body = JSON.stringify(body);\n }\n } catch {}\n }\n const fetchFn = options.fetch || fetch;\n return fetchFn(url, requestInit);\n };\n\n interface CommonModelConfig {\n provider: string;\n url: ({ path }: { path: string }) => string;\n headers: () => Record<string, string>;\n fetch?: FetchFunction;\n }\n\n const getModelConfig = (\n modelId: string,\n modelType: string\n ): CommonModelConfig => {\n let baseURL: string;\n\n if (options.baseURL) {\n baseURL = options.baseURL;\n } else {\n baseURL = MODEL_ID_TO_ENDPOINT_URL[modelId];\n if (!baseURL) {\n throw new Error(\n `Unsupported Runpod model: ${modelId}. Supported models: ${Object.keys(\n MODEL_ID_TO_ENDPOINT_URL\n ).join(', ')}. Or provide a custom baseURL.`\n );\n }\n }\n\n return {\n provider: `runpod.${modelType}`,\n url: ({ path }) => `${withoutTrailingSlash(baseURL)}${path}`,\n headers: getHeaders,\n fetch: runpodFetch,\n };\n };\n\n const createChatModel = (modelId: RunpodChatModelId) => {\n const openaiModelName = MODEL_ID_TO_OPENAI_NAME[modelId] || modelId;\n return new OpenAICompatibleChatLanguageModel(openaiModelName, {\n ...getModelConfig(modelId, 'chat'),\n includeUsage: true,\n });\n };\n\n const createCompletionModel = (modelId: RunpodCompletionModelId) => {\n const openaiModelName = MODEL_ID_TO_OPENAI_NAME[modelId] || modelId;\n return new OpenAICompatibleCompletionLanguageModel(openaiModelName, {\n ...getModelConfig(modelId, 'completion'),\n includeUsage: true,\n });\n };\n\n const createImageModel = (modelId: RunpodImageModelId) => {\n let baseURL: string;\n\n if (options.baseURL) {\n baseURL = options.baseURL;\n } else {\n baseURL = IMAGE_MODEL_ID_TO_ENDPOINT_URL[modelId];\n if (!baseURL) {\n throw new Error(\n `Unsupported Runpod image model: ${modelId}. Supported models: ${Object.keys(\n IMAGE_MODEL_ID_TO_ENDPOINT_URL\n ).join(', ')}. Or provide a custom baseURL.`\n );\n }\n }\n\n return new RunpodImageModel(modelId, {\n provider: 'runpod.image',\n baseURL,\n headers: getHeaders,\n fetch: options.fetch,\n });\n };\n\n const provider = (modelId: RunpodChatModelId) => createChatModel(modelId);\n\n provider.completionModel = createCompletionModel;\n provider.languageModel = createChatModel;\n provider.chatModel = createChatModel;\n provider.imageModel = createImageModel;\n\n return provider;\n}\n\nexport const runpod = createRunpod();\n","import { ImageModelV2, ImageModelV2CallWarning } from '@ai-sdk/provider';\r\nimport {\r\n combineHeaders,\r\n createJsonResponseHandler,\r\n createJsonErrorResponseHandler,\r\n createBinaryResponseHandler,\r\n FetchFunction,\r\n postJsonToApi,\r\n getFromApi,\r\n} from '@ai-sdk/provider-utils';\r\nimport { InvalidArgumentError } from '@ai-sdk/provider';\r\nimport { z } from 'zod';\r\nimport { RunpodImageModelId } from './runpod-image-options';\r\n\r\ninterface RunpodImageModelConfig {\r\n provider: string;\r\n baseURL: string;\r\n headers: () => Record<string, string>;\r\n fetch?: FetchFunction;\r\n _internal?: {\r\n currentDate?: () => Date;\r\n };\r\n}\r\n\r\n// Runpod supported aspect ratios (only validated working sizes)\r\nconst SUPPORTED_ASPECT_RATIOS: Record<string, string> = {\r\n '1:1': '1328*1328', // ✅ Native support\r\n '4:3': '1472*1140', // ✅ Native support\r\n '3:4': '1140*1472', // ✅ Native support\r\n};\r\n\r\n// Runpod supported sizes (validated working sizes)\r\nconst SUPPORTED_SIZES = new Set([\r\n // Native aspect ratio sizes\r\n '1328*1328', // 1:1\r\n '1472*1140', // 4:3\r\n '1140*1472', // 3:4\r\n // Additional validated sizes\r\n '512*512',\r\n '768*768',\r\n '1024*1024',\r\n '1536*1536',\r\n '2048*2048',\r\n '4096*4096',\r\n '512*768',\r\n '768*512',\r\n '1024*768',\r\n '768*1024',\r\n]);\r\n\r\nexport class RunpodImageModel implements ImageModelV2 {\r\n readonly specificationVersion = 'v2';\r\n readonly maxImagesPerCall = 1;\r\n\r\n get provider(): string {\r\n return this.config.provider;\r\n }\r\n\r\n constructor(\r\n readonly modelId: RunpodImageModelId,\r\n private config: RunpodImageModelConfig\r\n ) {}\r\n\r\n async doGenerate({\r\n prompt,\r\n n = 1,\r\n size,\r\n aspectRatio,\r\n seed,\r\n providerOptions,\r\n headers,\r\n abortSignal,\r\n }: Parameters<ImageModelV2['doGenerate']>[0]): Promise<\r\n Awaited<ReturnType<ImageModelV2['doGenerate']>>\r\n > {\r\n const warnings: Array<ImageModelV2CallWarning> = [];\r\n\r\n // Determine the size to use\r\n let runpodSize: string;\r\n\r\n if (size) {\r\n // Convert AI SDK format \"1328x1328\" to Runpod format \"1328*1328\"\r\n const runpodSizeCandidate = size.replace('x', '*');\r\n\r\n // Validate size is supported\r\n if (!SUPPORTED_SIZES.has(runpodSizeCandidate)) {\r\n throw new InvalidArgumentError({\r\n argument: 'size',\r\n message: `Size ${size} is not supported by Runpod. Supported sizes: ${Array.from(\r\n SUPPORTED_SIZES\r\n )\r\n .map((s) => s.replace('*', 'x'))\r\n .join(', ')}`,\r\n });\r\n }\r\n\r\n runpodSize = runpodSizeCandidate;\r\n } else if (aspectRatio) {\r\n // Validate aspect ratio is supported\r\n if (!SUPPORTED_ASPECT_RATIOS[aspectRatio]) {\r\n throw new InvalidArgumentError({\r\n argument: 'aspectRatio',\r\n message: `Aspect ratio ${aspectRatio} is not supported by Runpod. Supported aspect ratios: ${Object.keys(SUPPORTED_ASPECT_RATIOS).join(', ')}`,\r\n });\r\n }\r\n\r\n // Use supported aspect ratio mapping\r\n runpodSize = SUPPORTED_ASPECT_RATIOS[aspectRatio];\r\n } else {\r\n // Default to square format\r\n runpodSize = '1328*1328';\r\n }\r\n\r\n // Handle multiple images warning\r\n if (n > 1) {\r\n warnings.push({\r\n type: 'unsupported-setting',\r\n setting: 'n',\r\n details:\r\n 'Runpod image models only support generating 1 image at a time. Using n=1.',\r\n });\r\n }\r\n\r\n const currentDate = this.config._internal?.currentDate?.() ?? new Date();\r\n\r\n // Runpod uses a different request format - /runsync endpoint with input wrapper\r\n const inputPayload = this.buildInputPayload(\r\n prompt,\r\n runpodSize,\r\n seed,\r\n providerOptions.runpod\r\n );\r\n\r\n const { value: response, responseHeaders } = await postJsonToApi({\r\n url: `${this.config.baseURL}/runsync`,\r\n headers: combineHeaders(this.config.headers(), headers),\r\n body: {\r\n input: inputPayload,\r\n },\r\n failedResponseHandler: createJsonErrorResponseHandler({\r\n errorSchema: runpodImageErrorSchema as any,\r\n errorToMessage: (data: any) => data.error ?? 'Unknown error',\r\n }),\r\n successfulResponseHandler: createJsonResponseHandler(\r\n runpodImageResponseSchema as any\r\n ),\r\n abortSignal,\r\n fetch: this.config.fetch,\r\n });\r\n\r\n // Handle both sync and async responses from Runpod\r\n const typedResponse = response as any;\r\n if (\r\n typedResponse.status === 'COMPLETED' &&\r\n (typedResponse.output?.result || typedResponse.output?.image_url)\r\n ) {\r\n // Sync response - image is ready\r\n // Different models use different response formats: result vs image_url\r\n const imageUrl =\r\n typedResponse.output.result || typedResponse.output.image_url;\r\n const imageData = await this.downloadImage(imageUrl, abortSignal);\r\n\r\n return {\r\n images: [imageData],\r\n warnings,\r\n response: {\r\n timestamp: currentDate,\r\n modelId: this.modelId,\r\n headers: responseHeaders,\r\n },\r\n providerMetadata: {\r\n runpod: {\r\n images: [\r\n {\r\n url: imageUrl,\r\n cost: typedResponse.output?.cost,\r\n },\r\n ],\r\n },\r\n },\r\n };\r\n } else if (\r\n typedResponse.status === 'IN_QUEUE' ||\r\n typedResponse.status === 'IN_PROGRESS'\r\n ) {\r\n // Async response - need to poll for completion\r\n const pollOptions = {\r\n maxAttempts: providerOptions.runpod?.maxPollAttempts as number,\r\n pollIntervalMillis: providerOptions.runpod\r\n ?.pollIntervalMillis as number,\r\n };\r\n const imageUrl = await this.pollForCompletion(\r\n typedResponse.id,\r\n abortSignal,\r\n pollOptions\r\n );\r\n const imageData = await this.downloadImage(imageUrl, abortSignal);\r\n\r\n return {\r\n images: [imageData],\r\n warnings,\r\n response: {\r\n timestamp: currentDate,\r\n modelId: this.modelId,\r\n headers: responseHeaders,\r\n },\r\n providerMetadata: {\r\n runpod: {\r\n images: [\r\n {\r\n url: imageUrl,\r\n jobId: typedResponse.id,\r\n },\r\n ],\r\n },\r\n },\r\n };\r\n } else {\r\n throw new Error(`Unexpected response status: ${typedResponse.status}`);\r\n }\r\n }\r\n\r\n private async downloadImage(\r\n imageUrl: string,\r\n abortSignal?: AbortSignal\r\n ): Promise<Uint8Array> {\r\n const { value: imageData } = await getFromApi({\r\n url: imageUrl,\r\n successfulResponseHandler: createBinaryResponseHandler(),\r\n failedResponseHandler: createJsonErrorResponseHandler({\r\n errorSchema: runpodImageErrorSchema as any,\r\n errorToMessage: (data: any) => data.error ?? 'Failed to download image',\r\n }),\r\n abortSignal,\r\n fetch: this.config.fetch,\r\n });\r\n return imageData;\r\n }\r\n\r\n private async pollForCompletion(\r\n jobId: string,\r\n abortSignal?: AbortSignal,\r\n pollOptions?: { maxAttempts?: number; pollIntervalMillis?: number }\r\n ): Promise<string> {\r\n const maxAttempts = pollOptions?.maxAttempts ?? 60; // 5 minutes with 5-second intervals\r\n const pollInterval = pollOptions?.pollIntervalMillis ?? 5000; // 5 seconds\r\n\r\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\r\n if (abortSignal?.aborted) {\r\n throw new Error('Image generation was aborted');\r\n }\r\n\r\n const { value: statusResponse } = await getFromApi({\r\n url: `${this.config.baseURL}/status/${jobId}`,\r\n headers: this.config.headers(),\r\n successfulResponseHandler: createJsonResponseHandler(\r\n runpodImageStatusSchema as any\r\n ),\r\n failedResponseHandler: createJsonErrorResponseHandler({\r\n errorSchema: runpodImageErrorSchema as any,\r\n errorToMessage: (data: any) =>\r\n data.error ?? 'Failed to check job status',\r\n }),\r\n abortSignal,\r\n fetch: this.config.fetch,\r\n });\r\n\r\n const typedStatusResponse = statusResponse as any;\r\n if (\r\n typedStatusResponse.status === 'COMPLETED' &&\r\n (typedStatusResponse.output?.result ||\r\n typedStatusResponse.output?.image_url)\r\n ) {\r\n return (\r\n typedStatusResponse.output.result ||\r\n typedStatusResponse.output.image_url\r\n );\r\n }\r\n\r\n if (typedStatusResponse.status === 'FAILED') {\r\n throw new Error(\r\n `Image generation failed: ${typedStatusResponse.error || 'Unknown error'}`\r\n );\r\n }\r\n\r\n // Wait before next poll\r\n await new Promise((resolve) => setTimeout(resolve, pollInterval));\r\n }\r\n\r\n throw new Error(\r\n `Image generation timed out after ${maxAttempts} attempts (${(maxAttempts * pollInterval) / 1000}s)`\r\n );\r\n }\r\n\r\n private buildInputPayload(\r\n prompt: string,\r\n runpodSize: string,\r\n seed?: number,\r\n runpodOptions?: Record<string, unknown>\r\n ): Record<string, unknown> {\r\n // Check if this is a Flux model that uses different parameters\r\n const isFluxModel =\r\n this.modelId.includes('flux') ||\r\n this.modelId.includes('black-forest-labs');\r\n\r\n if (isFluxModel) {\r\n // Check if this is Flux Kontext (uses different parameters)\r\n const isKontext = this.modelId.includes('kontext');\r\n\r\n if (isKontext) {\r\n // Flux Kontext uses size format and has image input\r\n return {\r\n prompt,\r\n negative_prompt: runpodOptions?.negative_prompt ?? '',\r\n seed: seed ?? -1,\r\n num_inference_steps: 28,\r\n guidance: 2,\r\n size: runpodSize,\r\n output_format: 'png',\r\n enable_safety_checker: runpodOptions?.enable_safety_checker ?? true,\r\n ...runpodOptions, // This will include the 'image' parameter if provided\r\n };\r\n } else {\r\n // Regular Flux models use width/height\r\n const [width, height] = runpodSize.split('*').map(Number);\r\n\r\n return {\r\n prompt,\r\n negative_prompt: runpodOptions?.negative_prompt ?? '',\r\n seed: seed ?? -1,\r\n num_inference_steps: this.modelId.includes('schnell') ? 4 : 28,\r\n guidance: this.modelId.includes('schnell') ? 7 : 2,\r\n width,\r\n height,\r\n image_format: 'png',\r\n ...runpodOptions,\r\n };\r\n }\r\n }\r\n\r\n // Default format for Qwen and other models\r\n return {\r\n prompt,\r\n negative_prompt: runpodOptions?.negative_prompt ?? '',\r\n size: runpodSize,\r\n seed: seed ?? -1,\r\n enable_safety_checker: runpodOptions?.enable_safety_checker ?? true,\r\n ...runpodOptions,\r\n };\r\n }\r\n}\r\n\r\n// Runpod image API response schema (handles both sync and async responses)\r\nconst runpodImageResponseSchema = z.object({\r\n id: z.string(),\r\n status: z.enum(['COMPLETED', 'IN_QUEUE', 'IN_PROGRESS', 'FAILED']),\r\n delayTime: z.number().optional(),\r\n executionTime: z.number().optional(),\r\n output: z\r\n .object({\r\n cost: z.number().optional(),\r\n result: z.string().optional(), // URL to the generated image (Qwen format)\r\n image_url: z.string().optional(), // URL to the generated image (Flux format)\r\n })\r\n .optional(), // Optional for IN_QUEUE/IN_PROGRESS responses\r\n});\r\n\r\n// Schema for polling status endpoint\r\nconst runpodImageStatusSchema = z.object({\r\n id: z.string(),\r\n status: z.enum(['COMPLETED', 'IN_QUEUE', 'IN_PROGRESS', 'FAILED']),\r\n output: z\r\n .object({\r\n cost: z.number().optional(),\r\n result: z.string().optional(),\r\n image_url: z.string().optional(),\r\n })\r\n .optional(),\r\n error: z.string().optional(), // Error message if FAILED\r\n});\r\n\r\n// Runpod image API error schema\r\nconst runpodImageErrorSchema = z.object({\r\n error: z.string(),\r\n message: z.string().optional(),\r\n});\r\n"],"mappings":"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","names":["import_provider_utils"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/runpod-provider.ts","../src/runpod-image-model.ts","../src/runpod-error.ts"],"sourcesContent":["export { createRunpod, runpod } from './runpod-provider';\nexport type { RunpodProvider, RunpodProviderSettings } from './runpod-provider';\nexport type { RunpodChatModelId } from './runpod-chat-options';\nexport type { RunpodCompletionModelId } from './runpod-completion-options';\nexport type { RunpodImageModelId } from './runpod-image-options';\nexport type { OpenAICompatibleErrorData as RunpodErrorData } from '@ai-sdk/openai-compatible';\nexport type { RunpodImageErrorData } from './runpod-error';\n","import { LanguageModelV2, ImageModelV2 } from '@ai-sdk/provider';\nimport {\n OpenAICompatibleChatLanguageModel,\n OpenAICompatibleCompletionLanguageModel,\n} from '@ai-sdk/openai-compatible';\nimport {\n FetchFunction,\n loadApiKey,\n withoutTrailingSlash,\n} from '@ai-sdk/provider-utils';\nimport { RunpodImageModel } from './runpod-image-model';\n\nexport interface RunpodProviderSettings {\n /**\nRunpod API key.\n*/\n apiKey?: string;\n /**\nCustom base URL for Runpod API. Use this to point to custom endpoints or different Runpod deployments.\nExample: 'https://api.runpod.ai/v2/your-endpoint-id/openai/v1'\n*/\n baseURL?: string;\n /**\nCustom headers to include in the requests.\n*/\n headers?: Record<string, string>;\n /**\nCustom fetch implementation. You can use it as a middleware to intercept requests,\nor to provide a custom fetch implementation for e.g. testing.\n*/\n fetch?: FetchFunction;\n}\n\nexport interface RunpodProvider {\n /**\nCreates a model for text generation.\n*/\n (modelId: string): LanguageModelV2;\n\n /**\nCreates a chat model for text generation.\n*/\n chatModel(modelId: string): LanguageModelV2;\n\n /**\nCreates a chat model for text generation.\n*/\n languageModel(modelId: string): LanguageModelV2;\n\n /**\nCreates a completion model for text generation.\n*/\n completionModel(modelId: string): LanguageModelV2;\n\n /**\nCreates an image model for image generation.\n*/\n imageModel(modelId: string): ImageModelV2;\n}\n\n// Mapping of Runpod model IDs to their endpoint URLs\nconst MODEL_ID_TO_ENDPOINT_URL: Record<string, string> = {\n 'qwen/qwen3-32b-awq': 'https://api.runpod.ai/v2/qwen3-32b-awq/openai/v1',\n 'ibm-granite/granite-4.0-h-small': 'https://api.runpod.ai/v2/granite-4-0-h-small/openai/v1',\n};\n\n// Mapping of Runpod image model IDs to their endpoint URLs\nconst IMAGE_MODEL_ID_TO_ENDPOINT_URL: Record<string, string> = {\n 'qwen/qwen-image': 'https://api.runpod.ai/v2/qwen-image-t2i',\n 'qwen/qwen-image-edit': 'https://api.runpod.ai/v2/qwen-image-edit',\n 'bytedance/seedream-3.0': 'https://api.runpod.ai/v2/seedream-3-0-t2i',\n // Seadream v4 (t2i and edit)\n 'bytedance/seedream-4.0': 'https://api.runpod.ai/v2/seedream-v4-t2i',\n 'bytedance/seedream-4.0-edit': 'https://api.runpod.ai/v2/seedream-v4-edit',\n 'black-forest-labs/flux-1-kontext-dev':\n 'https://api.runpod.ai/v2/black-forest-labs-flux-1-kontext-dev',\n 'black-forest-labs/flux-1-schnell':\n 'https://api.runpod.ai/v2/black-forest-labs-flux-1-schnell',\n 'black-forest-labs/flux-1-dev':\n 'https://api.runpod.ai/v2/black-forest-labs-flux-1-dev',\n // Nano Banana (edit only)\n 'nano-banana-edit': 'https://api.runpod.ai/v2/nano-banana-edit',\n};\n\n// Mapping of Runpod model IDs to their OpenAI model names\nconst MODEL_ID_TO_OPENAI_NAME: Record<string, string> = {\n 'qwen/qwen3-32b-awq': 'Qwen/Qwen3-32B-AWQ',\n};\n\n/**\n * Derives the endpoint URL for a model by replacing slashes with hyphens.\n * Example: 'ibm-granite/granite-4.0-h-small' -> 'https://api.runpod.ai/v2/ibm-granite-granite-4.0-h-small/openai/v1'\n */\nfunction deriveEndpointURL(modelId: string): string {\n const normalized = modelId.replace(/\\//g, '-');\n return `https://api.runpod.ai/v2/${normalized}/openai/v1`;\n}\n\nexport function createRunpod(\n options: RunpodProviderSettings = {}\n): RunpodProvider {\n const getHeaders = () => ({\n Authorization: `Bearer ${loadApiKey({\n apiKey: options.apiKey,\n environmentVariableName: 'RUNPOD_API_KEY',\n description: 'Runpod',\n })}`,\n ...options.headers,\n });\n\n const runpodFetch: FetchFunction = async (url, requestInit) => {\n if (requestInit?.body) {\n try {\n const body = JSON.parse(requestInit.body as string);\n if (body.stream === true && !body.stream_options) {\n body.stream_options = { include_usage: true };\n requestInit.body = JSON.stringify(body);\n }\n } catch {}\n }\n const fetchFn = options.fetch || fetch;\n return fetchFn(url, requestInit);\n };\n\n interface CommonModelConfig {\n provider: string;\n url: ({ path }: { path: string }) => string;\n headers: () => Record<string, string>;\n fetch?: FetchFunction;\n }\n\n const getModelConfig = (\n modelId: string,\n modelType: string\n ): CommonModelConfig => {\n let baseURL: string;\n\n if (options.baseURL) {\n baseURL = options.baseURL;\n } else {\n // Use hardcoded mapping if available, otherwise derive endpoint\n baseURL = MODEL_ID_TO_ENDPOINT_URL[modelId] || deriveEndpointURL(modelId);\n }\n\n return {\n provider: `runpod.${modelType}`,\n url: ({ path }) => `${withoutTrailingSlash(baseURL)}${path}`,\n headers: getHeaders,\n fetch: runpodFetch,\n };\n };\n\n const createChatModel = (modelId: string) => {\n const openaiModelName = MODEL_ID_TO_OPENAI_NAME[modelId] || modelId;\n return new OpenAICompatibleChatLanguageModel(openaiModelName, {\n ...getModelConfig(modelId, 'chat'),\n includeUsage: true,\n });\n };\n\n const createCompletionModel = (modelId: string) => {\n const openaiModelName = MODEL_ID_TO_OPENAI_NAME[modelId] || modelId;\n return new OpenAICompatibleCompletionLanguageModel(openaiModelName, {\n ...getModelConfig(modelId, 'completion'),\n includeUsage: true,\n });\n };\n\n const createImageModel = (modelId: string) => {\n let baseURL: string;\n\n if (options.baseURL) {\n baseURL = options.baseURL;\n } else {\n // Use hardcoded mapping if available, otherwise derive endpoint\n baseURL =\n IMAGE_MODEL_ID_TO_ENDPOINT_URL[modelId] || deriveEndpointURL(modelId);\n }\n\n return new RunpodImageModel(modelId, {\n provider: 'runpod.image',\n baseURL,\n headers: getHeaders,\n fetch: options.fetch,\n });\n };\n\n const provider = (modelId: string) => createChatModel(modelId);\n\n provider.completionModel = createCompletionModel;\n provider.languageModel = createChatModel;\n provider.chatModel = createChatModel;\n provider.imageModel = createImageModel;\n\n return provider;\n}\n\nexport const runpod = createRunpod();\n","import { ImageModelV2, ImageModelV2CallWarning } from '@ai-sdk/provider';\nimport {\n combineHeaders,\n createJsonResponseHandler,\n createBinaryResponseHandler,\n FetchFunction,\n postJsonToApi,\n getFromApi,\n} from '@ai-sdk/provider-utils';\nimport { InvalidArgumentError } from '@ai-sdk/provider';\nimport { z } from 'zod';\nimport { runpodImageFailedResponseHandler } from './runpod-error';\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\ninterface RunpodImageModelConfig {\n provider: string;\n baseURL: string;\n headers: () => Record<string, string>;\n fetch?: FetchFunction;\n _internal?: {\n currentDate?: () => Date;\n };\n}\n\n// Runpod supported aspect ratios (only validated working sizes)\nconst SUPPORTED_ASPECT_RATIOS: Record<string, string> = {\n '1:1': '1328*1328', // ✅ Native support\n '4:3': '1472*1140', // ✅ Native support\n '3:4': '1140*1472', // ✅ Native support\n};\n\n// Runpod supported sizes (validated working sizes)\nconst SUPPORTED_SIZES = new Set([\n // Native aspect ratio sizes\n '1328*1328', // 1:1\n '1472*1140', // 4:3\n '1140*1472', // 3:4\n // Additional validated sizes\n '512*512',\n '768*768',\n '1024*1024',\n '1536*1536',\n '2048*2048',\n '4096*4096',\n '512*768',\n '768*512',\n '1024*768',\n '768*1024',\n]);\n\nexport class RunpodImageModel implements ImageModelV2 {\n readonly specificationVersion = 'v2';\n readonly maxImagesPerCall = 1;\n\n get provider(): string {\n return this.config.provider;\n }\n\n constructor(\n readonly modelId: string,\n private config: RunpodImageModelConfig\n ) {}\n\n async doGenerate({\n prompt,\n n = 1,\n size,\n aspectRatio,\n seed,\n providerOptions,\n headers,\n abortSignal,\n }: Parameters<ImageModelV2['doGenerate']>[0]): Promise<\n Awaited<ReturnType<ImageModelV2['doGenerate']>>\n > {\n const warnings: Array<ImageModelV2CallWarning> = [];\n\n // Determine the size to use\n let runpodSize: string;\n\n if (size) {\n // Convert AI SDK format \"1328x1328\" to Runpod format \"1328*1328\"\n const runpodSizeCandidate = size.replace('x', '*');\n\n // Validate size is supported\n if (!SUPPORTED_SIZES.has(runpodSizeCandidate)) {\n throw new InvalidArgumentError({\n argument: 'size',\n message: `Size ${size} is not supported by Runpod. Supported sizes: ${Array.from(\n SUPPORTED_SIZES\n )\n .map((s) => s.replace('*', 'x'))\n .join(', ')}`,\n });\n }\n\n runpodSize = runpodSizeCandidate;\n } else if (aspectRatio) {\n // Validate aspect ratio is supported\n if (!SUPPORTED_ASPECT_RATIOS[aspectRatio]) {\n throw new InvalidArgumentError({\n argument: 'aspectRatio',\n message: `Aspect ratio ${aspectRatio} is not supported by Runpod. Supported aspect ratios: ${Object.keys(SUPPORTED_ASPECT_RATIOS).join(', ')}`,\n });\n }\n\n // Use supported aspect ratio mapping\n runpodSize = SUPPORTED_ASPECT_RATIOS[aspectRatio];\n } else {\n // Default to square format\n runpodSize = '1328*1328';\n }\n\n // Handle multiple images warning\n if (n > 1) {\n warnings.push({\n type: 'unsupported-setting',\n setting: 'n',\n details:\n 'Runpod image models only support generating 1 image at a time. Using n=1.',\n });\n }\n\n const currentDate = this.config._internal?.currentDate?.() ?? new Date();\n\n // Runpod uses a different request format - /runsync endpoint with input wrapper\n const inputPayload = this.buildInputPayload(\n prompt,\n runpodSize,\n seed,\n providerOptions.runpod\n );\n\n const { value: response, responseHeaders } = await postJsonToApi({\n url: `${this.config.baseURL}/runsync`,\n headers: combineHeaders(this.config.headers(), headers),\n body: {\n input: inputPayload,\n },\n failedResponseHandler: runpodImageFailedResponseHandler,\n successfulResponseHandler: createJsonResponseHandler(\n runpodImageResponseSchema as any\n ),\n abortSignal,\n fetch: this.config.fetch,\n });\n\n // Handle both sync and async responses from Runpod\n const typedResponse = response as any;\n if (\n typedResponse.status === 'COMPLETED' &&\n (typedResponse.output?.result || typedResponse.output?.image_url)\n ) {\n // Sync response - image is ready\n // Different models use different response formats: result vs image_url\n const imageUrl =\n typedResponse.output.result || typedResponse.output.image_url;\n const imageData = await this.downloadImage(imageUrl, abortSignal);\n\n return {\n images: [imageData],\n warnings,\n response: {\n timestamp: currentDate,\n modelId: this.modelId,\n headers: responseHeaders,\n },\n providerMetadata: {\n runpod: {\n images: [\n {\n url: imageUrl,\n cost: typedResponse.output?.cost,\n },\n ],\n },\n },\n };\n } else if (\n typedResponse.status === 'IN_QUEUE' ||\n typedResponse.status === 'IN_PROGRESS'\n ) {\n // Async response - need to poll for completion\n const pollOptions = {\n maxAttempts: providerOptions.runpod?.maxPollAttempts as number,\n pollIntervalMillis: providerOptions.runpod\n ?.pollIntervalMillis as number,\n };\n const imageUrl = await this.pollForCompletion(\n typedResponse.id,\n abortSignal,\n pollOptions\n );\n const imageData = await this.downloadImage(imageUrl, abortSignal);\n\n return {\n images: [imageData],\n warnings,\n response: {\n timestamp: currentDate,\n modelId: this.modelId,\n headers: responseHeaders,\n },\n providerMetadata: {\n runpod: {\n images: [\n {\n url: imageUrl,\n jobId: typedResponse.id,\n },\n ],\n },\n },\n };\n } else {\n throw new Error(`Unexpected response status: ${typedResponse.status}`);\n }\n }\n\n private async downloadImage(\n imageUrl: string,\n abortSignal?: AbortSignal\n ): Promise<Uint8Array> {\n const { value: imageData } = await getFromApi({\n url: imageUrl,\n successfulResponseHandler: createBinaryResponseHandler(),\n failedResponseHandler: runpodImageFailedResponseHandler,\n abortSignal,\n fetch: this.config.fetch,\n });\n return imageData;\n }\n\n private async pollForCompletion(\n jobId: string,\n abortSignal?: AbortSignal,\n pollOptions?: { maxAttempts?: number; pollIntervalMillis?: number }\n ): Promise<string> {\n const maxAttempts = pollOptions?.maxAttempts ?? 60; // 5 minutes with 5-second intervals\n const pollInterval = pollOptions?.pollIntervalMillis ?? 5000; // 5 seconds\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n if (abortSignal?.aborted) {\n throw new Error('Image generation was aborted');\n }\n\n const { value: statusResponse } = await getFromApi({\n url: `${this.config.baseURL}/status/${jobId}`,\n headers: this.config.headers(),\n successfulResponseHandler: createJsonResponseHandler(\n runpodImageStatusSchema as any\n ),\n failedResponseHandler: runpodImageFailedResponseHandler,\n abortSignal,\n fetch: this.config.fetch,\n });\n\n const typedStatusResponse = statusResponse as any;\n if (\n typedStatusResponse.status === 'COMPLETED' &&\n (typedStatusResponse.output?.result ||\n typedStatusResponse.output?.image_url)\n ) {\n return (\n typedStatusResponse.output.result ||\n typedStatusResponse.output.image_url\n );\n }\n\n if (typedStatusResponse.status === 'FAILED') {\n throw new Error(\n `Image generation failed: ${typedStatusResponse.error || 'Unknown error'}`\n );\n }\n\n // Wait before next poll\n await new Promise((resolve) => setTimeout(resolve, pollInterval));\n }\n\n throw new Error(\n `Image generation timed out after ${maxAttempts} attempts (${(maxAttempts * pollInterval) / 1000}s)`\n );\n }\n\n private buildInputPayload(\n prompt: string,\n runpodSize: string,\n seed?: number,\n runpodOptions?: Record<string, unknown>\n ): Record<string, unknown> {\n // Check if this is a Flux model that uses different parameters\n const isFluxModel =\n this.modelId.includes('flux') ||\n this.modelId.includes('black-forest-labs');\n\n if (isFluxModel) {\n // Check if this is Flux Kontext (uses different parameters)\n const isKontext = this.modelId.includes('kontext');\n\n if (isKontext) {\n // Flux Kontext uses size format and has image input\n return {\n prompt,\n negative_prompt: runpodOptions?.negative_prompt ?? '',\n seed: seed ?? -1,\n num_inference_steps: 28,\n guidance: 2,\n size: runpodSize,\n output_format: 'png',\n enable_safety_checker: runpodOptions?.enable_safety_checker ?? true,\n ...runpodOptions, // This will include the 'image' parameter if provided\n };\n } else {\n // Regular Flux models use width/height\n const [width, height] = runpodSize.split('*').map(Number);\n\n return {\n prompt,\n negative_prompt: runpodOptions?.negative_prompt ?? '',\n seed: seed ?? -1,\n num_inference_steps: this.modelId.includes('schnell') ? 4 : 28,\n guidance: this.modelId.includes('schnell') ? 7 : 2,\n width,\n height,\n image_format: 'png',\n ...runpodOptions,\n };\n }\n }\n\n // Default format for Qwen and other models\n return {\n prompt,\n negative_prompt: runpodOptions?.negative_prompt ?? '',\n size: runpodSize,\n seed: seed ?? -1,\n enable_safety_checker: runpodOptions?.enable_safety_checker ?? true,\n ...runpodOptions,\n };\n }\n}\n\n// Runpod image API response schema (handles both sync and async responses)\nconst runpodImageResponseSchema = z.object({\n id: z.string(),\n status: z.enum(['COMPLETED', 'IN_QUEUE', 'IN_PROGRESS', 'FAILED']),\n delayTime: z.number().optional(),\n executionTime: z.number().optional(),\n output: z\n .object({\n cost: z.number().optional(),\n result: z.string().optional(), // URL to the generated image (Qwen format)\n image_url: z.string().optional(), // URL to the generated image (Flux format)\n })\n .optional(), // Optional for IN_QUEUE/IN_PROGRESS responses\n});\n\n// Schema for polling status endpoint\nconst runpodImageStatusSchema = z.object({\n id: z.string(),\n status: z.enum(['COMPLETED', 'IN_QUEUE', 'IN_PROGRESS', 'FAILED']),\n output: z\n .object({\n cost: z.number().optional(),\n result: z.string().optional(),\n image_url: z.string().optional(),\n })\n .optional(),\n error: z.string().optional(), // Error message if FAILED\n});\n","import { z } from 'zod';\r\nimport { createJsonErrorResponseHandler } from '@ai-sdk/provider-utils';\r\n\r\n// Runpod image API error schema (supports both error formats)\r\nexport const runpodImageErrorSchema = z.object({\r\n error: z.string().optional(),\r\n message: z.string().optional(),\r\n});\r\n\r\nexport type RunpodImageErrorData = z.infer<typeof runpodImageErrorSchema>;\r\n\r\nexport const runpodImageFailedResponseHandler = createJsonErrorResponseHandler({\r\n errorSchema: runpodImageErrorSchema as any,\r\n errorToMessage: (data: RunpodImageErrorData) => {\r\n // Prefer message if available (more descriptive)\r\n if (data.message) {\r\n return data.message;\r\n }\r\n \r\n // If error field exists, try to extract nested JSON message\r\n if (data.error) {\r\n // Runpod sometimes returns nested JSON in the error field like:\r\n // \"Error submitting task: 400, {\\\"code\\\":400,\\\"message\\\":\\\"...\\\"}\"\r\n // Try to extract the inner message for cleaner error messages\r\n // Find the last occurrence of { which likely starts the JSON object\r\n const lastBraceIndex = data.error.lastIndexOf('{');\r\n if (lastBraceIndex !== -1) {\r\n try {\r\n const jsonStr = data.error.substring(lastBraceIndex);\r\n const nestedError = JSON.parse(jsonStr);\r\n if (nestedError.message && typeof nestedError.message === 'string') {\r\n return nestedError.message;\r\n }\r\n } catch {\r\n // If parsing fails, fall back to the original error string\r\n }\r\n }\r\n return data.error;\r\n }\r\n \r\n return 'Unknown Runpod error';\r\n },\r\n});\r\n\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACCA,+BAGO;AACP,IAAAA,yBAIO;;;ACRP,IAAAC,yBAOO;AACP,sBAAqC;AACrC,IAAAC,cAAkB;;;ACVlB,iBAAkB;AAClB,4BAA+C;AAGxC,IAAM,yBAAyB,aAAE,OAAO;AAAA,EAC7C,OAAO,aAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,SAAS,aAAE,OAAO,EAAE,SAAS;AAC/B,CAAC;AAIM,IAAM,uCAAmC,sDAA+B;AAAA,EAC7E,aAAa;AAAA,EACb,gBAAgB,CAAC,SAA+B;AAE9C,QAAI,KAAK,SAAS;AAChB,aAAO,KAAK;AAAA,IACd;AAGA,QAAI,KAAK,OAAO;AAKd,YAAM,iBAAiB,KAAK,MAAM,YAAY,GAAG;AACjD,UAAI,mBAAmB,IAAI;AACzB,YAAI;AACF,gBAAM,UAAU,KAAK,MAAM,UAAU,cAAc;AACnD,gBAAM,cAAc,KAAK,MAAM,OAAO;AACtC,cAAI,YAAY,WAAW,OAAO,YAAY,YAAY,UAAU;AAClE,mBAAO,YAAY;AAAA,UACrB;AAAA,QACF,QAAQ;AAAA,QAER;AAAA,MACF;AACA,aAAO,KAAK;AAAA,IACd;AAEA,WAAO;AAAA,EACT;AACF,CAAC;;;ADjBD,IAAM,0BAAkD;AAAA,EACtD,OAAO;AAAA;AAAA,EACP,OAAO;AAAA;AAAA,EACP,OAAO;AAAA;AACT;AAGA,IAAM,kBAAkB,oBAAI,IAAI;AAAA;AAAA,EAE9B;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,IAAM,mBAAN,MAA+C;AAAA,EAQpD,YACW,SACD,QACR;AAFS;AACD;AATV,SAAS,uBAAuB;AAChC,SAAS,mBAAmB;AAAA,EASzB;AAAA,EAPH,IAAI,WAAmB;AACrB,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA,EAOA,MAAM,WAAW;AAAA,IACf;AAAA,IACA,IAAI;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAEE;AACA,UAAM,WAA2C,CAAC;AAGlD,QAAI;AAEJ,QAAI,MAAM;AAER,YAAM,sBAAsB,KAAK,QAAQ,KAAK,GAAG;AAGjD,UAAI,CAAC,gBAAgB,IAAI,mBAAmB,GAAG;AAC7C,cAAM,IAAI,qCAAqB;AAAA,UAC7B,UAAU;AAAA,UACV,SAAS,QAAQ,IAAI,iDAAiD,MAAM;AAAA,YAC1E;AAAA,UACF,EACG,IAAI,CAAC,MAAM,EAAE,QAAQ,KAAK,GAAG,CAAC,EAC9B,KAAK,IAAI,CAAC;AAAA,QACf,CAAC;AAAA,MACH;AAEA,mBAAa;AAAA,IACf,WAAW,aAAa;AAEtB,UAAI,CAAC,wBAAwB,WAAW,GAAG;AACzC,cAAM,IAAI,qCAAqB;AAAA,UAC7B,UAAU;AAAA,UACV,SAAS,gBAAgB,WAAW,yDAAyD,OAAO,KAAK,uBAAuB,EAAE,KAAK,IAAI,CAAC;AAAA,QAC9I,CAAC;AAAA,MACH;AAGA,mBAAa,wBAAwB,WAAW;AAAA,IAClD,OAAO;AAEL,mBAAa;AAAA,IACf;AAGA,QAAI,IAAI,GAAG;AACT,eAAS,KAAK;AAAA,QACZ,MAAM;AAAA,QACN,SAAS;AAAA,QACT,SACE;AAAA,MACJ,CAAC;AAAA,IACH;AAEA,UAAM,cAAc,KAAK,OAAO,WAAW,cAAc,KAAK,oBAAI,KAAK;AAGvE,UAAM,eAAe,KAAK;AAAA,MACxB;AAAA,MACA;AAAA,MACA;AAAA,MACA,gBAAgB;AAAA,IAClB;AAEA,UAAM,EAAE,OAAO,UAAU,gBAAgB,IAAI,UAAM,sCAAc;AAAA,MAC/D,KAAK,GAAG,KAAK,OAAO,OAAO;AAAA,MAC3B,aAAS,uCAAe,KAAK,OAAO,QAAQ,GAAG,OAAO;AAAA,MACtD,MAAM;AAAA,QACJ,OAAO;AAAA,MACT;AAAA,MACA,uBAAuB;AAAA,MACvB,+BAA2B;AAAA,QACzB;AAAA,MACF;AAAA,MACA;AAAA,MACA,OAAO,KAAK,OAAO;AAAA,IACrB,CAAC;AAGD,UAAM,gBAAgB;AACtB,QACE,cAAc,WAAW,gBACxB,cAAc,QAAQ,UAAU,cAAc,QAAQ,YACvD;AAGA,YAAM,WACJ,cAAc,OAAO,UAAU,cAAc,OAAO;AACtD,YAAM,YAAY,MAAM,KAAK,cAAc,UAAU,WAAW;AAEhE,aAAO;AAAA,QACL,QAAQ,CAAC,SAAS;AAAA,QAClB;AAAA,QACA,UAAU;AAAA,UACR,WAAW;AAAA,UACX,SAAS,KAAK;AAAA,UACd,SAAS;AAAA,QACX;AAAA,QACA,kBAAkB;AAAA,UAChB,QAAQ;AAAA,YACN,QAAQ;AAAA,cACN;AAAA,gBACE,KAAK;AAAA,gBACL,MAAM,cAAc,QAAQ;AAAA,cAC9B;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF,WACE,cAAc,WAAW,cACzB,cAAc,WAAW,eACzB;AAEA,YAAM,cAAc;AAAA,QAClB,aAAa,gBAAgB,QAAQ;AAAA,QACrC,oBAAoB,gBAAgB,QAChC;AAAA,MACN;AACA,YAAM,WAAW,MAAM,KAAK;AAAA,QAC1B,cAAc;AAAA,QACd;AAAA,QACA;AAAA,MACF;AACA,YAAM,YAAY,MAAM,KAAK,cAAc,UAAU,WAAW;AAEhE,aAAO;AAAA,QACL,QAAQ,CAAC,SAAS;AAAA,QAClB;AAAA,QACA,UAAU;AAAA,UACR,WAAW;AAAA,UACX,SAAS,KAAK;AAAA,UACd,SAAS;AAAA,QACX;AAAA,QACA,kBAAkB;AAAA,UAChB,QAAQ;AAAA,YACN,QAAQ;AAAA,cACN;AAAA,gBACE,KAAK;AAAA,gBACL,OAAO,cAAc;AAAA,cACvB;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF,OAAO;AACL,YAAM,IAAI,MAAM,+BAA+B,cAAc,MAAM,EAAE;AAAA,IACvE;AAAA,EACF;AAAA,EAEA,MAAc,cACZ,UACA,aACqB;AACrB,UAAM,EAAE,OAAO,UAAU,IAAI,UAAM,mCAAW;AAAA,MAC5C,KAAK;AAAA,MACL,+BAA2B,oDAA4B;AAAA,MACvD,uBAAuB;AAAA,MACvB;AAAA,MACA,OAAO,KAAK,OAAO;AAAA,IACrB,CAAC;AACD,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,kBACZ,OACA,aACA,aACiB;AACjB,UAAM,cAAc,aAAa,eAAe;AAChD,UAAM,eAAe,aAAa,sBAAsB;AAExD,aAAS,UAAU,GAAG,UAAU,aAAa,WAAW;AACtD,UAAI,aAAa,SAAS;AACxB,cAAM,IAAI,MAAM,8BAA8B;AAAA,MAChD;AAEA,YAAM,EAAE,OAAO,eAAe,IAAI,UAAM,mCAAW;AAAA,QACjD,KAAK,GAAG,KAAK,OAAO,OAAO,WAAW,KAAK;AAAA,QAC3C,SAAS,KAAK,OAAO,QAAQ;AAAA,QAC7B,+BAA2B;AAAA,UACzB;AAAA,QACF;AAAA,QACA,uBAAuB;AAAA,QACvB;AAAA,QACA,OAAO,KAAK,OAAO;AAAA,MACrB,CAAC;AAED,YAAM,sBAAsB;AAC5B,UACE,oBAAoB,WAAW,gBAC9B,oBAAoB,QAAQ,UAC3B,oBAAoB,QAAQ,YAC9B;AACA,eACE,oBAAoB,OAAO,UAC3B,oBAAoB,OAAO;AAAA,MAE/B;AAEA,UAAI,oBAAoB,WAAW,UAAU;AAC3C,cAAM,IAAI;AAAA,UACR,4BAA4B,oBAAoB,SAAS,eAAe;AAAA,QAC1E;AAAA,MACF;AAGA,YAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,YAAY,CAAC;AAAA,IAClE;AAEA,UAAM,IAAI;AAAA,MACR,oCAAoC,WAAW,cAAe,cAAc,eAAgB,GAAI;AAAA,IAClG;AAAA,EACF;AAAA,EAEQ,kBACN,QACA,YACA,MACA,eACyB;AAEzB,UAAM,cACJ,KAAK,QAAQ,SAAS,MAAM,KAC5B,KAAK,QAAQ,SAAS,mBAAmB;AAE3C,QAAI,aAAa;AAEf,YAAM,YAAY,KAAK,QAAQ,SAAS,SAAS;AAEjD,UAAI,WAAW;AAEb,eAAO;AAAA,UACL;AAAA,UACA,iBAAiB,eAAe,mBAAmB;AAAA,UACnD,MAAM,QAAQ;AAAA,UACd,qBAAqB;AAAA,UACrB,UAAU;AAAA,UACV,MAAM;AAAA,UACN,eAAe;AAAA,UACf,uBAAuB,eAAe,yBAAyB;AAAA,UAC/D,GAAG;AAAA;AAAA,QACL;AAAA,MACF,OAAO;AAEL,cAAM,CAAC,OAAO,MAAM,IAAI,WAAW,MAAM,GAAG,EAAE,IAAI,MAAM;AAExD,eAAO;AAAA,UACL;AAAA,UACA,iBAAiB,eAAe,mBAAmB;AAAA,UACnD,MAAM,QAAQ;AAAA,UACd,qBAAqB,KAAK,QAAQ,SAAS,SAAS,IAAI,IAAI;AAAA,UAC5D,UAAU,KAAK,QAAQ,SAAS,SAAS,IAAI,IAAI;AAAA,UACjD;AAAA,UACA;AAAA,UACA,cAAc;AAAA,UACd,GAAG;AAAA,QACL;AAAA,MACF;AAAA,IACF;AAGA,WAAO;AAAA,MACL;AAAA,MACA,iBAAiB,eAAe,mBAAmB;AAAA,MACnD,MAAM;AAAA,MACN,MAAM,QAAQ;AAAA,MACd,uBAAuB,eAAe,yBAAyB;AAAA,MAC/D,GAAG;AAAA,IACL;AAAA,EACF;AACF;AAGA,IAAM,4BAA4B,cAAE,OAAO;AAAA,EACzC,IAAI,cAAE,OAAO;AAAA,EACb,QAAQ,cAAE,KAAK,CAAC,aAAa,YAAY,eAAe,QAAQ,CAAC;AAAA,EACjE,WAAW,cAAE,OAAO,EAAE,SAAS;AAAA,EAC/B,eAAe,cAAE,OAAO,EAAE,SAAS;AAAA,EACnC,QAAQ,cACL,OAAO;AAAA,IACN,MAAM,cAAE,OAAO,EAAE,SAAS;AAAA,IAC1B,QAAQ,cAAE,OAAO,EAAE,SAAS;AAAA;AAAA,IAC5B,WAAW,cAAE,OAAO,EAAE,SAAS;AAAA;AAAA,EACjC,CAAC,EACA,SAAS;AAAA;AACd,CAAC;AAGD,IAAM,0BAA0B,cAAE,OAAO;AAAA,EACvC,IAAI,cAAE,OAAO;AAAA,EACb,QAAQ,cAAE,KAAK,CAAC,aAAa,YAAY,eAAe,QAAQ,CAAC;AAAA,EACjE,QAAQ,cACL,OAAO;AAAA,IACN,MAAM,cAAE,OAAO,EAAE,SAAS;AAAA,IAC1B,QAAQ,cAAE,OAAO,EAAE,SAAS;AAAA,IAC5B,WAAW,cAAE,OAAO,EAAE,SAAS;AAAA,EACjC,CAAC,EACA,SAAS;AAAA,EACZ,OAAO,cAAE,OAAO,EAAE,SAAS;AAAA;AAC7B,CAAC;;;ADpTD,IAAM,2BAAmD;AAAA,EACvD,sBAAsB;AAAA,EACtB,mCAAmC;AACrC;AAGA,IAAM,iCAAyD;AAAA,EAC7D,mBAAmB;AAAA,EACnB,wBAAwB;AAAA,EACxB,0BAA0B;AAAA;AAAA,EAE1B,0BAA0B;AAAA,EAC1B,+BAA+B;AAAA,EAC/B,wCACE;AAAA,EACF,oCACE;AAAA,EACF,gCACE;AAAA;AAAA,EAEF,oBAAoB;AACtB;AAGA,IAAM,0BAAkD;AAAA,EACtD,sBAAsB;AACxB;AAMA,SAAS,kBAAkB,SAAyB;AAClD,QAAM,aAAa,QAAQ,QAAQ,OAAO,GAAG;AAC7C,SAAO,4BAA4B,UAAU;AAC/C;AAEO,SAAS,aACd,UAAkC,CAAC,GACnB;AAChB,QAAM,aAAa,OAAO;AAAA,IACxB,eAAe,cAAU,mCAAW;AAAA,MAClC,QAAQ,QAAQ;AAAA,MAChB,yBAAyB;AAAA,MACzB,aAAa;AAAA,IACf,CAAC,CAAC;AAAA,IACF,GAAG,QAAQ;AAAA,EACb;AAEA,QAAM,cAA6B,OAAO,KAAK,gBAAgB;AAC7D,QAAI,aAAa,MAAM;AACrB,UAAI;AACF,cAAM,OAAO,KAAK,MAAM,YAAY,IAAc;AAClD,YAAI,KAAK,WAAW,QAAQ,CAAC,KAAK,gBAAgB;AAChD,eAAK,iBAAiB,EAAE,eAAe,KAAK;AAC5C,sBAAY,OAAO,KAAK,UAAU,IAAI;AAAA,QACxC;AAAA,MACF,QAAQ;AAAA,MAAC;AAAA,IACX;AACA,UAAM,UAAU,QAAQ,SAAS;AACjC,WAAO,QAAQ,KAAK,WAAW;AAAA,EACjC;AASA,QAAM,iBAAiB,CACrB,SACA,cACsB;AACtB,QAAI;AAEJ,QAAI,QAAQ,SAAS;AACnB,gBAAU,QAAQ;AAAA,IACpB,OAAO;AAEL,gBAAU,yBAAyB,OAAO,KAAK,kBAAkB,OAAO;AAAA,IAC1E;AAEA,WAAO;AAAA,MACL,UAAU,UAAU,SAAS;AAAA,MAC7B,KAAK,CAAC,EAAE,KAAK,MAAM,OAAG,6CAAqB,OAAO,CAAC,GAAG,IAAI;AAAA,MAC1D,SAAS;AAAA,MACT,OAAO;AAAA,IACT;AAAA,EACF;AAEA,QAAM,kBAAkB,CAAC,YAAoB;AAC3C,UAAM,kBAAkB,wBAAwB,OAAO,KAAK;AAC5D,WAAO,IAAI,2DAAkC,iBAAiB;AAAA,MAC5D,GAAG,eAAe,SAAS,MAAM;AAAA,MACjC,cAAc;AAAA,IAChB,CAAC;AAAA,EACH;AAEA,QAAM,wBAAwB,CAAC,YAAoB;AACjD,UAAM,kBAAkB,wBAAwB,OAAO,KAAK;AAC5D,WAAO,IAAI,iEAAwC,iBAAiB;AAAA,MAClE,GAAG,eAAe,SAAS,YAAY;AAAA,MACvC,cAAc;AAAA,IAChB,CAAC;AAAA,EACH;AAEA,QAAM,mBAAmB,CAAC,YAAoB;AAC5C,QAAI;AAEJ,QAAI,QAAQ,SAAS;AACnB,gBAAU,QAAQ;AAAA,IACpB,OAAO;AAEL,gBACE,+BAA+B,OAAO,KAAK,kBAAkB,OAAO;AAAA,IACxE;AAEA,WAAO,IAAI,iBAAiB,SAAS;AAAA,MACnC,UAAU;AAAA,MACV;AAAA,MACA,SAAS;AAAA,MACT,OAAO,QAAQ;AAAA,IACjB,CAAC;AAAA,EACH;AAEA,QAAM,WAAW,CAAC,YAAoB,gBAAgB,OAAO;AAE7D,WAAS,kBAAkB;AAC3B,WAAS,gBAAgB;AACzB,WAAS,YAAY;AACrB,WAAS,aAAa;AAEtB,SAAO;AACT;AAEO,IAAM,SAAS,aAAa;","names":["import_provider_utils","import_provider_utils","import_zod"]}
|
package/dist/index.mjs
CHANGED
|
@@ -12,13 +12,45 @@ import {
|
|
|
12
12
|
import {
|
|
13
13
|
combineHeaders,
|
|
14
14
|
createJsonResponseHandler,
|
|
15
|
-
createJsonErrorResponseHandler,
|
|
16
15
|
createBinaryResponseHandler,
|
|
17
16
|
postJsonToApi,
|
|
18
17
|
getFromApi
|
|
19
18
|
} from "@ai-sdk/provider-utils";
|
|
20
19
|
import { InvalidArgumentError } from "@ai-sdk/provider";
|
|
20
|
+
import { z as z2 } from "zod";
|
|
21
|
+
|
|
22
|
+
// src/runpod-error.ts
|
|
21
23
|
import { z } from "zod";
|
|
24
|
+
import { createJsonErrorResponseHandler } from "@ai-sdk/provider-utils";
|
|
25
|
+
var runpodImageErrorSchema = z.object({
|
|
26
|
+
error: z.string().optional(),
|
|
27
|
+
message: z.string().optional()
|
|
28
|
+
});
|
|
29
|
+
var runpodImageFailedResponseHandler = createJsonErrorResponseHandler({
|
|
30
|
+
errorSchema: runpodImageErrorSchema,
|
|
31
|
+
errorToMessage: (data) => {
|
|
32
|
+
if (data.message) {
|
|
33
|
+
return data.message;
|
|
34
|
+
}
|
|
35
|
+
if (data.error) {
|
|
36
|
+
const lastBraceIndex = data.error.lastIndexOf("{");
|
|
37
|
+
if (lastBraceIndex !== -1) {
|
|
38
|
+
try {
|
|
39
|
+
const jsonStr = data.error.substring(lastBraceIndex);
|
|
40
|
+
const nestedError = JSON.parse(jsonStr);
|
|
41
|
+
if (nestedError.message && typeof nestedError.message === "string") {
|
|
42
|
+
return nestedError.message;
|
|
43
|
+
}
|
|
44
|
+
} catch {
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return data.error;
|
|
48
|
+
}
|
|
49
|
+
return "Unknown Runpod error";
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// src/runpod-image-model.ts
|
|
22
54
|
var SUPPORTED_ASPECT_RATIOS = {
|
|
23
55
|
"1:1": "1328*1328",
|
|
24
56
|
// ✅ Native support
|
|
@@ -111,10 +143,7 @@ var RunpodImageModel = class {
|
|
|
111
143
|
body: {
|
|
112
144
|
input: inputPayload
|
|
113
145
|
},
|
|
114
|
-
failedResponseHandler:
|
|
115
|
-
errorSchema: runpodImageErrorSchema,
|
|
116
|
-
errorToMessage: (data) => data.error ?? "Unknown error"
|
|
117
|
-
}),
|
|
146
|
+
failedResponseHandler: runpodImageFailedResponseHandler,
|
|
118
147
|
successfulResponseHandler: createJsonResponseHandler(
|
|
119
148
|
runpodImageResponseSchema
|
|
120
149
|
),
|
|
@@ -182,10 +211,7 @@ var RunpodImageModel = class {
|
|
|
182
211
|
const { value: imageData } = await getFromApi({
|
|
183
212
|
url: imageUrl,
|
|
184
213
|
successfulResponseHandler: createBinaryResponseHandler(),
|
|
185
|
-
failedResponseHandler:
|
|
186
|
-
errorSchema: runpodImageErrorSchema,
|
|
187
|
-
errorToMessage: (data) => data.error ?? "Failed to download image"
|
|
188
|
-
}),
|
|
214
|
+
failedResponseHandler: runpodImageFailedResponseHandler,
|
|
189
215
|
abortSignal,
|
|
190
216
|
fetch: this.config.fetch
|
|
191
217
|
});
|
|
@@ -204,10 +230,7 @@ var RunpodImageModel = class {
|
|
|
204
230
|
successfulResponseHandler: createJsonResponseHandler(
|
|
205
231
|
runpodImageStatusSchema
|
|
206
232
|
),
|
|
207
|
-
failedResponseHandler:
|
|
208
|
-
errorSchema: runpodImageErrorSchema,
|
|
209
|
-
errorToMessage: (data) => data.error ?? "Failed to check job status"
|
|
210
|
-
}),
|
|
233
|
+
failedResponseHandler: runpodImageFailedResponseHandler,
|
|
211
234
|
abortSignal,
|
|
212
235
|
fetch: this.config.fetch
|
|
213
236
|
});
|
|
@@ -268,40 +291,36 @@ var RunpodImageModel = class {
|
|
|
268
291
|
};
|
|
269
292
|
}
|
|
270
293
|
};
|
|
271
|
-
var runpodImageResponseSchema =
|
|
272
|
-
id:
|
|
273
|
-
status:
|
|
274
|
-
delayTime:
|
|
275
|
-
executionTime:
|
|
276
|
-
output:
|
|
277
|
-
cost:
|
|
278
|
-
result:
|
|
294
|
+
var runpodImageResponseSchema = z2.object({
|
|
295
|
+
id: z2.string(),
|
|
296
|
+
status: z2.enum(["COMPLETED", "IN_QUEUE", "IN_PROGRESS", "FAILED"]),
|
|
297
|
+
delayTime: z2.number().optional(),
|
|
298
|
+
executionTime: z2.number().optional(),
|
|
299
|
+
output: z2.object({
|
|
300
|
+
cost: z2.number().optional(),
|
|
301
|
+
result: z2.string().optional(),
|
|
279
302
|
// URL to the generated image (Qwen format)
|
|
280
|
-
image_url:
|
|
303
|
+
image_url: z2.string().optional()
|
|
281
304
|
// URL to the generated image (Flux format)
|
|
282
305
|
}).optional()
|
|
283
306
|
// Optional for IN_QUEUE/IN_PROGRESS responses
|
|
284
307
|
});
|
|
285
|
-
var runpodImageStatusSchema =
|
|
286
|
-
id:
|
|
287
|
-
status:
|
|
288
|
-
output:
|
|
289
|
-
cost:
|
|
290
|
-
result:
|
|
291
|
-
image_url:
|
|
308
|
+
var runpodImageStatusSchema = z2.object({
|
|
309
|
+
id: z2.string(),
|
|
310
|
+
status: z2.enum(["COMPLETED", "IN_QUEUE", "IN_PROGRESS", "FAILED"]),
|
|
311
|
+
output: z2.object({
|
|
312
|
+
cost: z2.number().optional(),
|
|
313
|
+
result: z2.string().optional(),
|
|
314
|
+
image_url: z2.string().optional()
|
|
292
315
|
}).optional(),
|
|
293
|
-
error:
|
|
316
|
+
error: z2.string().optional()
|
|
294
317
|
// Error message if FAILED
|
|
295
318
|
});
|
|
296
|
-
var runpodImageErrorSchema = z.object({
|
|
297
|
-
error: z.string(),
|
|
298
|
-
message: z.string().optional()
|
|
299
|
-
});
|
|
300
319
|
|
|
301
320
|
// src/runpod-provider.ts
|
|
302
321
|
var MODEL_ID_TO_ENDPOINT_URL = {
|
|
303
|
-
"
|
|
304
|
-
"
|
|
322
|
+
"qwen/qwen3-32b-awq": "https://api.runpod.ai/v2/qwen3-32b-awq/openai/v1",
|
|
323
|
+
"ibm-granite/granite-4.0-h-small": "https://api.runpod.ai/v2/granite-4-0-h-small/openai/v1"
|
|
305
324
|
};
|
|
306
325
|
var IMAGE_MODEL_ID_TO_ENDPOINT_URL = {
|
|
307
326
|
"qwen/qwen-image": "https://api.runpod.ai/v2/qwen-image-t2i",
|
|
@@ -312,12 +331,17 @@ var IMAGE_MODEL_ID_TO_ENDPOINT_URL = {
|
|
|
312
331
|
"bytedance/seedream-4.0-edit": "https://api.runpod.ai/v2/seedream-v4-edit",
|
|
313
332
|
"black-forest-labs/flux-1-kontext-dev": "https://api.runpod.ai/v2/black-forest-labs-flux-1-kontext-dev",
|
|
314
333
|
"black-forest-labs/flux-1-schnell": "https://api.runpod.ai/v2/black-forest-labs-flux-1-schnell",
|
|
315
|
-
"black-forest-labs/flux-1-dev": "https://api.runpod.ai/v2/black-forest-labs-flux-1-dev"
|
|
334
|
+
"black-forest-labs/flux-1-dev": "https://api.runpod.ai/v2/black-forest-labs-flux-1-dev",
|
|
335
|
+
// Nano Banana (edit only)
|
|
336
|
+
"nano-banana-edit": "https://api.runpod.ai/v2/nano-banana-edit"
|
|
316
337
|
};
|
|
317
338
|
var MODEL_ID_TO_OPENAI_NAME = {
|
|
318
|
-
"deep-cogito/deep-cogito-v2-llama-70b": "deepcogito/cogito-v2-preview-llama-70B",
|
|
319
339
|
"qwen/qwen3-32b-awq": "Qwen/Qwen3-32B-AWQ"
|
|
320
340
|
};
|
|
341
|
+
function deriveEndpointURL(modelId) {
|
|
342
|
+
const normalized = modelId.replace(/\//g, "-");
|
|
343
|
+
return `https://api.runpod.ai/v2/${normalized}/openai/v1`;
|
|
344
|
+
}
|
|
321
345
|
function createRunpod(options = {}) {
|
|
322
346
|
const getHeaders = () => ({
|
|
323
347
|
Authorization: `Bearer ${loadApiKey({
|
|
@@ -346,14 +370,7 @@ function createRunpod(options = {}) {
|
|
|
346
370
|
if (options.baseURL) {
|
|
347
371
|
baseURL = options.baseURL;
|
|
348
372
|
} else {
|
|
349
|
-
baseURL = MODEL_ID_TO_ENDPOINT_URL[modelId];
|
|
350
|
-
if (!baseURL) {
|
|
351
|
-
throw new Error(
|
|
352
|
-
`Unsupported Runpod model: ${modelId}. Supported models: ${Object.keys(
|
|
353
|
-
MODEL_ID_TO_ENDPOINT_URL
|
|
354
|
-
).join(", ")}. Or provide a custom baseURL.`
|
|
355
|
-
);
|
|
356
|
-
}
|
|
373
|
+
baseURL = MODEL_ID_TO_ENDPOINT_URL[modelId] || deriveEndpointURL(modelId);
|
|
357
374
|
}
|
|
358
375
|
return {
|
|
359
376
|
provider: `runpod.${modelType}`,
|
|
@@ -381,14 +398,7 @@ function createRunpod(options = {}) {
|
|
|
381
398
|
if (options.baseURL) {
|
|
382
399
|
baseURL = options.baseURL;
|
|
383
400
|
} else {
|
|
384
|
-
baseURL = IMAGE_MODEL_ID_TO_ENDPOINT_URL[modelId];
|
|
385
|
-
if (!baseURL) {
|
|
386
|
-
throw new Error(
|
|
387
|
-
`Unsupported Runpod image model: ${modelId}. Supported models: ${Object.keys(
|
|
388
|
-
IMAGE_MODEL_ID_TO_ENDPOINT_URL
|
|
389
|
-
).join(", ")}. Or provide a custom baseURL.`
|
|
390
|
-
);
|
|
391
|
-
}
|
|
401
|
+
baseURL = IMAGE_MODEL_ID_TO_ENDPOINT_URL[modelId] || deriveEndpointURL(modelId);
|
|
392
402
|
}
|
|
393
403
|
return new RunpodImageModel(modelId, {
|
|
394
404
|
provider: "runpod.image",
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/runpod-provider.ts","../src/runpod-image-model.ts"],"sourcesContent":["import { LanguageModelV2, ImageModelV2 } from '@ai-sdk/provider';\nimport {\n OpenAICompatibleChatLanguageModel,\n OpenAICompatibleCompletionLanguageModel,\n} from '@ai-sdk/openai-compatible';\nimport {\n FetchFunction,\n loadApiKey,\n withoutTrailingSlash,\n} from '@ai-sdk/provider-utils';\nimport { RunpodChatModelId } from './runpod-chat-options';\nimport { RunpodCompletionModelId } from './runpod-completion-options';\nimport { RunpodImageModelId } from './runpod-image-options';\nimport { RunpodImageModel } from './runpod-image-model';\n\nexport interface RunpodProviderSettings {\n /**\nRunpod API key.\n*/\n apiKey?: string;\n /**\nCustom base URL for Runpod API. Use this to point to custom endpoints or different Runpod deployments.\nExample: 'https://api.runpod.ai/v2/your-endpoint-id/openai/v1'\n*/\n baseURL?: string;\n /**\nCustom headers to include in the requests.\n*/\n headers?: Record<string, string>;\n /**\nCustom fetch implementation. You can use it as a middleware to intercept requests,\nor to provide a custom fetch implementation for e.g. testing.\n*/\n fetch?: FetchFunction;\n}\n\nexport interface RunpodProvider {\n /**\nCreates a model for text generation.\n*/\n (modelId: RunpodChatModelId): LanguageModelV2;\n\n /**\nCreates a chat model for text generation.\n*/\n chatModel(modelId: RunpodChatModelId): LanguageModelV2;\n\n /**\nCreates a chat model for text generation.\n*/\n languageModel(modelId: RunpodChatModelId): LanguageModelV2;\n\n /**\nCreates a completion model for text generation.\n*/\n completionModel(modelId: RunpodCompletionModelId): LanguageModelV2;\n\n /**\nCreates an image model for image generation.\n*/\n imageModel(modelId: RunpodImageModelId): ImageModelV2;\n}\n\n// Mapping of Runpod model IDs to their endpoint URLs\nconst MODEL_ID_TO_ENDPOINT_URL: Record<string, string> = {\n 'deep-cogito/deep-cogito-v2-llama-70b':\n 'https://api.runpod.ai/v2/deep-cogito-v2-llama-70b/openai/v1',\n 'qwen/qwen3-32b-awq': 'https://api.runpod.ai/v2/qwen3-32b-awq/openai/v1',\n};\n\n// Mapping of Runpod image model IDs to their endpoint URLs\nconst IMAGE_MODEL_ID_TO_ENDPOINT_URL: Record<string, string> = {\n 'qwen/qwen-image': 'https://api.runpod.ai/v2/qwen-image-t2i',\n 'qwen/qwen-image-edit': 'https://api.runpod.ai/v2/qwen-image-edit',\n 'bytedance/seedream-3.0': 'https://api.runpod.ai/v2/seedream-3-0-t2i',\n // Seadream v4 (t2i and edit)\n 'bytedance/seedream-4.0': 'https://api.runpod.ai/v2/seedream-v4-t2i',\n 'bytedance/seedream-4.0-edit': 'https://api.runpod.ai/v2/seedream-v4-edit',\n 'black-forest-labs/flux-1-kontext-dev':\n 'https://api.runpod.ai/v2/black-forest-labs-flux-1-kontext-dev',\n 'black-forest-labs/flux-1-schnell':\n 'https://api.runpod.ai/v2/black-forest-labs-flux-1-schnell',\n 'black-forest-labs/flux-1-dev':\n 'https://api.runpod.ai/v2/black-forest-labs-flux-1-dev',\n};\n\n// Mapping of Runpod model IDs to their OpenAI model names\nconst MODEL_ID_TO_OPENAI_NAME: Record<string, string> = {\n 'deep-cogito/deep-cogito-v2-llama-70b':\n 'deepcogito/cogito-v2-preview-llama-70B',\n 'qwen/qwen3-32b-awq': 'Qwen/Qwen3-32B-AWQ',\n};\n\nexport function createRunpod(\n options: RunpodProviderSettings = {}\n): RunpodProvider {\n const getHeaders = () => ({\n Authorization: `Bearer ${loadApiKey({\n apiKey: options.apiKey,\n environmentVariableName: 'RUNPOD_API_KEY',\n description: 'Runpod',\n })}`,\n ...options.headers,\n });\n\n const runpodFetch: FetchFunction = async (url, requestInit) => {\n if (requestInit?.body) {\n try {\n const body = JSON.parse(requestInit.body as string);\n if (body.stream === true && !body.stream_options) {\n body.stream_options = { include_usage: true };\n requestInit.body = JSON.stringify(body);\n }\n } catch {}\n }\n const fetchFn = options.fetch || fetch;\n return fetchFn(url, requestInit);\n };\n\n interface CommonModelConfig {\n provider: string;\n url: ({ path }: { path: string }) => string;\n headers: () => Record<string, string>;\n fetch?: FetchFunction;\n }\n\n const getModelConfig = (\n modelId: string,\n modelType: string\n ): CommonModelConfig => {\n let baseURL: string;\n\n if (options.baseURL) {\n baseURL = options.baseURL;\n } else {\n baseURL = MODEL_ID_TO_ENDPOINT_URL[modelId];\n if (!baseURL) {\n throw new Error(\n `Unsupported Runpod model: ${modelId}. Supported models: ${Object.keys(\n MODEL_ID_TO_ENDPOINT_URL\n ).join(', ')}. Or provide a custom baseURL.`\n );\n }\n }\n\n return {\n provider: `runpod.${modelType}`,\n url: ({ path }) => `${withoutTrailingSlash(baseURL)}${path}`,\n headers: getHeaders,\n fetch: runpodFetch,\n };\n };\n\n const createChatModel = (modelId: RunpodChatModelId) => {\n const openaiModelName = MODEL_ID_TO_OPENAI_NAME[modelId] || modelId;\n return new OpenAICompatibleChatLanguageModel(openaiModelName, {\n ...getModelConfig(modelId, 'chat'),\n includeUsage: true,\n });\n };\n\n const createCompletionModel = (modelId: RunpodCompletionModelId) => {\n const openaiModelName = MODEL_ID_TO_OPENAI_NAME[modelId] || modelId;\n return new OpenAICompatibleCompletionLanguageModel(openaiModelName, {\n ...getModelConfig(modelId, 'completion'),\n includeUsage: true,\n });\n };\n\n const createImageModel = (modelId: RunpodImageModelId) => {\n let baseURL: string;\n\n if (options.baseURL) {\n baseURL = options.baseURL;\n } else {\n baseURL = IMAGE_MODEL_ID_TO_ENDPOINT_URL[modelId];\n if (!baseURL) {\n throw new Error(\n `Unsupported Runpod image model: ${modelId}. Supported models: ${Object.keys(\n IMAGE_MODEL_ID_TO_ENDPOINT_URL\n ).join(', ')}. Or provide a custom baseURL.`\n );\n }\n }\n\n return new RunpodImageModel(modelId, {\n provider: 'runpod.image',\n baseURL,\n headers: getHeaders,\n fetch: options.fetch,\n });\n };\n\n const provider = (modelId: RunpodChatModelId) => createChatModel(modelId);\n\n provider.completionModel = createCompletionModel;\n provider.languageModel = createChatModel;\n provider.chatModel = createChatModel;\n provider.imageModel = createImageModel;\n\n return provider;\n}\n\nexport const runpod = createRunpod();\n","import { ImageModelV2, ImageModelV2CallWarning } from '@ai-sdk/provider';\r\nimport {\r\n combineHeaders,\r\n createJsonResponseHandler,\r\n createJsonErrorResponseHandler,\r\n createBinaryResponseHandler,\r\n FetchFunction,\r\n postJsonToApi,\r\n getFromApi,\r\n} from '@ai-sdk/provider-utils';\r\nimport { InvalidArgumentError } from '@ai-sdk/provider';\r\nimport { z } from 'zod';\r\nimport { RunpodImageModelId } from './runpod-image-options';\r\n\r\ninterface RunpodImageModelConfig {\r\n provider: string;\r\n baseURL: string;\r\n headers: () => Record<string, string>;\r\n fetch?: FetchFunction;\r\n _internal?: {\r\n currentDate?: () => Date;\r\n };\r\n}\r\n\r\n// Runpod supported aspect ratios (only validated working sizes)\r\nconst SUPPORTED_ASPECT_RATIOS: Record<string, string> = {\r\n '1:1': '1328*1328', // ✅ Native support\r\n '4:3': '1472*1140', // ✅ Native support\r\n '3:4': '1140*1472', // ✅ Native support\r\n};\r\n\r\n// Runpod supported sizes (validated working sizes)\r\nconst SUPPORTED_SIZES = new Set([\r\n // Native aspect ratio sizes\r\n '1328*1328', // 1:1\r\n '1472*1140', // 4:3\r\n '1140*1472', // 3:4\r\n // Additional validated sizes\r\n '512*512',\r\n '768*768',\r\n '1024*1024',\r\n '1536*1536',\r\n '2048*2048',\r\n '4096*4096',\r\n '512*768',\r\n '768*512',\r\n '1024*768',\r\n '768*1024',\r\n]);\r\n\r\nexport class RunpodImageModel implements ImageModelV2 {\r\n readonly specificationVersion = 'v2';\r\n readonly maxImagesPerCall = 1;\r\n\r\n get provider(): string {\r\n return this.config.provider;\r\n }\r\n\r\n constructor(\r\n readonly modelId: RunpodImageModelId,\r\n private config: RunpodImageModelConfig\r\n ) {}\r\n\r\n async doGenerate({\r\n prompt,\r\n n = 1,\r\n size,\r\n aspectRatio,\r\n seed,\r\n providerOptions,\r\n headers,\r\n abortSignal,\r\n }: Parameters<ImageModelV2['doGenerate']>[0]): Promise<\r\n Awaited<ReturnType<ImageModelV2['doGenerate']>>\r\n > {\r\n const warnings: Array<ImageModelV2CallWarning> = [];\r\n\r\n // Determine the size to use\r\n let runpodSize: string;\r\n\r\n if (size) {\r\n // Convert AI SDK format \"1328x1328\" to Runpod format \"1328*1328\"\r\n const runpodSizeCandidate = size.replace('x', '*');\r\n\r\n // Validate size is supported\r\n if (!SUPPORTED_SIZES.has(runpodSizeCandidate)) {\r\n throw new InvalidArgumentError({\r\n argument: 'size',\r\n message: `Size ${size} is not supported by Runpod. Supported sizes: ${Array.from(\r\n SUPPORTED_SIZES\r\n )\r\n .map((s) => s.replace('*', 'x'))\r\n .join(', ')}`,\r\n });\r\n }\r\n\r\n runpodSize = runpodSizeCandidate;\r\n } else if (aspectRatio) {\r\n // Validate aspect ratio is supported\r\n if (!SUPPORTED_ASPECT_RATIOS[aspectRatio]) {\r\n throw new InvalidArgumentError({\r\n argument: 'aspectRatio',\r\n message: `Aspect ratio ${aspectRatio} is not supported by Runpod. Supported aspect ratios: ${Object.keys(SUPPORTED_ASPECT_RATIOS).join(', ')}`,\r\n });\r\n }\r\n\r\n // Use supported aspect ratio mapping\r\n runpodSize = SUPPORTED_ASPECT_RATIOS[aspectRatio];\r\n } else {\r\n // Default to square format\r\n runpodSize = '1328*1328';\r\n }\r\n\r\n // Handle multiple images warning\r\n if (n > 1) {\r\n warnings.push({\r\n type: 'unsupported-setting',\r\n setting: 'n',\r\n details:\r\n 'Runpod image models only support generating 1 image at a time. Using n=1.',\r\n });\r\n }\r\n\r\n const currentDate = this.config._internal?.currentDate?.() ?? new Date();\r\n\r\n // Runpod uses a different request format - /runsync endpoint with input wrapper\r\n const inputPayload = this.buildInputPayload(\r\n prompt,\r\n runpodSize,\r\n seed,\r\n providerOptions.runpod\r\n );\r\n\r\n const { value: response, responseHeaders } = await postJsonToApi({\r\n url: `${this.config.baseURL}/runsync`,\r\n headers: combineHeaders(this.config.headers(), headers),\r\n body: {\r\n input: inputPayload,\r\n },\r\n failedResponseHandler: createJsonErrorResponseHandler({\r\n errorSchema: runpodImageErrorSchema as any,\r\n errorToMessage: (data: any) => data.error ?? 'Unknown error',\r\n }),\r\n successfulResponseHandler: createJsonResponseHandler(\r\n runpodImageResponseSchema as any\r\n ),\r\n abortSignal,\r\n fetch: this.config.fetch,\r\n });\r\n\r\n // Handle both sync and async responses from Runpod\r\n const typedResponse = response as any;\r\n if (\r\n typedResponse.status === 'COMPLETED' &&\r\n (typedResponse.output?.result || typedResponse.output?.image_url)\r\n ) {\r\n // Sync response - image is ready\r\n // Different models use different response formats: result vs image_url\r\n const imageUrl =\r\n typedResponse.output.result || typedResponse.output.image_url;\r\n const imageData = await this.downloadImage(imageUrl, abortSignal);\r\n\r\n return {\r\n images: [imageData],\r\n warnings,\r\n response: {\r\n timestamp: currentDate,\r\n modelId: this.modelId,\r\n headers: responseHeaders,\r\n },\r\n providerMetadata: {\r\n runpod: {\r\n images: [\r\n {\r\n url: imageUrl,\r\n cost: typedResponse.output?.cost,\r\n },\r\n ],\r\n },\r\n },\r\n };\r\n } else if (\r\n typedResponse.status === 'IN_QUEUE' ||\r\n typedResponse.status === 'IN_PROGRESS'\r\n ) {\r\n // Async response - need to poll for completion\r\n const pollOptions = {\r\n maxAttempts: providerOptions.runpod?.maxPollAttempts as number,\r\n pollIntervalMillis: providerOptions.runpod\r\n ?.pollIntervalMillis as number,\r\n };\r\n const imageUrl = await this.pollForCompletion(\r\n typedResponse.id,\r\n abortSignal,\r\n pollOptions\r\n );\r\n const imageData = await this.downloadImage(imageUrl, abortSignal);\r\n\r\n return {\r\n images: [imageData],\r\n warnings,\r\n response: {\r\n timestamp: currentDate,\r\n modelId: this.modelId,\r\n headers: responseHeaders,\r\n },\r\n providerMetadata: {\r\n runpod: {\r\n images: [\r\n {\r\n url: imageUrl,\r\n jobId: typedResponse.id,\r\n },\r\n ],\r\n },\r\n },\r\n };\r\n } else {\r\n throw new Error(`Unexpected response status: ${typedResponse.status}`);\r\n }\r\n }\r\n\r\n private async downloadImage(\r\n imageUrl: string,\r\n abortSignal?: AbortSignal\r\n ): Promise<Uint8Array> {\r\n const { value: imageData } = await getFromApi({\r\n url: imageUrl,\r\n successfulResponseHandler: createBinaryResponseHandler(),\r\n failedResponseHandler: createJsonErrorResponseHandler({\r\n errorSchema: runpodImageErrorSchema as any,\r\n errorToMessage: (data: any) => data.error ?? 'Failed to download image',\r\n }),\r\n abortSignal,\r\n fetch: this.config.fetch,\r\n });\r\n return imageData;\r\n }\r\n\r\n private async pollForCompletion(\r\n jobId: string,\r\n abortSignal?: AbortSignal,\r\n pollOptions?: { maxAttempts?: number; pollIntervalMillis?: number }\r\n ): Promise<string> {\r\n const maxAttempts = pollOptions?.maxAttempts ?? 60; // 5 minutes with 5-second intervals\r\n const pollInterval = pollOptions?.pollIntervalMillis ?? 5000; // 5 seconds\r\n\r\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\r\n if (abortSignal?.aborted) {\r\n throw new Error('Image generation was aborted');\r\n }\r\n\r\n const { value: statusResponse } = await getFromApi({\r\n url: `${this.config.baseURL}/status/${jobId}`,\r\n headers: this.config.headers(),\r\n successfulResponseHandler: createJsonResponseHandler(\r\n runpodImageStatusSchema as any\r\n ),\r\n failedResponseHandler: createJsonErrorResponseHandler({\r\n errorSchema: runpodImageErrorSchema as any,\r\n errorToMessage: (data: any) =>\r\n data.error ?? 'Failed to check job status',\r\n }),\r\n abortSignal,\r\n fetch: this.config.fetch,\r\n });\r\n\r\n const typedStatusResponse = statusResponse as any;\r\n if (\r\n typedStatusResponse.status === 'COMPLETED' &&\r\n (typedStatusResponse.output?.result ||\r\n typedStatusResponse.output?.image_url)\r\n ) {\r\n return (\r\n typedStatusResponse.output.result ||\r\n typedStatusResponse.output.image_url\r\n );\r\n }\r\n\r\n if (typedStatusResponse.status === 'FAILED') {\r\n throw new Error(\r\n `Image generation failed: ${typedStatusResponse.error || 'Unknown error'}`\r\n );\r\n }\r\n\r\n // Wait before next poll\r\n await new Promise((resolve) => setTimeout(resolve, pollInterval));\r\n }\r\n\r\n throw new Error(\r\n `Image generation timed out after ${maxAttempts} attempts (${(maxAttempts * pollInterval) / 1000}s)`\r\n );\r\n }\r\n\r\n private buildInputPayload(\r\n prompt: string,\r\n runpodSize: string,\r\n seed?: number,\r\n runpodOptions?: Record<string, unknown>\r\n ): Record<string, unknown> {\r\n // Check if this is a Flux model that uses different parameters\r\n const isFluxModel =\r\n this.modelId.includes('flux') ||\r\n this.modelId.includes('black-forest-labs');\r\n\r\n if (isFluxModel) {\r\n // Check if this is Flux Kontext (uses different parameters)\r\n const isKontext = this.modelId.includes('kontext');\r\n\r\n if (isKontext) {\r\n // Flux Kontext uses size format and has image input\r\n return {\r\n prompt,\r\n negative_prompt: runpodOptions?.negative_prompt ?? '',\r\n seed: seed ?? -1,\r\n num_inference_steps: 28,\r\n guidance: 2,\r\n size: runpodSize,\r\n output_format: 'png',\r\n enable_safety_checker: runpodOptions?.enable_safety_checker ?? true,\r\n ...runpodOptions, // This will include the 'image' parameter if provided\r\n };\r\n } else {\r\n // Regular Flux models use width/height\r\n const [width, height] = runpodSize.split('*').map(Number);\r\n\r\n return {\r\n prompt,\r\n negative_prompt: runpodOptions?.negative_prompt ?? '',\r\n seed: seed ?? -1,\r\n num_inference_steps: this.modelId.includes('schnell') ? 4 : 28,\r\n guidance: this.modelId.includes('schnell') ? 7 : 2,\r\n width,\r\n height,\r\n image_format: 'png',\r\n ...runpodOptions,\r\n };\r\n }\r\n }\r\n\r\n // Default format for Qwen and other models\r\n return {\r\n prompt,\r\n negative_prompt: runpodOptions?.negative_prompt ?? '',\r\n size: runpodSize,\r\n seed: seed ?? -1,\r\n enable_safety_checker: runpodOptions?.enable_safety_checker ?? true,\r\n ...runpodOptions,\r\n };\r\n }\r\n}\r\n\r\n// Runpod image API response schema (handles both sync and async responses)\r\nconst runpodImageResponseSchema = z.object({\r\n id: z.string(),\r\n status: z.enum(['COMPLETED', 'IN_QUEUE', 'IN_PROGRESS', 'FAILED']),\r\n delayTime: z.number().optional(),\r\n executionTime: z.number().optional(),\r\n output: z\r\n .object({\r\n cost: z.number().optional(),\r\n result: z.string().optional(), // URL to the generated image (Qwen format)\r\n image_url: z.string().optional(), // URL to the generated image (Flux format)\r\n })\r\n .optional(), // Optional for IN_QUEUE/IN_PROGRESS responses\r\n});\r\n\r\n// Schema for polling status endpoint\r\nconst runpodImageStatusSchema = z.object({\r\n id: z.string(),\r\n status: z.enum(['COMPLETED', 'IN_QUEUE', 'IN_PROGRESS', 'FAILED']),\r\n output: z\r\n .object({\r\n cost: z.number().optional(),\r\n result: z.string().optional(),\r\n image_url: z.string().optional(),\r\n })\r\n .optional(),\r\n error: z.string().optional(), // Error message if FAILED\r\n});\r\n\r\n// Runpod image API error schema\r\nconst runpodImageErrorSchema = z.object({\r\n error: z.string(),\r\n message: z.string().optional(),\r\n});\r\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/runpod-provider.ts","../src/runpod-image-model.ts","../src/runpod-error.ts"],"sourcesContent":["import { LanguageModelV2, ImageModelV2 } from '@ai-sdk/provider';\nimport {\n OpenAICompatibleChatLanguageModel,\n OpenAICompatibleCompletionLanguageModel,\n} from '@ai-sdk/openai-compatible';\nimport {\n FetchFunction,\n loadApiKey,\n withoutTrailingSlash,\n} from '@ai-sdk/provider-utils';\nimport { RunpodImageModel } from './runpod-image-model';\n\nexport interface RunpodProviderSettings {\n /**\nRunpod API key.\n*/\n apiKey?: string;\n /**\nCustom base URL for Runpod API. Use this to point to custom endpoints or different Runpod deployments.\nExample: 'https://api.runpod.ai/v2/your-endpoint-id/openai/v1'\n*/\n baseURL?: string;\n /**\nCustom headers to include in the requests.\n*/\n headers?: Record<string, string>;\n /**\nCustom fetch implementation. You can use it as a middleware to intercept requests,\nor to provide a custom fetch implementation for e.g. testing.\n*/\n fetch?: FetchFunction;\n}\n\nexport interface RunpodProvider {\n /**\nCreates a model for text generation.\n*/\n (modelId: string): LanguageModelV2;\n\n /**\nCreates a chat model for text generation.\n*/\n chatModel(modelId: string): LanguageModelV2;\n\n /**\nCreates a chat model for text generation.\n*/\n languageModel(modelId: string): LanguageModelV2;\n\n /**\nCreates a completion model for text generation.\n*/\n completionModel(modelId: string): LanguageModelV2;\n\n /**\nCreates an image model for image generation.\n*/\n imageModel(modelId: string): ImageModelV2;\n}\n\n// Mapping of Runpod model IDs to their endpoint URLs\nconst MODEL_ID_TO_ENDPOINT_URL: Record<string, string> = {\n 'qwen/qwen3-32b-awq': 'https://api.runpod.ai/v2/qwen3-32b-awq/openai/v1',\n 'ibm-granite/granite-4.0-h-small': 'https://api.runpod.ai/v2/granite-4-0-h-small/openai/v1',\n};\n\n// Mapping of Runpod image model IDs to their endpoint URLs\nconst IMAGE_MODEL_ID_TO_ENDPOINT_URL: Record<string, string> = {\n 'qwen/qwen-image': 'https://api.runpod.ai/v2/qwen-image-t2i',\n 'qwen/qwen-image-edit': 'https://api.runpod.ai/v2/qwen-image-edit',\n 'bytedance/seedream-3.0': 'https://api.runpod.ai/v2/seedream-3-0-t2i',\n // Seadream v4 (t2i and edit)\n 'bytedance/seedream-4.0': 'https://api.runpod.ai/v2/seedream-v4-t2i',\n 'bytedance/seedream-4.0-edit': 'https://api.runpod.ai/v2/seedream-v4-edit',\n 'black-forest-labs/flux-1-kontext-dev':\n 'https://api.runpod.ai/v2/black-forest-labs-flux-1-kontext-dev',\n 'black-forest-labs/flux-1-schnell':\n 'https://api.runpod.ai/v2/black-forest-labs-flux-1-schnell',\n 'black-forest-labs/flux-1-dev':\n 'https://api.runpod.ai/v2/black-forest-labs-flux-1-dev',\n // Nano Banana (edit only)\n 'nano-banana-edit': 'https://api.runpod.ai/v2/nano-banana-edit',\n};\n\n// Mapping of Runpod model IDs to their OpenAI model names\nconst MODEL_ID_TO_OPENAI_NAME: Record<string, string> = {\n 'qwen/qwen3-32b-awq': 'Qwen/Qwen3-32B-AWQ',\n};\n\n/**\n * Derives the endpoint URL for a model by replacing slashes with hyphens.\n * Example: 'ibm-granite/granite-4.0-h-small' -> 'https://api.runpod.ai/v2/ibm-granite-granite-4.0-h-small/openai/v1'\n */\nfunction deriveEndpointURL(modelId: string): string {\n const normalized = modelId.replace(/\\//g, '-');\n return `https://api.runpod.ai/v2/${normalized}/openai/v1`;\n}\n\nexport function createRunpod(\n options: RunpodProviderSettings = {}\n): RunpodProvider {\n const getHeaders = () => ({\n Authorization: `Bearer ${loadApiKey({\n apiKey: options.apiKey,\n environmentVariableName: 'RUNPOD_API_KEY',\n description: 'Runpod',\n })}`,\n ...options.headers,\n });\n\n const runpodFetch: FetchFunction = async (url, requestInit) => {\n if (requestInit?.body) {\n try {\n const body = JSON.parse(requestInit.body as string);\n if (body.stream === true && !body.stream_options) {\n body.stream_options = { include_usage: true };\n requestInit.body = JSON.stringify(body);\n }\n } catch {}\n }\n const fetchFn = options.fetch || fetch;\n return fetchFn(url, requestInit);\n };\n\n interface CommonModelConfig {\n provider: string;\n url: ({ path }: { path: string }) => string;\n headers: () => Record<string, string>;\n fetch?: FetchFunction;\n }\n\n const getModelConfig = (\n modelId: string,\n modelType: string\n ): CommonModelConfig => {\n let baseURL: string;\n\n if (options.baseURL) {\n baseURL = options.baseURL;\n } else {\n // Use hardcoded mapping if available, otherwise derive endpoint\n baseURL = MODEL_ID_TO_ENDPOINT_URL[modelId] || deriveEndpointURL(modelId);\n }\n\n return {\n provider: `runpod.${modelType}`,\n url: ({ path }) => `${withoutTrailingSlash(baseURL)}${path}`,\n headers: getHeaders,\n fetch: runpodFetch,\n };\n };\n\n const createChatModel = (modelId: string) => {\n const openaiModelName = MODEL_ID_TO_OPENAI_NAME[modelId] || modelId;\n return new OpenAICompatibleChatLanguageModel(openaiModelName, {\n ...getModelConfig(modelId, 'chat'),\n includeUsage: true,\n });\n };\n\n const createCompletionModel = (modelId: string) => {\n const openaiModelName = MODEL_ID_TO_OPENAI_NAME[modelId] || modelId;\n return new OpenAICompatibleCompletionLanguageModel(openaiModelName, {\n ...getModelConfig(modelId, 'completion'),\n includeUsage: true,\n });\n };\n\n const createImageModel = (modelId: string) => {\n let baseURL: string;\n\n if (options.baseURL) {\n baseURL = options.baseURL;\n } else {\n // Use hardcoded mapping if available, otherwise derive endpoint\n baseURL =\n IMAGE_MODEL_ID_TO_ENDPOINT_URL[modelId] || deriveEndpointURL(modelId);\n }\n\n return new RunpodImageModel(modelId, {\n provider: 'runpod.image',\n baseURL,\n headers: getHeaders,\n fetch: options.fetch,\n });\n };\n\n const provider = (modelId: string) => createChatModel(modelId);\n\n provider.completionModel = createCompletionModel;\n provider.languageModel = createChatModel;\n provider.chatModel = createChatModel;\n provider.imageModel = createImageModel;\n\n return provider;\n}\n\nexport const runpod = createRunpod();\n","import { ImageModelV2, ImageModelV2CallWarning } from '@ai-sdk/provider';\nimport {\n combineHeaders,\n createJsonResponseHandler,\n createBinaryResponseHandler,\n FetchFunction,\n postJsonToApi,\n getFromApi,\n} from '@ai-sdk/provider-utils';\nimport { InvalidArgumentError } from '@ai-sdk/provider';\nimport { z } from 'zod';\nimport { runpodImageFailedResponseHandler } from './runpod-error';\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\ninterface RunpodImageModelConfig {\n provider: string;\n baseURL: string;\n headers: () => Record<string, string>;\n fetch?: FetchFunction;\n _internal?: {\n currentDate?: () => Date;\n };\n}\n\n// Runpod supported aspect ratios (only validated working sizes)\nconst SUPPORTED_ASPECT_RATIOS: Record<string, string> = {\n '1:1': '1328*1328', // ✅ Native support\n '4:3': '1472*1140', // ✅ Native support\n '3:4': '1140*1472', // ✅ Native support\n};\n\n// Runpod supported sizes (validated working sizes)\nconst SUPPORTED_SIZES = new Set([\n // Native aspect ratio sizes\n '1328*1328', // 1:1\n '1472*1140', // 4:3\n '1140*1472', // 3:4\n // Additional validated sizes\n '512*512',\n '768*768',\n '1024*1024',\n '1536*1536',\n '2048*2048',\n '4096*4096',\n '512*768',\n '768*512',\n '1024*768',\n '768*1024',\n]);\n\nexport class RunpodImageModel implements ImageModelV2 {\n readonly specificationVersion = 'v2';\n readonly maxImagesPerCall = 1;\n\n get provider(): string {\n return this.config.provider;\n }\n\n constructor(\n readonly modelId: string,\n private config: RunpodImageModelConfig\n ) {}\n\n async doGenerate({\n prompt,\n n = 1,\n size,\n aspectRatio,\n seed,\n providerOptions,\n headers,\n abortSignal,\n }: Parameters<ImageModelV2['doGenerate']>[0]): Promise<\n Awaited<ReturnType<ImageModelV2['doGenerate']>>\n > {\n const warnings: Array<ImageModelV2CallWarning> = [];\n\n // Determine the size to use\n let runpodSize: string;\n\n if (size) {\n // Convert AI SDK format \"1328x1328\" to Runpod format \"1328*1328\"\n const runpodSizeCandidate = size.replace('x', '*');\n\n // Validate size is supported\n if (!SUPPORTED_SIZES.has(runpodSizeCandidate)) {\n throw new InvalidArgumentError({\n argument: 'size',\n message: `Size ${size} is not supported by Runpod. Supported sizes: ${Array.from(\n SUPPORTED_SIZES\n )\n .map((s) => s.replace('*', 'x'))\n .join(', ')}`,\n });\n }\n\n runpodSize = runpodSizeCandidate;\n } else if (aspectRatio) {\n // Validate aspect ratio is supported\n if (!SUPPORTED_ASPECT_RATIOS[aspectRatio]) {\n throw new InvalidArgumentError({\n argument: 'aspectRatio',\n message: `Aspect ratio ${aspectRatio} is not supported by Runpod. Supported aspect ratios: ${Object.keys(SUPPORTED_ASPECT_RATIOS).join(', ')}`,\n });\n }\n\n // Use supported aspect ratio mapping\n runpodSize = SUPPORTED_ASPECT_RATIOS[aspectRatio];\n } else {\n // Default to square format\n runpodSize = '1328*1328';\n }\n\n // Handle multiple images warning\n if (n > 1) {\n warnings.push({\n type: 'unsupported-setting',\n setting: 'n',\n details:\n 'Runpod image models only support generating 1 image at a time. Using n=1.',\n });\n }\n\n const currentDate = this.config._internal?.currentDate?.() ?? new Date();\n\n // Runpod uses a different request format - /runsync endpoint with input wrapper\n const inputPayload = this.buildInputPayload(\n prompt,\n runpodSize,\n seed,\n providerOptions.runpod\n );\n\n const { value: response, responseHeaders } = await postJsonToApi({\n url: `${this.config.baseURL}/runsync`,\n headers: combineHeaders(this.config.headers(), headers),\n body: {\n input: inputPayload,\n },\n failedResponseHandler: runpodImageFailedResponseHandler,\n successfulResponseHandler: createJsonResponseHandler(\n runpodImageResponseSchema as any\n ),\n abortSignal,\n fetch: this.config.fetch,\n });\n\n // Handle both sync and async responses from Runpod\n const typedResponse = response as any;\n if (\n typedResponse.status === 'COMPLETED' &&\n (typedResponse.output?.result || typedResponse.output?.image_url)\n ) {\n // Sync response - image is ready\n // Different models use different response formats: result vs image_url\n const imageUrl =\n typedResponse.output.result || typedResponse.output.image_url;\n const imageData = await this.downloadImage(imageUrl, abortSignal);\n\n return {\n images: [imageData],\n warnings,\n response: {\n timestamp: currentDate,\n modelId: this.modelId,\n headers: responseHeaders,\n },\n providerMetadata: {\n runpod: {\n images: [\n {\n url: imageUrl,\n cost: typedResponse.output?.cost,\n },\n ],\n },\n },\n };\n } else if (\n typedResponse.status === 'IN_QUEUE' ||\n typedResponse.status === 'IN_PROGRESS'\n ) {\n // Async response - need to poll for completion\n const pollOptions = {\n maxAttempts: providerOptions.runpod?.maxPollAttempts as number,\n pollIntervalMillis: providerOptions.runpod\n ?.pollIntervalMillis as number,\n };\n const imageUrl = await this.pollForCompletion(\n typedResponse.id,\n abortSignal,\n pollOptions\n );\n const imageData = await this.downloadImage(imageUrl, abortSignal);\n\n return {\n images: [imageData],\n warnings,\n response: {\n timestamp: currentDate,\n modelId: this.modelId,\n headers: responseHeaders,\n },\n providerMetadata: {\n runpod: {\n images: [\n {\n url: imageUrl,\n jobId: typedResponse.id,\n },\n ],\n },\n },\n };\n } else {\n throw new Error(`Unexpected response status: ${typedResponse.status}`);\n }\n }\n\n private async downloadImage(\n imageUrl: string,\n abortSignal?: AbortSignal\n ): Promise<Uint8Array> {\n const { value: imageData } = await getFromApi({\n url: imageUrl,\n successfulResponseHandler: createBinaryResponseHandler(),\n failedResponseHandler: runpodImageFailedResponseHandler,\n abortSignal,\n fetch: this.config.fetch,\n });\n return imageData;\n }\n\n private async pollForCompletion(\n jobId: string,\n abortSignal?: AbortSignal,\n pollOptions?: { maxAttempts?: number; pollIntervalMillis?: number }\n ): Promise<string> {\n const maxAttempts = pollOptions?.maxAttempts ?? 60; // 5 minutes with 5-second intervals\n const pollInterval = pollOptions?.pollIntervalMillis ?? 5000; // 5 seconds\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n if (abortSignal?.aborted) {\n throw new Error('Image generation was aborted');\n }\n\n const { value: statusResponse } = await getFromApi({\n url: `${this.config.baseURL}/status/${jobId}`,\n headers: this.config.headers(),\n successfulResponseHandler: createJsonResponseHandler(\n runpodImageStatusSchema as any\n ),\n failedResponseHandler: runpodImageFailedResponseHandler,\n abortSignal,\n fetch: this.config.fetch,\n });\n\n const typedStatusResponse = statusResponse as any;\n if (\n typedStatusResponse.status === 'COMPLETED' &&\n (typedStatusResponse.output?.result ||\n typedStatusResponse.output?.image_url)\n ) {\n return (\n typedStatusResponse.output.result ||\n typedStatusResponse.output.image_url\n );\n }\n\n if (typedStatusResponse.status === 'FAILED') {\n throw new Error(\n `Image generation failed: ${typedStatusResponse.error || 'Unknown error'}`\n );\n }\n\n // Wait before next poll\n await new Promise((resolve) => setTimeout(resolve, pollInterval));\n }\n\n throw new Error(\n `Image generation timed out after ${maxAttempts} attempts (${(maxAttempts * pollInterval) / 1000}s)`\n );\n }\n\n private buildInputPayload(\n prompt: string,\n runpodSize: string,\n seed?: number,\n runpodOptions?: Record<string, unknown>\n ): Record<string, unknown> {\n // Check if this is a Flux model that uses different parameters\n const isFluxModel =\n this.modelId.includes('flux') ||\n this.modelId.includes('black-forest-labs');\n\n if (isFluxModel) {\n // Check if this is Flux Kontext (uses different parameters)\n const isKontext = this.modelId.includes('kontext');\n\n if (isKontext) {\n // Flux Kontext uses size format and has image input\n return {\n prompt,\n negative_prompt: runpodOptions?.negative_prompt ?? '',\n seed: seed ?? -1,\n num_inference_steps: 28,\n guidance: 2,\n size: runpodSize,\n output_format: 'png',\n enable_safety_checker: runpodOptions?.enable_safety_checker ?? true,\n ...runpodOptions, // This will include the 'image' parameter if provided\n };\n } else {\n // Regular Flux models use width/height\n const [width, height] = runpodSize.split('*').map(Number);\n\n return {\n prompt,\n negative_prompt: runpodOptions?.negative_prompt ?? '',\n seed: seed ?? -1,\n num_inference_steps: this.modelId.includes('schnell') ? 4 : 28,\n guidance: this.modelId.includes('schnell') ? 7 : 2,\n width,\n height,\n image_format: 'png',\n ...runpodOptions,\n };\n }\n }\n\n // Default format for Qwen and other models\n return {\n prompt,\n negative_prompt: runpodOptions?.negative_prompt ?? '',\n size: runpodSize,\n seed: seed ?? -1,\n enable_safety_checker: runpodOptions?.enable_safety_checker ?? true,\n ...runpodOptions,\n };\n }\n}\n\n// Runpod image API response schema (handles both sync and async responses)\nconst runpodImageResponseSchema = z.object({\n id: z.string(),\n status: z.enum(['COMPLETED', 'IN_QUEUE', 'IN_PROGRESS', 'FAILED']),\n delayTime: z.number().optional(),\n executionTime: z.number().optional(),\n output: z\n .object({\n cost: z.number().optional(),\n result: z.string().optional(), // URL to the generated image (Qwen format)\n image_url: z.string().optional(), // URL to the generated image (Flux format)\n })\n .optional(), // Optional for IN_QUEUE/IN_PROGRESS responses\n});\n\n// Schema for polling status endpoint\nconst runpodImageStatusSchema = z.object({\n id: z.string(),\n status: z.enum(['COMPLETED', 'IN_QUEUE', 'IN_PROGRESS', 'FAILED']),\n output: z\n .object({\n cost: z.number().optional(),\n result: z.string().optional(),\n image_url: z.string().optional(),\n })\n .optional(),\n error: z.string().optional(), // Error message if FAILED\n});\n","import { z } from 'zod';\r\nimport { createJsonErrorResponseHandler } from '@ai-sdk/provider-utils';\r\n\r\n// Runpod image API error schema (supports both error formats)\r\nexport const runpodImageErrorSchema = z.object({\r\n error: z.string().optional(),\r\n message: z.string().optional(),\r\n});\r\n\r\nexport type RunpodImageErrorData = z.infer<typeof runpodImageErrorSchema>;\r\n\r\nexport const runpodImageFailedResponseHandler = createJsonErrorResponseHandler({\r\n errorSchema: runpodImageErrorSchema as any,\r\n errorToMessage: (data: RunpodImageErrorData) => {\r\n // Prefer message if available (more descriptive)\r\n if (data.message) {\r\n return data.message;\r\n }\r\n \r\n // If error field exists, try to extract nested JSON message\r\n if (data.error) {\r\n // Runpod sometimes returns nested JSON in the error field like:\r\n // \"Error submitting task: 400, {\\\"code\\\":400,\\\"message\\\":\\\"...\\\"}\"\r\n // Try to extract the inner message for cleaner error messages\r\n // Find the last occurrence of { which likely starts the JSON object\r\n const lastBraceIndex = data.error.lastIndexOf('{');\r\n if (lastBraceIndex !== -1) {\r\n try {\r\n const jsonStr = data.error.substring(lastBraceIndex);\r\n const nestedError = JSON.parse(jsonStr);\r\n if (nestedError.message && typeof nestedError.message === 'string') {\r\n return nestedError.message;\r\n }\r\n } catch {\r\n // If parsing fails, fall back to the original error string\r\n }\r\n }\r\n return data.error;\r\n }\r\n \r\n return 'Unknown Runpod error';\r\n },\r\n});\r\n\r\n"],"mappings":"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","names":["z","z"]}
|