@runpod/ai-sdk-provider 0.1.1 → 0.2.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 CHANGED
@@ -1,5 +1,22 @@
1
1
  # @runpod/ai-sdk-provider
2
2
 
3
+ ## 0.2.1
4
+
5
+ ### Patch Changes
6
+
7
+ - eb1b7f8: improved docs
8
+
9
+ ## 0.2.0
10
+
11
+ ### Minor Changes
12
+
13
+ - 1fec4a8: added support for image gen:
14
+ - `qwen/qwen-image`
15
+ - `bytedance/seedream-3.0`
16
+ - `black-forest-labs/flux-1-kontext-dev`
17
+ - `black-forest-labs/flux-1-schnell`
18
+ - `black-forest-labs/flux-1-dev`
19
+
3
20
  ## 0.1.1
4
21
 
5
22
  ### Patch Changes
package/README.md CHANGED
@@ -1,132 +1,275 @@
1
- # Runpod AI SDK Provider
2
-
3
- The **Runpod provider** for the [AI SDK](https://ai-sdk.dev/docs) contains language model support for [Runpod's](https://runpod.io) public endpoints.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- # npm
9
- npm install @runpod/ai-sdk-provider
10
-
11
- # pnpm
12
- pnpm add @runpod/ai-sdk-provider
13
-
14
- # yarn
15
- yarn add @runpod/ai-sdk-provider
16
- ```
17
-
18
- ## Setup
19
-
20
- The Runpod provider requires a Runpod API key. You can obtain one from the [Runpod console](https://console.runpod.io/user/settings) under "API Keys".
21
-
22
- ### Environment Variable
23
-
24
- Set your API key as an environment variable:
25
-
26
- ```bash
27
- export RUNPOD_API_KEY="your-api-key-here"
28
- ```
29
-
30
- ### Provider Instance
31
-
32
- Import the provider:
33
-
34
- ```ts
35
- import { runpod } from '@runpod/ai-sdk-provider';
36
- ```
37
-
38
- ## Supported Models
39
-
40
- | Model ID | Description |
41
- | -------------------------------------- | ------------------------------------------------------------------- |
42
- | `deep-cogito/deep-cogito-v2-llama-70b` | 70B parameter general-purpose LLM with advanced reasoning |
43
- | `qwen/qwen3-32b-awq` | 32B parameter multilingual model with strong reasoning capabilities |
44
-
45
- ## Usage Examples
46
-
47
- ### Basic Text Generation
48
-
49
- ```ts
50
- import { runpod } from '@runpod/ai-sdk-provider';
51
- import { generateText } from 'ai';
52
-
53
- const { text } = await generateText({
54
- model: runpod('deep-cogito/deep-cogito-v2-llama-70b'),
55
- prompt: 'Write a Python function that sorts a list:',
56
- });
57
-
58
- console.log(text);
59
- ```
60
-
61
- ### Streaming
62
-
63
- **Note**: Streaming is not yet supported by Runpod's public endpoints. The team is working on implementing this feature.
64
-
65
- ### Chat Conversations
66
-
67
- ```ts
68
- import { runpod } from '@runpod/ai-sdk-provider';
69
- import { generateText } from 'ai';
70
-
71
- const { text } = await generateText({
72
- model: runpod('deep-cogito/deep-cogito-v2-llama-70b'),
73
- messages: [
74
- { role: 'system', content: 'You are a helpful assistant.' },
75
- { role: 'user', content: 'What is the capital of France?' },
76
- ],
77
- });
78
- ```
79
-
80
- ### Function Calling
81
-
82
- ```ts
83
- import { runpod } from '@runpod/ai-sdk-provider';
84
- import { generateText, tool } from 'ai';
85
- import { z } from 'zod';
86
-
87
- const { text, toolCalls } = await generateText({
88
- model: runpod('deep-cogito/deep-cogito-v2-llama-70b'),
89
- prompt: 'What is the weather like in San Francisco?',
90
- tools: {
91
- getWeather: tool({
92
- description: 'Get weather information for a city',
93
- parameters: z.object({
94
- city: z.string().describe('The city name'),
95
- }),
96
- execute: async ({ city }) => {
97
- // Your weather API call here
98
- return `The weather in ${city} is sunny.`;
99
- },
100
- }),
101
- },
102
- });
103
- ```
104
-
105
- ### Structured Output
106
-
107
- ```ts
108
- import { runpod } from '@runpod/ai-sdk-provider';
109
- import { generateObject } from 'ai';
110
- import { z } from 'zod';
111
-
112
- const { object } = await generateObject({
113
- model: runpod('qwen/qwen3-32b-awq'),
114
- schema: z.object({
115
- recipe: z.object({
116
- name: z.string(),
117
- ingredients: z.array(z.string()),
118
- steps: z.array(z.string()),
119
- }),
120
- }),
121
- prompt: 'Generate a recipe for chocolate chip cookies.',
122
- });
123
-
124
- console.log(object.recipe);
125
- ```
126
-
127
- ## Links
128
-
129
- - [Runpod](https://runpod.io) - Cloud platform for AI compute
130
- - [Runpod Public Endpoints Documentation](https://docs.runpod.io/hub/public-endpoints)
131
- - [AI SDK Documentation](https://ai-sdk.dev/docs)
132
- - [GitHub Repository](https://github.com/runpod/ai-sdk-provider)
1
+ # Runpod AI SDK Provider
2
+
3
+ The **Runpod provider** for the [AI SDK](https://ai-sdk.dev/docs) contains language model and image generation support for [Runpod's](https://runpod.io) public endpoints.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ # npm
9
+ npm install @runpod/ai-sdk-provider
10
+
11
+ # pnpm
12
+ pnpm add @runpod/ai-sdk-provider
13
+
14
+ # yarn
15
+ yarn add @runpod/ai-sdk-provider
16
+ ```
17
+
18
+ ## Setup
19
+
20
+ The Runpod provider requires a Runpod API key. You can obtain one from the [Runpod console](https://console.runpod.io/user/settings) under "API Keys".
21
+
22
+ ### Environment Variable
23
+
24
+ Set your API key as an environment variable:
25
+
26
+ ```bash
27
+ export RUNPOD_API_KEY="your-api-key-here"
28
+ ```
29
+
30
+ ### Provider Instance
31
+
32
+ Import the provider:
33
+
34
+ ```ts
35
+ import { runpod } from '@runpod/ai-sdk-provider';
36
+ ```
37
+
38
+ ## Supported Models
39
+
40
+ ### Language Models
41
+
42
+ | Model ID | Description |
43
+ | -------------------------------------- | ------------------------------------------------------------------- |
44
+ | `deep-cogito/deep-cogito-v2-llama-70b` | 70B parameter general-purpose LLM with advanced reasoning |
45
+ | `qwen/qwen3-32b-awq` | 32B parameter multilingual model with strong reasoning capabilities |
46
+
47
+ ### Image Models
48
+
49
+ | Model ID | Description | Supported Aspect Ratios |
50
+ | -------------------------------------- | ------------------------------- | ----------------------- |
51
+ | `qwen/qwen-image` | Text-to-image generation | 1:1, 4:3, 3:4 |
52
+ | `bytedance/seedream-3.0` | Advanced text-to-image model | 1:1, 4:3, 3:4 |
53
+ | `black-forest-labs/flux-1-kontext-dev` | Context-aware image generation | 1:1, 4:3, 3:4 |
54
+ | `black-forest-labs/flux-1-schnell` | Fast image generation (4 steps) | 1:1, 4:3, 3:4 |
55
+ | `black-forest-labs/flux-1-dev` | High-quality image generation | 1:1, 4:3, 3:4 |
56
+
57
+ ## Text Generation
58
+
59
+ ### Basic Usage
60
+
61
+ ```ts
62
+ import { runpod } from '@runpod/ai-sdk-provider';
63
+ import { generateText } from 'ai';
64
+
65
+ const { text } = await generateText({
66
+ model: runpod('deep-cogito/deep-cogito-v2-llama-70b'),
67
+ prompt: 'Write a Python function that sorts a list:',
68
+ });
69
+ ```
70
+
71
+ **Returns:**
72
+
73
+ - `text` - Generated text string
74
+ - `finishReason` - Why generation stopped ('stop', 'length', etc.)
75
+ - `usage` - Token usage information (prompt, completion, total tokens)
76
+
77
+ ### Chat Conversations
78
+
79
+ ```ts
80
+ const { text } = await generateText({
81
+ model: runpod('deep-cogito/deep-cogito-v2-llama-70b'),
82
+ messages: [
83
+ { role: 'system', content: 'You are a helpful assistant.' },
84
+ { role: 'user', content: 'What is the capital of France?' },
85
+ ],
86
+ });
87
+ ```
88
+
89
+ ### Function Calling
90
+
91
+ ```ts
92
+ import { generateText, tool } from 'ai';
93
+ import { z } from 'zod';
94
+
95
+ const { text, toolCalls } = await generateText({
96
+ model: runpod('deep-cogito/deep-cogito-v2-llama-70b'),
97
+ prompt: 'What is the weather like in San Francisco?',
98
+ tools: {
99
+ getWeather: tool({
100
+ description: 'Get weather information for a city',
101
+ parameters: z.object({
102
+ city: z.string().describe('The city name'),
103
+ }),
104
+ execute: async ({ city }) => {
105
+ return `The weather in ${city} is sunny.`;
106
+ },
107
+ }),
108
+ },
109
+ });
110
+ ```
111
+
112
+ **Additional Returns:**
113
+
114
+ - `toolCalls` - Array of tool calls made by the model
115
+ - `toolResults` - Results from executed tools
116
+
117
+ ### Structured Output
118
+
119
+ ```ts
120
+ import { generateObject } from 'ai';
121
+ import { z } from 'zod';
122
+
123
+ const { object } = await generateObject({
124
+ model: runpod('qwen/qwen3-32b-awq'),
125
+ schema: z.object({
126
+ recipe: z.object({
127
+ name: z.string(),
128
+ ingredients: z.array(z.string()),
129
+ steps: z.array(z.string()),
130
+ }),
131
+ }),
132
+ prompt: 'Generate a recipe for chocolate chip cookies.',
133
+ });
134
+ ```
135
+
136
+ **Returns:**
137
+
138
+ - `object` - Parsed object matching your schema
139
+ - `usage` - Token usage information
140
+
141
+ ### Streaming
142
+
143
+ **Note**: Streaming is not yet supported by Runpod's public endpoints. The team is working on implementing this feature.
144
+
145
+ ## Image Generation
146
+
147
+ ### Basic Usage
148
+
149
+ ```ts
150
+ import { runpod } from '@runpod/ai-sdk-provider';
151
+ import { experimental_generateImage as generateImage } from 'ai';
152
+
153
+ const { image } = await generateImage({
154
+ model: runpod.imageModel('qwen/qwen-image'),
155
+ prompt: 'A fashion-forward woman in Paris wearing a trench coat',
156
+ aspectRatio: '4:3',
157
+ });
158
+ ```
159
+
160
+ **Returns:**
161
+
162
+ - `image.uint8Array` - Binary image data (efficient for processing/saving)
163
+ - `image.base64` - Base64 encoded string (for web display)
164
+ - `image.mediaType` - MIME type ('image/jpeg' or 'image/png')
165
+ - `warnings` - Array of any warnings about unsupported parameters
166
+
167
+ ### Advanced Parameters
168
+
169
+ ```ts
170
+ const { image } = await generateImage({
171
+ model: runpod.imageModel('bytedance/seedream-3.0'),
172
+ prompt: 'A sunset over mountains',
173
+ size: '1328x1328',
174
+ seed: 42,
175
+ providerOptions: {
176
+ runpod: {
177
+ negative_prompt: 'blurry, low quality',
178
+ enable_safety_checker: true,
179
+ },
180
+ },
181
+ });
182
+
183
+ // Save to filesystem
184
+ import { writeFileSync } from 'fs';
185
+ writeFileSync('generated-image.jpg', image.uint8Array);
186
+ ```
187
+
188
+ ### Context-Aware Generation (Flux Kontext)
189
+
190
+ ```ts
191
+ const { image } = await generateImage({
192
+ model: runpod.imageModel('black-forest-labs/flux-1-kontext-dev'),
193
+ prompt: 'Transform this into a cyberpunk style with neon lights',
194
+ aspectRatio: '1:1',
195
+ providerOptions: {
196
+ runpod: {
197
+ image: 'https://example.com/input-image.jpg', // Image URL
198
+ negative_prompt: 'blurry, distorted',
199
+ },
200
+ },
201
+ });
202
+
203
+ // Alternative: Using base64 encoded image
204
+ const { image } = await generateImage({
205
+ model: runpod.imageModel('black-forest-labs/flux-1-kontext-dev'),
206
+ prompt: 'Make this image look like a painting',
207
+ aspectRatio: '4:3',
208
+ providerOptions: {
209
+ runpod: {
210
+ image: 'data:image/png;base64,iVBORw0KGgoAAAANS...', // Base64 data URI
211
+ negative_prompt: 'blurry, distorted',
212
+ },
213
+ },
214
+ });
215
+ ```
216
+
217
+ ### Advanced Configuration
218
+
219
+ ```ts
220
+ // Full control over generation parameters
221
+ const { image } = await generateImage({
222
+ model: runpod.imageModel('black-forest-labs/flux-1-dev'),
223
+ prompt: 'A majestic dragon breathing fire in a medieval castle',
224
+ size: '1328x1328',
225
+ seed: 42, // For reproducible results
226
+ providerOptions: {
227
+ runpod: {
228
+ negative_prompt: 'blurry, low quality, distorted, ugly, bad anatomy',
229
+ enable_safety_checker: true,
230
+ num_inference_steps: 50, // Higher quality (default: 28)
231
+ guidance: 3.5, // Stronger prompt adherence (default: 2)
232
+ output_format: 'png', // High quality format
233
+ // Polling settings for long generations
234
+ maxPollAttempts: 30,
235
+ pollIntervalMillis: 4000,
236
+ },
237
+ },
238
+ });
239
+
240
+ // Fast generation with minimal steps
241
+ const { image } = await generateImage({
242
+ model: runpod.imageModel('black-forest-labs/flux-1-schnell'),
243
+ prompt: 'A simple red apple',
244
+ aspectRatio: '1:1',
245
+ providerOptions: {
246
+ runpod: {
247
+ num_inference_steps: 2, // Even faster (default: 4)
248
+ guidance: 10, // Higher guidance for simple prompts
249
+ output_format: 'jpg', // Smaller file size
250
+ },
251
+ },
252
+ });
253
+ ```
254
+
255
+ ### Provider Options
256
+
257
+ | Option | Type | Default | Description |
258
+ | ----------------------- | --------- | ------- | ----------------------------------------------------------------------- |
259
+ | `negative_prompt` | `string` | `""` | Text describing what you don't want in the image |
260
+ | `enable_safety_checker` | `boolean` | `true` | Enable content safety filtering |
261
+ | `image` | `string` | - | Input image: URL or base64 data URI (required for Flux Kontext models) |
262
+ | `num_inference_steps` | `number` | Auto | Number of denoising steps (Flux: 4 for schnell, 28 for others) |
263
+ | `guidance` | `number` | Auto | Guidance scale for prompt adherence (Flux: 7 for schnell, 2 for others) |
264
+ | `output_format` | `string` | `"png"` | Output image format ("png" or "jpg") |
265
+ | `maxPollAttempts` | `number` | `60` | Maximum polling attempts for async generation |
266
+ | `pollIntervalMillis` | `number` | `5000` | Polling interval in milliseconds (5 seconds) |
267
+
268
+ **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.
269
+
270
+ ## Links
271
+
272
+ - [Runpod](https://runpod.io) - Cloud platform for AI compute
273
+ - [Runpod Public Endpoints Documentation](https://docs.runpod.io/hub/public-endpoints)
274
+ - [AI SDK Documentation](https://ai-sdk.dev/docs)
275
+ - [GitHub Repository](https://github.com/runpod/ai-sdk-provider)
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { LanguageModelV2 } from '@ai-sdk/provider';
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
4
 
@@ -6,6 +6,8 @@ type RunPodChatModelId = 'deep-cogito/deep-cogito-v2-llama-70b' | 'qwen/qwen3-32
6
6
 
7
7
  type RunPodCompletionModelId = 'deep-cogito/deep-cogito-v2-llama-70b' | 'qwen/qwen3-32b-awq' | (string & {});
8
8
 
9
+ type RunpodImageModelId = 'qwen/qwen-image' | 'bytedance/seedream-3.0' | 'black-forest-labs/flux-1-kontext-dev' | 'black-forest-labs/flux-1-schnell' | 'black-forest-labs/flux-1-dev';
10
+
9
11
  interface RunPodProviderSettings {
10
12
  /**
11
13
  RunPod API key.
@@ -38,8 +40,12 @@ interface RunPodProvider {
38
40
  Creates a completion model for text generation.
39
41
  */
40
42
  completionModel(modelId: RunPodCompletionModelId): LanguageModelV2;
43
+ /**
44
+ Creates an image model for image generation.
45
+ */
46
+ imageModel(modelId: RunpodImageModelId): ImageModelV2;
41
47
  }
42
48
  declare function createRunPod(options?: RunPodProviderSettings): RunPodProvider;
43
49
  declare const runpod: RunPodProvider;
44
50
 
45
- export { type RunPodChatModelId, type RunPodCompletionModelId, type RunPodProvider, type RunPodProviderSettings, createRunPod, runpod };
51
+ export { type RunPodChatModelId, type RunPodCompletionModelId, type RunPodProvider, type RunPodProviderSettings, type RunpodImageModelId, createRunPod, runpod };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { LanguageModelV2 } from '@ai-sdk/provider';
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
4
 
@@ -6,6 +6,8 @@ type RunPodChatModelId = 'deep-cogito/deep-cogito-v2-llama-70b' | 'qwen/qwen3-32
6
6
 
7
7
  type RunPodCompletionModelId = 'deep-cogito/deep-cogito-v2-llama-70b' | 'qwen/qwen3-32b-awq' | (string & {});
8
8
 
9
+ type RunpodImageModelId = 'qwen/qwen-image' | 'bytedance/seedream-3.0' | 'black-forest-labs/flux-1-kontext-dev' | 'black-forest-labs/flux-1-schnell' | 'black-forest-labs/flux-1-dev';
10
+
9
11
  interface RunPodProviderSettings {
10
12
  /**
11
13
  RunPod API key.
@@ -38,8 +40,12 @@ interface RunPodProvider {
38
40
  Creates a completion model for text generation.
39
41
  */
40
42
  completionModel(modelId: RunPodCompletionModelId): LanguageModelV2;
43
+ /**
44
+ Creates an image model for image generation.
45
+ */
46
+ imageModel(modelId: RunpodImageModelId): ImageModelV2;
41
47
  }
42
48
  declare function createRunPod(options?: RunPodProviderSettings): RunPodProvider;
43
49
  declare const runpod: RunPodProvider;
44
50
 
45
- export { type RunPodChatModelId, type RunPodCompletionModelId, type RunPodProvider, type RunPodProviderSettings, createRunPod, runpod };
51
+ export { type RunPodChatModelId, type RunPodCompletionModelId, type RunPodProvider, type RunPodProviderSettings, type RunpodImageModelId, createRunPod, runpod };
package/dist/index.js CHANGED
@@ -27,18 +27,307 @@ 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 import_provider_utils2 = require("@ai-sdk/provider-utils");
31
+
32
+ // src/runpod-image-model.ts
30
33
  var import_provider_utils = require("@ai-sdk/provider-utils");
34
+ var import_provider = require("@ai-sdk/provider");
35
+ var import_zod = require("zod");
36
+ var SUPPORTED_ASPECT_RATIOS = {
37
+ "1:1": "1328*1328",
38
+ // ✅ Native support
39
+ "4:3": "1472*1140",
40
+ // ✅ Native support
41
+ "3:4": "1140*1472"
42
+ // ✅ Native support
43
+ };
44
+ var SUPPORTED_SIZES = /* @__PURE__ */ new Set([
45
+ // Native aspect ratio sizes
46
+ "1328*1328",
47
+ // 1:1
48
+ "1472*1140",
49
+ // 4:3
50
+ "1140*1472",
51
+ // 3:4
52
+ // Additional validated sizes
53
+ "512*512",
54
+ "768*768",
55
+ "1024*1024",
56
+ "512*768",
57
+ "768*512",
58
+ "1024*768",
59
+ "768*1024"
60
+ ]);
61
+ var RunpodImageModel = class {
62
+ constructor(modelId, config) {
63
+ this.modelId = modelId;
64
+ this.config = config;
65
+ this.specificationVersion = "v2";
66
+ this.maxImagesPerCall = 1;
67
+ }
68
+ get provider() {
69
+ return this.config.provider;
70
+ }
71
+ async doGenerate({
72
+ prompt,
73
+ n = 1,
74
+ size,
75
+ aspectRatio,
76
+ seed,
77
+ providerOptions,
78
+ headers,
79
+ abortSignal
80
+ }) {
81
+ const warnings = [];
82
+ let runpodSize;
83
+ if (size) {
84
+ const runpodSizeCandidate = size.replace("x", "*");
85
+ if (!SUPPORTED_SIZES.has(runpodSizeCandidate)) {
86
+ throw new import_provider.InvalidArgumentError({
87
+ argument: "size",
88
+ message: `Size ${size} is not supported by Runpod. Supported sizes: ${Array.from(
89
+ SUPPORTED_SIZES
90
+ ).map((s) => s.replace("*", "x")).join(", ")}`
91
+ });
92
+ }
93
+ runpodSize = runpodSizeCandidate;
94
+ } else if (aspectRatio) {
95
+ if (!SUPPORTED_ASPECT_RATIOS[aspectRatio]) {
96
+ throw new import_provider.InvalidArgumentError({
97
+ argument: "aspectRatio",
98
+ message: `Aspect ratio ${aspectRatio} is not supported by Runpod. Supported aspect ratios: ${Object.keys(SUPPORTED_ASPECT_RATIOS).join(", ")}`
99
+ });
100
+ }
101
+ runpodSize = SUPPORTED_ASPECT_RATIOS[aspectRatio];
102
+ } else {
103
+ runpodSize = "1328*1328";
104
+ }
105
+ if (n > 1) {
106
+ warnings.push({
107
+ type: "unsupported-setting",
108
+ setting: "n",
109
+ details: "Runpod image models only support generating 1 image at a time. Using n=1."
110
+ });
111
+ }
112
+ const currentDate = this.config._internal?.currentDate?.() ?? /* @__PURE__ */ new Date();
113
+ const inputPayload = this.buildInputPayload(
114
+ prompt,
115
+ runpodSize,
116
+ seed,
117
+ providerOptions.runpod
118
+ );
119
+ const { value: response, responseHeaders } = await (0, import_provider_utils.postJsonToApi)({
120
+ url: `${this.config.baseURL}/runsync`,
121
+ headers: (0, import_provider_utils.combineHeaders)(this.config.headers(), headers),
122
+ body: {
123
+ input: inputPayload
124
+ },
125
+ failedResponseHandler: (0, import_provider_utils.createJsonErrorResponseHandler)({
126
+ errorSchema: runpodImageErrorSchema,
127
+ errorToMessage: (data) => data.error ?? "Unknown error"
128
+ }),
129
+ successfulResponseHandler: (0, import_provider_utils.createJsonResponseHandler)(
130
+ runpodImageResponseSchema
131
+ ),
132
+ abortSignal,
133
+ fetch: this.config.fetch
134
+ });
135
+ const typedResponse = response;
136
+ if (typedResponse.status === "COMPLETED" && (typedResponse.output?.result || typedResponse.output?.image_url)) {
137
+ const imageUrl = typedResponse.output.result || typedResponse.output.image_url;
138
+ const imageData = await this.downloadImage(imageUrl, abortSignal);
139
+ return {
140
+ images: [imageData],
141
+ warnings,
142
+ response: {
143
+ timestamp: currentDate,
144
+ modelId: this.modelId,
145
+ headers: responseHeaders
146
+ },
147
+ providerMetadata: {
148
+ runpod: {
149
+ images: [
150
+ {
151
+ url: imageUrl,
152
+ cost: typedResponse.output?.cost
153
+ }
154
+ ]
155
+ }
156
+ }
157
+ };
158
+ } else if (typedResponse.status === "IN_QUEUE" || typedResponse.status === "IN_PROGRESS") {
159
+ const pollOptions = {
160
+ maxAttempts: providerOptions.runpod?.maxPollAttempts,
161
+ pollIntervalMillis: providerOptions.runpod?.pollIntervalMillis
162
+ };
163
+ const imageUrl = await this.pollForCompletion(
164
+ typedResponse.id,
165
+ abortSignal,
166
+ pollOptions
167
+ );
168
+ const imageData = await this.downloadImage(imageUrl, abortSignal);
169
+ return {
170
+ images: [imageData],
171
+ warnings,
172
+ response: {
173
+ timestamp: currentDate,
174
+ modelId: this.modelId,
175
+ headers: responseHeaders
176
+ },
177
+ providerMetadata: {
178
+ runpod: {
179
+ images: [
180
+ {
181
+ url: imageUrl,
182
+ jobId: typedResponse.id
183
+ }
184
+ ]
185
+ }
186
+ }
187
+ };
188
+ } else {
189
+ throw new Error(`Unexpected response status: ${typedResponse.status}`);
190
+ }
191
+ }
192
+ async downloadImage(imageUrl, abortSignal) {
193
+ const { value: imageData } = await (0, import_provider_utils.getFromApi)({
194
+ url: imageUrl,
195
+ successfulResponseHandler: (0, import_provider_utils.createBinaryResponseHandler)(),
196
+ failedResponseHandler: (0, import_provider_utils.createJsonErrorResponseHandler)({
197
+ errorSchema: runpodImageErrorSchema,
198
+ errorToMessage: (data) => data.error ?? "Failed to download image"
199
+ }),
200
+ abortSignal,
201
+ fetch: this.config.fetch
202
+ });
203
+ return imageData;
204
+ }
205
+ async pollForCompletion(jobId, abortSignal, pollOptions) {
206
+ const maxAttempts = pollOptions?.maxAttempts ?? 60;
207
+ const pollInterval = pollOptions?.pollIntervalMillis ?? 5e3;
208
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
209
+ if (abortSignal?.aborted) {
210
+ throw new Error("Image generation was aborted");
211
+ }
212
+ const { value: statusResponse } = await (0, import_provider_utils.getFromApi)({
213
+ url: `${this.config.baseURL}/status/${jobId}`,
214
+ headers: this.config.headers(),
215
+ successfulResponseHandler: (0, import_provider_utils.createJsonResponseHandler)(
216
+ runpodImageStatusSchema
217
+ ),
218
+ failedResponseHandler: (0, import_provider_utils.createJsonErrorResponseHandler)({
219
+ errorSchema: runpodImageErrorSchema,
220
+ errorToMessage: (data) => data.error ?? "Failed to check job status"
221
+ }),
222
+ abortSignal,
223
+ fetch: this.config.fetch
224
+ });
225
+ const typedStatusResponse = statusResponse;
226
+ if (typedStatusResponse.status === "COMPLETED" && (typedStatusResponse.output?.result || typedStatusResponse.output?.image_url)) {
227
+ return typedStatusResponse.output.result || typedStatusResponse.output.image_url;
228
+ }
229
+ if (typedStatusResponse.status === "FAILED") {
230
+ throw new Error(
231
+ `Image generation failed: ${typedStatusResponse.error || "Unknown error"}`
232
+ );
233
+ }
234
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
235
+ }
236
+ throw new Error(
237
+ `Image generation timed out after ${maxAttempts} attempts (${maxAttempts * pollInterval / 1e3}s)`
238
+ );
239
+ }
240
+ buildInputPayload(prompt, runpodSize, seed, runpodOptions) {
241
+ const isFluxModel = this.modelId.includes("flux") || this.modelId.includes("black-forest-labs");
242
+ if (isFluxModel) {
243
+ const isKontext = this.modelId.includes("kontext");
244
+ if (isKontext) {
245
+ return {
246
+ prompt,
247
+ negative_prompt: runpodOptions?.negative_prompt ?? "",
248
+ seed: seed ?? -1,
249
+ num_inference_steps: 28,
250
+ guidance: 2,
251
+ size: runpodSize,
252
+ output_format: "png",
253
+ enable_safety_checker: runpodOptions?.enable_safety_checker ?? true,
254
+ ...runpodOptions
255
+ // This will include the 'image' parameter if provided
256
+ };
257
+ } else {
258
+ const [width, height] = runpodSize.split("*").map(Number);
259
+ return {
260
+ prompt,
261
+ negative_prompt: runpodOptions?.negative_prompt ?? "",
262
+ seed: seed ?? -1,
263
+ num_inference_steps: this.modelId.includes("schnell") ? 4 : 28,
264
+ guidance: this.modelId.includes("schnell") ? 7 : 2,
265
+ width,
266
+ height,
267
+ image_format: "png",
268
+ ...runpodOptions
269
+ };
270
+ }
271
+ }
272
+ return {
273
+ prompt,
274
+ negative_prompt: runpodOptions?.negative_prompt ?? "",
275
+ size: runpodSize,
276
+ seed: seed ?? -1,
277
+ enable_safety_checker: runpodOptions?.enable_safety_checker ?? true,
278
+ ...runpodOptions
279
+ };
280
+ }
281
+ };
282
+ var runpodImageResponseSchema = import_zod.z.object({
283
+ id: import_zod.z.string(),
284
+ status: import_zod.z.enum(["COMPLETED", "IN_QUEUE", "IN_PROGRESS", "FAILED"]),
285
+ delayTime: import_zod.z.number().optional(),
286
+ executionTime: import_zod.z.number().optional(),
287
+ output: import_zod.z.object({
288
+ cost: import_zod.z.number().optional(),
289
+ result: import_zod.z.string().optional(),
290
+ // URL to the generated image (Qwen format)
291
+ image_url: import_zod.z.string().optional()
292
+ // URL to the generated image (Flux format)
293
+ }).optional()
294
+ // Optional for IN_QUEUE/IN_PROGRESS responses
295
+ });
296
+ var runpodImageStatusSchema = import_zod.z.object({
297
+ id: import_zod.z.string(),
298
+ status: import_zod.z.enum(["COMPLETED", "IN_QUEUE", "IN_PROGRESS", "FAILED"]),
299
+ output: import_zod.z.object({
300
+ cost: import_zod.z.number().optional(),
301
+ result: import_zod.z.string().optional(),
302
+ image_url: import_zod.z.string().optional()
303
+ }).optional(),
304
+ error: import_zod.z.string().optional()
305
+ // Error message if FAILED
306
+ });
307
+ var runpodImageErrorSchema = import_zod.z.object({
308
+ error: import_zod.z.string(),
309
+ message: import_zod.z.string().optional()
310
+ });
311
+
312
+ // src/runpod-provider.ts
31
313
  var MODEL_ID_TO_ENDPOINT_URL = {
32
314
  "deep-cogito/deep-cogito-v2-llama-70b": "https://api.runpod.ai/v2/deep-cogito-v2-llama-70b/openai/v1",
33
315
  "qwen/qwen3-32b-awq": "https://api.runpod.ai/v2/qwen3-32b-awq/openai/v1"
34
316
  };
317
+ var IMAGE_MODEL_ID_TO_ENDPOINT_URL = {
318
+ "qwen/qwen-image": "https://api.runpod.ai/v2/qwen-image-t2i",
319
+ "bytedance/seedream-3.0": "https://api.runpod.ai/v2/seedream-3-0-t2i",
320
+ "black-forest-labs/flux-1-kontext-dev": "https://api.runpod.ai/v2/black-forest-labs-flux-1-kontext-dev",
321
+ "black-forest-labs/flux-1-schnell": "https://api.runpod.ai/v2/black-forest-labs-flux-1-schnell",
322
+ "black-forest-labs/flux-1-dev": "https://api.runpod.ai/v2/black-forest-labs-flux-1-dev"
323
+ };
35
324
  var MODEL_ID_TO_OPENAI_NAME = {
36
325
  "deep-cogito/deep-cogito-v2-llama-70b": "deepcogito/cogito-v2-preview-llama-70B",
37
326
  "qwen/qwen3-32b-awq": "Qwen/Qwen3-32B-AWQ"
38
327
  };
39
328
  function createRunPod(options = {}) {
40
329
  const getHeaders = () => ({
41
- Authorization: `Bearer ${(0, import_provider_utils.loadApiKey)({
330
+ Authorization: `Bearer ${(0, import_provider_utils2.loadApiKey)({
42
331
  apiKey: options.apiKey,
43
332
  environmentVariableName: "RUNPOD_API_KEY",
44
333
  description: "RunPod"
@@ -56,7 +345,7 @@ function createRunPod(options = {}) {
56
345
  }
57
346
  return {
58
347
  provider: `runpod.${modelType}`,
59
- url: ({ path }) => `${(0, import_provider_utils.withoutTrailingSlash)(baseURL)}${path}`,
348
+ url: ({ path }) => `${(0, import_provider_utils2.withoutTrailingSlash)(baseURL)}${path}`,
60
349
  headers: getHeaders,
61
350
  fetch: options.fetch
62
351
  };
@@ -75,10 +364,27 @@ function createRunPod(options = {}) {
75
364
  getModelConfig(modelId, "completion")
76
365
  );
77
366
  };
367
+ const createImageModel = (modelId) => {
368
+ const baseURL = IMAGE_MODEL_ID_TO_ENDPOINT_URL[modelId];
369
+ if (!baseURL) {
370
+ throw new Error(
371
+ `Unsupported Runpod image model: ${modelId}. Supported models: ${Object.keys(
372
+ IMAGE_MODEL_ID_TO_ENDPOINT_URL
373
+ ).join(", ")}`
374
+ );
375
+ }
376
+ return new RunpodImageModel(modelId, {
377
+ provider: "runpod.image",
378
+ baseURL,
379
+ headers: getHeaders,
380
+ fetch: options.fetch
381
+ });
382
+ };
78
383
  const provider = (modelId) => createChatModel(modelId);
79
384
  provider.completionModel = createCompletionModel;
80
385
  provider.languageModel = createChatModel;
81
386
  provider.chatModel = createChatModel;
387
+ provider.imageModel = createImageModel;
82
388
  return provider;
83
389
  }
84
390
  var runpod = createRunPod();
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/runpod-provider.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 { OpenAICompatibleErrorData as RunPodErrorData } from '@ai-sdk/openai-compatible';\n","import { LanguageModelV2 } 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';\n\nexport interface RunPodProviderSettings {\n /**\nRunPod API key.\n*/\n apiKey?: 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\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 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 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 const 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(', ')}`\n );\n }\n\n return {\n provider: `runpod.${modelType}`,\n url: ({ path }) => `${withoutTrailingSlash(baseURL)}${path}`,\n headers: getHeaders,\n fetch: options.fetch,\n };\n };\n\n const createChatModel = (modelId: RunPodChatModelId) => {\n const openaiModelName = MODEL_ID_TO_OPENAI_NAME[modelId] || modelId;\n return new OpenAICompatibleChatLanguageModel(\n openaiModelName,\n getModelConfig(modelId, 'chat')\n );\n };\n\n const createCompletionModel = (modelId: RunPodCompletionModelId) => {\n const openaiModelName = MODEL_ID_TO_OPENAI_NAME[modelId] || modelId;\n return new OpenAICompatibleCompletionLanguageModel(\n openaiModelName,\n getModelConfig(modelId, 'completion')\n );\n };\n\n const provider = (modelId: RunPodChatModelId) => createChatModel(modelId);\n\n provider.completionModel = createCompletionModel;\n provider.languageModel = createChatModel;\n provider.chatModel = createChatModel;\n\n return provider;\n}\n\nexport const runpod = createRunPod();\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACCA,+BAGO;AACP,4BAIO;AA2CP,IAAM,2BAAmD;AAAA,EACvD,wCACE;AAAA,EACF,sBAAsB;AACxB;AAGA,IAAM,0BAAkD;AAAA,EACtD,wCACE;AAAA,EACF,sBAAsB;AACxB;AAEO,SAAS,aACd,UAAkC,CAAC,GACnB;AAChB,QAAM,aAAa,OAAO;AAAA,IACxB,eAAe,cAAU,kCAAW;AAAA,MAClC,QAAQ,QAAQ;AAAA,MAChB,yBAAyB;AAAA,MACzB,aAAa;AAAA,IACf,CAAC,CAAC;AAAA,IACF,GAAG,QAAQ;AAAA,EACb;AASA,QAAM,iBAAiB,CACrB,SACA,cACsB;AACtB,UAAM,UAAU,yBAAyB,OAAO;AAChD,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI;AAAA,QACR,6BAA6B,OAAO,uBAAuB,OAAO;AAAA,UAChE;AAAA,QACF,EAAE,KAAK,IAAI,CAAC;AAAA,MACd;AAAA,IACF;AAEA,WAAO;AAAA,MACL,UAAU,UAAU,SAAS;AAAA,MAC7B,KAAK,CAAC,EAAE,KAAK,MAAM,OAAG,4CAAqB,OAAO,CAAC,GAAG,IAAI;AAAA,MAC1D,SAAS;AAAA,MACT,OAAO,QAAQ;AAAA,IACjB;AAAA,EACF;AAEA,QAAM,kBAAkB,CAAC,YAA+B;AACtD,UAAM,kBAAkB,wBAAwB,OAAO,KAAK;AAC5D,WAAO,IAAI;AAAA,MACT;AAAA,MACA,eAAe,SAAS,MAAM;AAAA,IAChC;AAAA,EACF;AAEA,QAAM,wBAAwB,CAAC,YAAqC;AAClE,UAAM,kBAAkB,wBAAwB,OAAO,KAAK;AAC5D,WAAO,IAAI;AAAA,MACT;AAAA,MACA,eAAe,SAAS,YAAY;AAAA,IACtC;AAAA,EACF;AAEA,QAAM,WAAW,CAAC,YAA+B,gBAAgB,OAAO;AAExE,WAAS,kBAAkB;AAC3B,WAAS,gBAAgB;AACzB,WAAS,YAAY;AAErB,SAAO;AACT;AAEO,IAAM,SAAS,aAAa;","names":[]}
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 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 'bytedance/seedream-3.0': 'https://api.runpod.ai/v2/seedream-3-0-t2i',\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 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 const 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(', ')}`\n );\n }\n\n return {\n provider: `runpod.${modelType}`,\n url: ({ path }) => `${withoutTrailingSlash(baseURL)}${path}`,\n headers: getHeaders,\n fetch: options.fetch,\n };\n };\n\n const createChatModel = (modelId: RunPodChatModelId) => {\n const openaiModelName = MODEL_ID_TO_OPENAI_NAME[modelId] || modelId;\n return new OpenAICompatibleChatLanguageModel(\n openaiModelName,\n getModelConfig(modelId, 'chat')\n );\n };\n\n const createCompletionModel = (modelId: RunPodCompletionModelId) => {\n const openaiModelName = MODEL_ID_TO_OPENAI_NAME[modelId] || modelId;\n return new OpenAICompatibleCompletionLanguageModel(\n openaiModelName,\n getModelConfig(modelId, 'completion')\n );\n };\n\n const createImageModel = (modelId: RunpodImageModelId) => {\n const 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(', ')}`\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 '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":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACCA,+BAGO;AACP,IAAAA,yBAIO;;;ACRP,4BAQO;AACP,sBAAqC;AACrC,iBAAkB;AAclB,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;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,qCAAc;AAAA,MAC/D,KAAK,GAAG,KAAK,OAAO,OAAO;AAAA,MAC3B,aAAS,sCAAe,KAAK,OAAO,QAAQ,GAAG,OAAO;AAAA,MACtD,MAAM;AAAA,QACJ,OAAO;AAAA,MACT;AAAA,MACA,2BAAuB,sDAA+B;AAAA,QACpD,aAAa;AAAA,QACb,gBAAgB,CAAC,SAAc,KAAK,SAAS;AAAA,MAC/C,CAAC;AAAA,MACD,+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,kCAAW;AAAA,MAC5C,KAAK;AAAA,MACL,+BAA2B,mDAA4B;AAAA,MACvD,2BAAuB,sDAA+B;AAAA,QACpD,aAAa;AAAA,QACb,gBAAgB,CAAC,SAAc,KAAK,SAAS;AAAA,MAC/C,CAAC;AAAA,MACD;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,kCAAW;AAAA,QACjD,KAAK,GAAG,KAAK,OAAO,OAAO,WAAW,KAAK;AAAA,QAC3C,SAAS,KAAK,OAAO,QAAQ;AAAA,QAC7B,+BAA2B;AAAA,UACzB;AAAA,QACF;AAAA,QACA,2BAAuB,sDAA+B;AAAA,UACpD,aAAa;AAAA,UACb,gBAAgB,CAAC,SACf,KAAK,SAAS;AAAA,QAClB,CAAC;AAAA,QACD;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,aAAE,OAAO;AAAA,EACzC,IAAI,aAAE,OAAO;AAAA,EACb,QAAQ,aAAE,KAAK,CAAC,aAAa,YAAY,eAAe,QAAQ,CAAC;AAAA,EACjE,WAAW,aAAE,OAAO,EAAE,SAAS;AAAA,EAC/B,eAAe,aAAE,OAAO,EAAE,SAAS;AAAA,EACnC,QAAQ,aACL,OAAO;AAAA,IACN,MAAM,aAAE,OAAO,EAAE,SAAS;AAAA,IAC1B,QAAQ,aAAE,OAAO,EAAE,SAAS;AAAA;AAAA,IAC5B,WAAW,aAAE,OAAO,EAAE,SAAS;AAAA;AAAA,EACjC,CAAC,EACA,SAAS;AAAA;AACd,CAAC;AAGD,IAAM,0BAA0B,aAAE,OAAO;AAAA,EACvC,IAAI,aAAE,OAAO;AAAA,EACb,QAAQ,aAAE,KAAK,CAAC,aAAa,YAAY,eAAe,QAAQ,CAAC;AAAA,EACjE,QAAQ,aACL,OAAO;AAAA,IACN,MAAM,aAAE,OAAO,EAAE,SAAS;AAAA,IAC1B,QAAQ,aAAE,OAAO,EAAE,SAAS;AAAA,IAC5B,WAAW,aAAE,OAAO,EAAE,SAAS;AAAA,EACjC,CAAC,EACA,SAAS;AAAA,EACZ,OAAO,aAAE,OAAO,EAAE,SAAS;AAAA;AAC7B,CAAC;AAGD,IAAM,yBAAyB,aAAE,OAAO;AAAA,EACtC,OAAO,aAAE,OAAO;AAAA,EAChB,SAAS,aAAE,OAAO,EAAE,SAAS;AAC/B,CAAC;;;ADnUD,IAAM,2BAAmD;AAAA,EACvD,wCACE;AAAA,EACF,sBAAsB;AACxB;AAGA,IAAM,iCAAyD;AAAA,EAC7D,mBAAmB;AAAA,EACnB,0BAA0B;AAAA,EAC1B,wCACE;AAAA,EACF,oCACE;AAAA,EACF,gCACE;AACJ;AAGA,IAAM,0BAAkD;AAAA,EACtD,wCACE;AAAA,EACF,sBAAsB;AACxB;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;AASA,QAAM,iBAAiB,CACrB,SACA,cACsB;AACtB,UAAM,UAAU,yBAAyB,OAAO;AAChD,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI;AAAA,QACR,6BAA6B,OAAO,uBAAuB,OAAO;AAAA,UAChE;AAAA,QACF,EAAE,KAAK,IAAI,CAAC;AAAA,MACd;AAAA,IACF;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,QAAQ;AAAA,IACjB;AAAA,EACF;AAEA,QAAM,kBAAkB,CAAC,YAA+B;AACtD,UAAM,kBAAkB,wBAAwB,OAAO,KAAK;AAC5D,WAAO,IAAI;AAAA,MACT;AAAA,MACA,eAAe,SAAS,MAAM;AAAA,IAChC;AAAA,EACF;AAEA,QAAM,wBAAwB,CAAC,YAAqC;AAClE,UAAM,kBAAkB,wBAAwB,OAAO,KAAK;AAC5D,WAAO,IAAI;AAAA,MACT;AAAA,MACA,eAAe,SAAS,YAAY;AAAA,IACtC;AAAA,EACF;AAEA,QAAM,mBAAmB,CAAC,YAAgC;AACxD,UAAM,UAAU,+BAA+B,OAAO;AACtD,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI;AAAA,QACR,mCAAmC,OAAO,uBAAuB,OAAO;AAAA,UACtE;AAAA,QACF,EAAE,KAAK,IAAI,CAAC;AAAA,MACd;AAAA,IACF;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,YAA+B,gBAAgB,OAAO;AAExE,WAAS,kBAAkB;AAC3B,WAAS,gBAAgB;AACzB,WAAS,YAAY;AACrB,WAAS,aAAa;AAEtB,SAAO;AACT;AAEO,IAAM,SAAS,aAAa;","names":["import_provider_utils"]}
package/dist/index.mjs CHANGED
@@ -7,10 +7,306 @@ import {
7
7
  loadApiKey,
8
8
  withoutTrailingSlash
9
9
  } from "@ai-sdk/provider-utils";
10
+
11
+ // src/runpod-image-model.ts
12
+ import {
13
+ combineHeaders,
14
+ createJsonResponseHandler,
15
+ createJsonErrorResponseHandler,
16
+ createBinaryResponseHandler,
17
+ postJsonToApi,
18
+ getFromApi
19
+ } from "@ai-sdk/provider-utils";
20
+ import { InvalidArgumentError } from "@ai-sdk/provider";
21
+ import { z } from "zod";
22
+ var SUPPORTED_ASPECT_RATIOS = {
23
+ "1:1": "1328*1328",
24
+ // ✅ Native support
25
+ "4:3": "1472*1140",
26
+ // ✅ Native support
27
+ "3:4": "1140*1472"
28
+ // ✅ Native support
29
+ };
30
+ var SUPPORTED_SIZES = /* @__PURE__ */ new Set([
31
+ // Native aspect ratio sizes
32
+ "1328*1328",
33
+ // 1:1
34
+ "1472*1140",
35
+ // 4:3
36
+ "1140*1472",
37
+ // 3:4
38
+ // Additional validated sizes
39
+ "512*512",
40
+ "768*768",
41
+ "1024*1024",
42
+ "512*768",
43
+ "768*512",
44
+ "1024*768",
45
+ "768*1024"
46
+ ]);
47
+ var RunpodImageModel = class {
48
+ constructor(modelId, config) {
49
+ this.modelId = modelId;
50
+ this.config = config;
51
+ this.specificationVersion = "v2";
52
+ this.maxImagesPerCall = 1;
53
+ }
54
+ get provider() {
55
+ return this.config.provider;
56
+ }
57
+ async doGenerate({
58
+ prompt,
59
+ n = 1,
60
+ size,
61
+ aspectRatio,
62
+ seed,
63
+ providerOptions,
64
+ headers,
65
+ abortSignal
66
+ }) {
67
+ const warnings = [];
68
+ let runpodSize;
69
+ if (size) {
70
+ const runpodSizeCandidate = size.replace("x", "*");
71
+ if (!SUPPORTED_SIZES.has(runpodSizeCandidate)) {
72
+ throw new InvalidArgumentError({
73
+ argument: "size",
74
+ message: `Size ${size} is not supported by Runpod. Supported sizes: ${Array.from(
75
+ SUPPORTED_SIZES
76
+ ).map((s) => s.replace("*", "x")).join(", ")}`
77
+ });
78
+ }
79
+ runpodSize = runpodSizeCandidate;
80
+ } else if (aspectRatio) {
81
+ if (!SUPPORTED_ASPECT_RATIOS[aspectRatio]) {
82
+ throw new InvalidArgumentError({
83
+ argument: "aspectRatio",
84
+ message: `Aspect ratio ${aspectRatio} is not supported by Runpod. Supported aspect ratios: ${Object.keys(SUPPORTED_ASPECT_RATIOS).join(", ")}`
85
+ });
86
+ }
87
+ runpodSize = SUPPORTED_ASPECT_RATIOS[aspectRatio];
88
+ } else {
89
+ runpodSize = "1328*1328";
90
+ }
91
+ if (n > 1) {
92
+ warnings.push({
93
+ type: "unsupported-setting",
94
+ setting: "n",
95
+ details: "Runpod image models only support generating 1 image at a time. Using n=1."
96
+ });
97
+ }
98
+ const currentDate = this.config._internal?.currentDate?.() ?? /* @__PURE__ */ new Date();
99
+ const inputPayload = this.buildInputPayload(
100
+ prompt,
101
+ runpodSize,
102
+ seed,
103
+ providerOptions.runpod
104
+ );
105
+ const { value: response, responseHeaders } = await postJsonToApi({
106
+ url: `${this.config.baseURL}/runsync`,
107
+ headers: combineHeaders(this.config.headers(), headers),
108
+ body: {
109
+ input: inputPayload
110
+ },
111
+ failedResponseHandler: createJsonErrorResponseHandler({
112
+ errorSchema: runpodImageErrorSchema,
113
+ errorToMessage: (data) => data.error ?? "Unknown error"
114
+ }),
115
+ successfulResponseHandler: createJsonResponseHandler(
116
+ runpodImageResponseSchema
117
+ ),
118
+ abortSignal,
119
+ fetch: this.config.fetch
120
+ });
121
+ const typedResponse = response;
122
+ if (typedResponse.status === "COMPLETED" && (typedResponse.output?.result || typedResponse.output?.image_url)) {
123
+ const imageUrl = typedResponse.output.result || typedResponse.output.image_url;
124
+ const imageData = await this.downloadImage(imageUrl, abortSignal);
125
+ return {
126
+ images: [imageData],
127
+ warnings,
128
+ response: {
129
+ timestamp: currentDate,
130
+ modelId: this.modelId,
131
+ headers: responseHeaders
132
+ },
133
+ providerMetadata: {
134
+ runpod: {
135
+ images: [
136
+ {
137
+ url: imageUrl,
138
+ cost: typedResponse.output?.cost
139
+ }
140
+ ]
141
+ }
142
+ }
143
+ };
144
+ } else if (typedResponse.status === "IN_QUEUE" || typedResponse.status === "IN_PROGRESS") {
145
+ const pollOptions = {
146
+ maxAttempts: providerOptions.runpod?.maxPollAttempts,
147
+ pollIntervalMillis: providerOptions.runpod?.pollIntervalMillis
148
+ };
149
+ const imageUrl = await this.pollForCompletion(
150
+ typedResponse.id,
151
+ abortSignal,
152
+ pollOptions
153
+ );
154
+ const imageData = await this.downloadImage(imageUrl, abortSignal);
155
+ return {
156
+ images: [imageData],
157
+ warnings,
158
+ response: {
159
+ timestamp: currentDate,
160
+ modelId: this.modelId,
161
+ headers: responseHeaders
162
+ },
163
+ providerMetadata: {
164
+ runpod: {
165
+ images: [
166
+ {
167
+ url: imageUrl,
168
+ jobId: typedResponse.id
169
+ }
170
+ ]
171
+ }
172
+ }
173
+ };
174
+ } else {
175
+ throw new Error(`Unexpected response status: ${typedResponse.status}`);
176
+ }
177
+ }
178
+ async downloadImage(imageUrl, abortSignal) {
179
+ const { value: imageData } = await getFromApi({
180
+ url: imageUrl,
181
+ successfulResponseHandler: createBinaryResponseHandler(),
182
+ failedResponseHandler: createJsonErrorResponseHandler({
183
+ errorSchema: runpodImageErrorSchema,
184
+ errorToMessage: (data) => data.error ?? "Failed to download image"
185
+ }),
186
+ abortSignal,
187
+ fetch: this.config.fetch
188
+ });
189
+ return imageData;
190
+ }
191
+ async pollForCompletion(jobId, abortSignal, pollOptions) {
192
+ const maxAttempts = pollOptions?.maxAttempts ?? 60;
193
+ const pollInterval = pollOptions?.pollIntervalMillis ?? 5e3;
194
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
195
+ if (abortSignal?.aborted) {
196
+ throw new Error("Image generation was aborted");
197
+ }
198
+ const { value: statusResponse } = await getFromApi({
199
+ url: `${this.config.baseURL}/status/${jobId}`,
200
+ headers: this.config.headers(),
201
+ successfulResponseHandler: createJsonResponseHandler(
202
+ runpodImageStatusSchema
203
+ ),
204
+ failedResponseHandler: createJsonErrorResponseHandler({
205
+ errorSchema: runpodImageErrorSchema,
206
+ errorToMessage: (data) => data.error ?? "Failed to check job status"
207
+ }),
208
+ abortSignal,
209
+ fetch: this.config.fetch
210
+ });
211
+ const typedStatusResponse = statusResponse;
212
+ if (typedStatusResponse.status === "COMPLETED" && (typedStatusResponse.output?.result || typedStatusResponse.output?.image_url)) {
213
+ return typedStatusResponse.output.result || typedStatusResponse.output.image_url;
214
+ }
215
+ if (typedStatusResponse.status === "FAILED") {
216
+ throw new Error(
217
+ `Image generation failed: ${typedStatusResponse.error || "Unknown error"}`
218
+ );
219
+ }
220
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
221
+ }
222
+ throw new Error(
223
+ `Image generation timed out after ${maxAttempts} attempts (${maxAttempts * pollInterval / 1e3}s)`
224
+ );
225
+ }
226
+ buildInputPayload(prompt, runpodSize, seed, runpodOptions) {
227
+ const isFluxModel = this.modelId.includes("flux") || this.modelId.includes("black-forest-labs");
228
+ if (isFluxModel) {
229
+ const isKontext = this.modelId.includes("kontext");
230
+ if (isKontext) {
231
+ return {
232
+ prompt,
233
+ negative_prompt: runpodOptions?.negative_prompt ?? "",
234
+ seed: seed ?? -1,
235
+ num_inference_steps: 28,
236
+ guidance: 2,
237
+ size: runpodSize,
238
+ output_format: "png",
239
+ enable_safety_checker: runpodOptions?.enable_safety_checker ?? true,
240
+ ...runpodOptions
241
+ // This will include the 'image' parameter if provided
242
+ };
243
+ } else {
244
+ const [width, height] = runpodSize.split("*").map(Number);
245
+ return {
246
+ prompt,
247
+ negative_prompt: runpodOptions?.negative_prompt ?? "",
248
+ seed: seed ?? -1,
249
+ num_inference_steps: this.modelId.includes("schnell") ? 4 : 28,
250
+ guidance: this.modelId.includes("schnell") ? 7 : 2,
251
+ width,
252
+ height,
253
+ image_format: "png",
254
+ ...runpodOptions
255
+ };
256
+ }
257
+ }
258
+ return {
259
+ prompt,
260
+ negative_prompt: runpodOptions?.negative_prompt ?? "",
261
+ size: runpodSize,
262
+ seed: seed ?? -1,
263
+ enable_safety_checker: runpodOptions?.enable_safety_checker ?? true,
264
+ ...runpodOptions
265
+ };
266
+ }
267
+ };
268
+ var runpodImageResponseSchema = z.object({
269
+ id: z.string(),
270
+ status: z.enum(["COMPLETED", "IN_QUEUE", "IN_PROGRESS", "FAILED"]),
271
+ delayTime: z.number().optional(),
272
+ executionTime: z.number().optional(),
273
+ output: z.object({
274
+ cost: z.number().optional(),
275
+ result: z.string().optional(),
276
+ // URL to the generated image (Qwen format)
277
+ image_url: z.string().optional()
278
+ // URL to the generated image (Flux format)
279
+ }).optional()
280
+ // Optional for IN_QUEUE/IN_PROGRESS responses
281
+ });
282
+ var runpodImageStatusSchema = z.object({
283
+ id: z.string(),
284
+ status: z.enum(["COMPLETED", "IN_QUEUE", "IN_PROGRESS", "FAILED"]),
285
+ output: z.object({
286
+ cost: z.number().optional(),
287
+ result: z.string().optional(),
288
+ image_url: z.string().optional()
289
+ }).optional(),
290
+ error: z.string().optional()
291
+ // Error message if FAILED
292
+ });
293
+ var runpodImageErrorSchema = z.object({
294
+ error: z.string(),
295
+ message: z.string().optional()
296
+ });
297
+
298
+ // src/runpod-provider.ts
10
299
  var MODEL_ID_TO_ENDPOINT_URL = {
11
300
  "deep-cogito/deep-cogito-v2-llama-70b": "https://api.runpod.ai/v2/deep-cogito-v2-llama-70b/openai/v1",
12
301
  "qwen/qwen3-32b-awq": "https://api.runpod.ai/v2/qwen3-32b-awq/openai/v1"
13
302
  };
303
+ var IMAGE_MODEL_ID_TO_ENDPOINT_URL = {
304
+ "qwen/qwen-image": "https://api.runpod.ai/v2/qwen-image-t2i",
305
+ "bytedance/seedream-3.0": "https://api.runpod.ai/v2/seedream-3-0-t2i",
306
+ "black-forest-labs/flux-1-kontext-dev": "https://api.runpod.ai/v2/black-forest-labs-flux-1-kontext-dev",
307
+ "black-forest-labs/flux-1-schnell": "https://api.runpod.ai/v2/black-forest-labs-flux-1-schnell",
308
+ "black-forest-labs/flux-1-dev": "https://api.runpod.ai/v2/black-forest-labs-flux-1-dev"
309
+ };
14
310
  var MODEL_ID_TO_OPENAI_NAME = {
15
311
  "deep-cogito/deep-cogito-v2-llama-70b": "deepcogito/cogito-v2-preview-llama-70B",
16
312
  "qwen/qwen3-32b-awq": "Qwen/Qwen3-32B-AWQ"
@@ -54,10 +350,27 @@ function createRunPod(options = {}) {
54
350
  getModelConfig(modelId, "completion")
55
351
  );
56
352
  };
353
+ const createImageModel = (modelId) => {
354
+ const baseURL = IMAGE_MODEL_ID_TO_ENDPOINT_URL[modelId];
355
+ if (!baseURL) {
356
+ throw new Error(
357
+ `Unsupported Runpod image model: ${modelId}. Supported models: ${Object.keys(
358
+ IMAGE_MODEL_ID_TO_ENDPOINT_URL
359
+ ).join(", ")}`
360
+ );
361
+ }
362
+ return new RunpodImageModel(modelId, {
363
+ provider: "runpod.image",
364
+ baseURL,
365
+ headers: getHeaders,
366
+ fetch: options.fetch
367
+ });
368
+ };
57
369
  const provider = (modelId) => createChatModel(modelId);
58
370
  provider.completionModel = createCompletionModel;
59
371
  provider.languageModel = createChatModel;
60
372
  provider.chatModel = createChatModel;
373
+ provider.imageModel = createImageModel;
61
374
  return provider;
62
375
  }
63
376
  var runpod = createRunPod();
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/runpod-provider.ts"],"sourcesContent":["import { LanguageModelV2 } 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';\n\nexport interface RunPodProviderSettings {\n /**\nRunPod API key.\n*/\n apiKey?: 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\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 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 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 const 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(', ')}`\n );\n }\n\n return {\n provider: `runpod.${modelType}`,\n url: ({ path }) => `${withoutTrailingSlash(baseURL)}${path}`,\n headers: getHeaders,\n fetch: options.fetch,\n };\n };\n\n const createChatModel = (modelId: RunPodChatModelId) => {\n const openaiModelName = MODEL_ID_TO_OPENAI_NAME[modelId] || modelId;\n return new OpenAICompatibleChatLanguageModel(\n openaiModelName,\n getModelConfig(modelId, 'chat')\n );\n };\n\n const createCompletionModel = (modelId: RunPodCompletionModelId) => {\n const openaiModelName = MODEL_ID_TO_OPENAI_NAME[modelId] || modelId;\n return new OpenAICompatibleCompletionLanguageModel(\n openaiModelName,\n getModelConfig(modelId, 'completion')\n );\n };\n\n const provider = (modelId: RunPodChatModelId) => createChatModel(modelId);\n\n provider.completionModel = createCompletionModel;\n provider.languageModel = createChatModel;\n provider.chatModel = createChatModel;\n\n return provider;\n}\n\nexport const runpod = createRunPod();\n"],"mappings":";AACA;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP;AAAA,EAEE;AAAA,EACA;AAAA,OACK;AA2CP,IAAM,2BAAmD;AAAA,EACvD,wCACE;AAAA,EACF,sBAAsB;AACxB;AAGA,IAAM,0BAAkD;AAAA,EACtD,wCACE;AAAA,EACF,sBAAsB;AACxB;AAEO,SAAS,aACd,UAAkC,CAAC,GACnB;AAChB,QAAM,aAAa,OAAO;AAAA,IACxB,eAAe,UAAU,WAAW;AAAA,MAClC,QAAQ,QAAQ;AAAA,MAChB,yBAAyB;AAAA,MACzB,aAAa;AAAA,IACf,CAAC,CAAC;AAAA,IACF,GAAG,QAAQ;AAAA,EACb;AASA,QAAM,iBAAiB,CACrB,SACA,cACsB;AACtB,UAAM,UAAU,yBAAyB,OAAO;AAChD,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI;AAAA,QACR,6BAA6B,OAAO,uBAAuB,OAAO;AAAA,UAChE;AAAA,QACF,EAAE,KAAK,IAAI,CAAC;AAAA,MACd;AAAA,IACF;AAEA,WAAO;AAAA,MACL,UAAU,UAAU,SAAS;AAAA,MAC7B,KAAK,CAAC,EAAE,KAAK,MAAM,GAAG,qBAAqB,OAAO,CAAC,GAAG,IAAI;AAAA,MAC1D,SAAS;AAAA,MACT,OAAO,QAAQ;AAAA,IACjB;AAAA,EACF;AAEA,QAAM,kBAAkB,CAAC,YAA+B;AACtD,UAAM,kBAAkB,wBAAwB,OAAO,KAAK;AAC5D,WAAO,IAAI;AAAA,MACT;AAAA,MACA,eAAe,SAAS,MAAM;AAAA,IAChC;AAAA,EACF;AAEA,QAAM,wBAAwB,CAAC,YAAqC;AAClE,UAAM,kBAAkB,wBAAwB,OAAO,KAAK;AAC5D,WAAO,IAAI;AAAA,MACT;AAAA,MACA,eAAe,SAAS,YAAY;AAAA,IACtC;AAAA,EACF;AAEA,QAAM,WAAW,CAAC,YAA+B,gBAAgB,OAAO;AAExE,WAAS,kBAAkB;AAC3B,WAAS,gBAAgB;AACzB,WAAS,YAAY;AAErB,SAAO;AACT;AAEO,IAAM,SAAS,aAAa;","names":[]}
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 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 'bytedance/seedream-3.0': 'https://api.runpod.ai/v2/seedream-3-0-t2i',\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 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 const 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(', ')}`\n );\n }\n\n return {\n provider: `runpod.${modelType}`,\n url: ({ path }) => `${withoutTrailingSlash(baseURL)}${path}`,\n headers: getHeaders,\n fetch: options.fetch,\n };\n };\n\n const createChatModel = (modelId: RunPodChatModelId) => {\n const openaiModelName = MODEL_ID_TO_OPENAI_NAME[modelId] || modelId;\n return new OpenAICompatibleChatLanguageModel(\n openaiModelName,\n getModelConfig(modelId, 'chat')\n );\n };\n\n const createCompletionModel = (modelId: RunPodCompletionModelId) => {\n const openaiModelName = MODEL_ID_TO_OPENAI_NAME[modelId] || modelId;\n return new OpenAICompatibleCompletionLanguageModel(\n openaiModelName,\n getModelConfig(modelId, 'completion')\n );\n };\n\n const createImageModel = (modelId: RunpodImageModelId) => {\n const 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(', ')}`\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 '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":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@runpod/ai-sdk-provider",
3
- "version": "0.1.1",
3
+ "version": "0.2.1",
4
4
  "license": "Apache-2.0",
5
5
  "sideEffects": false,
6
6
  "main": "./dist/index.js",