@runpod/ai-sdk-provider 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @runpod/ai-sdk-provider
2
2
 
3
+ ## 0.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - ef53393: use consistent brandname "Runpod"
8
+
3
9
  ## 0.2.1
4
10
 
5
11
  ### Patch Changes
package/README.md CHANGED
@@ -1,8 +1,10 @@
1
1
  # Runpod AI SDK Provider
2
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.
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. Runpod is a foundational platform for developers to build, deploy, and scale custom AI systems.
4
4
 
5
- ## Installation
5
+ ## Setup
6
+
7
+ The Runpod provider is available in the `@runpod/ai-sdk-provider` module. You can install it with:
6
8
 
7
9
  ```bash
8
10
  # npm
@@ -13,50 +15,61 @@ pnpm add @runpod/ai-sdk-provider
13
15
 
14
16
  # yarn
15
17
  yarn add @runpod/ai-sdk-provider
18
+
19
+ # bun
20
+ bun add @runpod/ai-sdk-provider
16
21
  ```
17
22
 
18
- ## Setup
23
+ ## Provider Instance
19
24
 
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".
25
+ You can import the default provider instance `runpod` from `@runpod/ai-sdk-provider`:
21
26
 
22
- ### Environment Variable
27
+ ```ts
28
+ import { runpod } from '@runpod/ai-sdk-provider';
29
+ ```
23
30
 
24
- Set your API key as an environment variable:
31
+ If you need a customized setup, you can import `createRunpod` and create a provider instance with your settings:
25
32
 
26
- ```bash
27
- export RUNPOD_API_KEY="your-api-key-here"
33
+ ```ts
34
+ import { createRunpod } from '@runpod/ai-sdk-provider';
35
+
36
+ const runpod = createRunpod({
37
+ apiKey: 'your-api-key', // optional, defaults to RUNPOD_API_KEY environment variable
38
+ baseURL: 'custom-url', // optional, for custom endpoints
39
+ headers: {
40
+ /* custom headers */
41
+ }, // optional
42
+ });
28
43
  ```
29
44
 
30
- ### Provider Instance
45
+ You can use the following optional settings to customize the Runpod provider instance:
31
46
 
32
- Import the provider:
47
+ - **baseURL** _string_
33
48
 
34
- ```ts
35
- import { runpod } from '@runpod/ai-sdk-provider';
36
- ```
49
+ Use a different URL prefix for API calls, e.g. to use proxy servers or custom endpoints.
50
+ Supports vLLM deployments, SGLang servers, and any OpenAI-compatible API.
51
+ The default prefix is `https://api.runpod.ai/v2`.
37
52
 
38
- ## Supported Models
53
+ - **apiKey** _string_
39
54
 
40
- ### Language Models
55
+ API key that is being sent using the `Authorization` header.
56
+ It defaults to the `RUNPOD_API_KEY` environment variable.
41
57
 
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 |
58
+ - **headers** _Record<string,string>_
46
59
 
47
- ### Image Models
60
+ Custom headers to include in the requests.
48
61
 
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 |
62
+ - **fetch** _(input: RequestInfo, init?: RequestInit) => Promise<Response>_
56
63
 
57
- ## Text Generation
64
+ Custom [fetch](https://developer.mozilla.org/en-US/docs/Web/API/fetch) implementation.
65
+ You can use it as a middleware to intercept requests,
66
+ or to provide a custom fetch implementation for e.g. testing.
58
67
 
59
- ### Basic Usage
68
+ You can obtain your Runpod API key from the [Runpod Console](https://console.runpod.io/user/settings) under "API Keys".
69
+
70
+ ## Language Models
71
+
72
+ You can create language models using the provider instance. The first argument is the model ID:
60
73
 
61
74
  ```ts
62
75
  import { runpod } from '@runpod/ai-sdk-provider';
@@ -74,6 +87,17 @@ const { text } = await generateText({
74
87
  - `finishReason` - Why generation stopped ('stop', 'length', etc.)
75
88
  - `usage` - Token usage information (prompt, completion, total tokens)
76
89
 
90
+ Runpod language models can also be used in the `streamText` function (see [AI SDK Core](/docs/ai-sdk-core)).
91
+
92
+ **Note**: Streaming is not yet supported by Runpod's public endpoints. The team is working on implementing this feature.
93
+
94
+ ### Model Capabilities
95
+
96
+ | Model ID | Description | Object Generation | Tool Usage |
97
+ | -------------------------------------- | ------------------------------------------------------------------- | ----------------- | ---------- |
98
+ | `deep-cogito/deep-cogito-v2-llama-70b` | 70B parameter general-purpose LLM with advanced reasoning | ✅ | ✅ |
99
+ | `qwen/qwen3-32b-awq` | 32B parameter multilingual model with strong reasoning capabilities | ✅ | ✅ |
100
+
77
101
  ### Chat Conversations
78
102
 
79
103
  ```ts
@@ -138,11 +162,10 @@ const { object } = await generateObject({
138
162
  - `object` - Parsed object matching your schema
139
163
  - `usage` - Token usage information
140
164
 
141
- ### Streaming
142
-
143
- **Note**: Streaming is not yet supported by Runpod's public endpoints. The team is working on implementing this feature.
165
+ ## Image Models
144
166
 
145
- ## Image Generation
167
+ You can create Runpod image models using the `.imageModel()` factory method.
168
+ For more on image generation with the AI SDK see [generateImage()](/docs/reference/ai-sdk-core/generate-image).
146
169
 
147
170
  ### Basic Usage
148
171
 
@@ -152,9 +175,13 @@ import { experimental_generateImage as generateImage } from 'ai';
152
175
 
153
176
  const { image } = await generateImage({
154
177
  model: runpod.imageModel('qwen/qwen-image'),
155
- prompt: 'A fashion-forward woman in Paris wearing a trench coat',
178
+ prompt: 'A serene mountain landscape at sunset',
156
179
  aspectRatio: '4:3',
157
180
  });
181
+
182
+ // Save to filesystem
183
+ import { writeFileSync } from 'fs';
184
+ writeFileSync('landscape.jpg', image.uint8Array);
158
185
  ```
159
186
 
160
187
  **Returns:**
@@ -164,6 +191,18 @@ const { image } = await generateImage({
164
191
  - `image.mediaType` - MIME type ('image/jpeg' or 'image/png')
165
192
  - `warnings` - Array of any warnings about unsupported parameters
166
193
 
194
+ ### Model Capabilities
195
+
196
+ | Model ID | Description | Supported Aspect Ratios |
197
+ | -------------------------------------- | ------------------------------- | ----------------------- |
198
+ | `qwen/qwen-image` | Text-to-image generation | 1:1, 4:3, 3:4 |
199
+ | `bytedance/seedream-3.0` | Advanced text-to-image model | 1:1, 4:3, 3:4 |
200
+ | `black-forest-labs/flux-1-schnell` | Fast image generation (4 steps) | 1:1, 4:3, 3:4 |
201
+ | `black-forest-labs/flux-1-dev` | High-quality image generation | 1:1, 4:3, 3:4 |
202
+ | `black-forest-labs/flux-1-kontext-dev` | Context-aware image generation | 1:1, 4:3, 3:4 |
203
+
204
+ **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.
205
+
167
206
  ### Advanced Parameters
168
207
 
169
208
  ```ts
@@ -179,36 +218,32 @@ const { image } = await generateImage({
179
218
  },
180
219
  },
181
220
  });
182
-
183
- // Save to filesystem
184
- import { writeFileSync } from 'fs';
185
- writeFileSync('generated-image.jpg', image.uint8Array);
186
221
  ```
187
222
 
188
- ### Context-Aware Generation (Flux Kontext)
223
+ #### Modify Image
224
+
225
+ Transform existing images using text prompts.
189
226
 
190
227
  ```ts
228
+ // Example: Transform existing image
191
229
  const { image } = await generateImage({
192
230
  model: runpod.imageModel('black-forest-labs/flux-1-kontext-dev'),
193
231
  prompt: 'Transform this into a cyberpunk style with neon lights',
194
232
  aspectRatio: '1:1',
195
233
  providerOptions: {
196
234
  runpod: {
197
- image: 'https://example.com/input-image.jpg', // Image URL
198
- negative_prompt: 'blurry, distorted',
235
+ image: 'https://example.com/input-image.jpg',
199
236
  },
200
237
  },
201
238
  });
202
239
 
203
- // Alternative: Using base64 encoded image
240
+ // Example: Using base64 encoded image
204
241
  const { image } = await generateImage({
205
242
  model: runpod.imageModel('black-forest-labs/flux-1-kontext-dev'),
206
243
  prompt: 'Make this image look like a painting',
207
- aspectRatio: '4:3',
208
244
  providerOptions: {
209
245
  runpod: {
210
- image: 'data:image/png;base64,iVBORw0KGgoAAAANS...', // Base64 data URI
211
- negative_prompt: 'blurry, distorted',
246
+ image: 'data:image/png;base64,iVBORw0KGgoAAAANS...',
212
247
  },
213
248
  },
214
249
  });
@@ -254,6 +289,8 @@ const { image } = await generateImage({
254
289
 
255
290
  ### Provider Options
256
291
 
292
+ Runpod image models support flexible provider options through the `providerOptions.runpod` object:
293
+
257
294
  | Option | Type | Default | Description |
258
295
  | ----------------------- | --------- | ------- | ----------------------------------------------------------------------- |
259
296
  | `negative_prompt` | `string` | `""` | Text describing what you don't want in the image |
@@ -265,7 +302,23 @@ const { image } = await generateImage({
265
302
  | `maxPollAttempts` | `number` | `60` | Maximum polling attempts for async generation |
266
303
  | `pollIntervalMillis` | `number` | `5000` | Polling interval in milliseconds (5 seconds) |
267
304
 
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.
305
+ ## Advanced Features
306
+
307
+ Runpod offers several advanced features to enhance your AI applications:
308
+
309
+ 1. **Multiple Model Families**: Access to both language models (LLMs) and cutting-edge image generation models.
310
+
311
+ 2. **OpenAI Compatibility**: Language models support full OpenAI API features including function calling and structured output.
312
+
313
+ 3. **Custom Endpoint Support**: Use with vLLM, SGLang, or any OpenAI-compatible server.
314
+
315
+ 4. **Advanced Image Controls**: Fine-tune image generation with parameters like inference steps, guidance scale, and output format.
316
+
317
+ 5. **Context-Aware Generation**: Transform existing images with Flux Kontext models using URL or base64 inputs.
318
+
319
+ 6. **Automatic Polling**: Seamless handling of both synchronous and asynchronous image generation.
320
+
321
+ 7. **Strict Validation**: Clear error messages for unsupported parameters to prevent confusion.
269
322
 
270
323
  ## Links
271
324
 
package/dist/index.d.mts CHANGED
@@ -1,16 +1,16 @@
1
1
  import { LanguageModelV2, ImageModelV2 } from '@ai-sdk/provider';
2
2
  import { FetchFunction } from '@ai-sdk/provider-utils';
3
- export { OpenAICompatibleErrorData as RunPodErrorData } from '@ai-sdk/openai-compatible';
3
+ export { OpenAICompatibleErrorData as RunpodErrorData } from '@ai-sdk/openai-compatible';
4
4
 
5
- type RunPodChatModelId = 'deep-cogito/deep-cogito-v2-llama-70b' | 'qwen/qwen3-32b-awq' | (string & {});
5
+ type RunpodChatModelId = 'deep-cogito/deep-cogito-v2-llama-70b' | 'qwen/qwen3-32b-awq' | (string & {});
6
6
 
7
- type RunPodCompletionModelId = 'deep-cogito/deep-cogito-v2-llama-70b' | 'qwen/qwen3-32b-awq' | (string & {});
7
+ type RunpodCompletionModelId = 'deep-cogito/deep-cogito-v2-llama-70b' | 'qwen/qwen3-32b-awq' | (string & {});
8
8
 
9
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
10
 
11
- interface RunPodProviderSettings {
11
+ interface RunpodProviderSettings {
12
12
  /**
13
- RunPod API key.
13
+ Runpod API key.
14
14
  */
15
15
  apiKey?: string;
16
16
  /**
@@ -23,29 +23,29 @@ interface RunPodProviderSettings {
23
23
  */
24
24
  fetch?: FetchFunction;
25
25
  }
26
- interface RunPodProvider {
26
+ interface RunpodProvider {
27
27
  /**
28
28
  Creates a model for text generation.
29
29
  */
30
- (modelId: RunPodChatModelId): LanguageModelV2;
30
+ (modelId: RunpodChatModelId): LanguageModelV2;
31
31
  /**
32
32
  Creates a chat model for text generation.
33
33
  */
34
- chatModel(modelId: RunPodChatModelId): LanguageModelV2;
34
+ chatModel(modelId: RunpodChatModelId): LanguageModelV2;
35
35
  /**
36
36
  Creates a chat model for text generation.
37
37
  */
38
- languageModel(modelId: RunPodChatModelId): LanguageModelV2;
38
+ languageModel(modelId: RunpodChatModelId): LanguageModelV2;
39
39
  /**
40
40
  Creates a completion model for text generation.
41
41
  */
42
- completionModel(modelId: RunPodCompletionModelId): LanguageModelV2;
42
+ completionModel(modelId: RunpodCompletionModelId): LanguageModelV2;
43
43
  /**
44
44
  Creates an image model for image generation.
45
45
  */
46
46
  imageModel(modelId: RunpodImageModelId): ImageModelV2;
47
47
  }
48
- declare function createRunPod(options?: RunPodProviderSettings): RunPodProvider;
49
- declare const runpod: RunPodProvider;
48
+ declare function createRunpod(options?: RunpodProviderSettings): RunpodProvider;
49
+ declare const runpod: RunpodProvider;
50
50
 
51
- export { type RunPodChatModelId, type RunPodCompletionModelId, type RunPodProvider, type RunPodProviderSettings, type RunpodImageModelId, createRunPod, runpod };
51
+ export { type RunpodChatModelId, type RunpodCompletionModelId, type RunpodImageModelId, type RunpodProvider, type RunpodProviderSettings, createRunpod, runpod };
package/dist/index.d.ts CHANGED
@@ -1,16 +1,16 @@
1
1
  import { LanguageModelV2, ImageModelV2 } from '@ai-sdk/provider';
2
2
  import { FetchFunction } from '@ai-sdk/provider-utils';
3
- export { OpenAICompatibleErrorData as RunPodErrorData } from '@ai-sdk/openai-compatible';
3
+ export { OpenAICompatibleErrorData as RunpodErrorData } from '@ai-sdk/openai-compatible';
4
4
 
5
- type RunPodChatModelId = 'deep-cogito/deep-cogito-v2-llama-70b' | 'qwen/qwen3-32b-awq' | (string & {});
5
+ type RunpodChatModelId = 'deep-cogito/deep-cogito-v2-llama-70b' | 'qwen/qwen3-32b-awq' | (string & {});
6
6
 
7
- type RunPodCompletionModelId = 'deep-cogito/deep-cogito-v2-llama-70b' | 'qwen/qwen3-32b-awq' | (string & {});
7
+ type RunpodCompletionModelId = 'deep-cogito/deep-cogito-v2-llama-70b' | 'qwen/qwen3-32b-awq' | (string & {});
8
8
 
9
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
10
 
11
- interface RunPodProviderSettings {
11
+ interface RunpodProviderSettings {
12
12
  /**
13
- RunPod API key.
13
+ Runpod API key.
14
14
  */
15
15
  apiKey?: string;
16
16
  /**
@@ -23,29 +23,29 @@ interface RunPodProviderSettings {
23
23
  */
24
24
  fetch?: FetchFunction;
25
25
  }
26
- interface RunPodProvider {
26
+ interface RunpodProvider {
27
27
  /**
28
28
  Creates a model for text generation.
29
29
  */
30
- (modelId: RunPodChatModelId): LanguageModelV2;
30
+ (modelId: RunpodChatModelId): LanguageModelV2;
31
31
  /**
32
32
  Creates a chat model for text generation.
33
33
  */
34
- chatModel(modelId: RunPodChatModelId): LanguageModelV2;
34
+ chatModel(modelId: RunpodChatModelId): LanguageModelV2;
35
35
  /**
36
36
  Creates a chat model for text generation.
37
37
  */
38
- languageModel(modelId: RunPodChatModelId): LanguageModelV2;
38
+ languageModel(modelId: RunpodChatModelId): LanguageModelV2;
39
39
  /**
40
40
  Creates a completion model for text generation.
41
41
  */
42
- completionModel(modelId: RunPodCompletionModelId): LanguageModelV2;
42
+ completionModel(modelId: RunpodCompletionModelId): LanguageModelV2;
43
43
  /**
44
44
  Creates an image model for image generation.
45
45
  */
46
46
  imageModel(modelId: RunpodImageModelId): ImageModelV2;
47
47
  }
48
- declare function createRunPod(options?: RunPodProviderSettings): RunPodProvider;
49
- declare const runpod: RunPodProvider;
48
+ declare function createRunpod(options?: RunpodProviderSettings): RunpodProvider;
49
+ declare const runpod: RunpodProvider;
50
50
 
51
- export { type RunPodChatModelId, type RunPodCompletionModelId, type RunPodProvider, type RunPodProviderSettings, type RunpodImageModelId, createRunPod, runpod };
51
+ export { type RunpodChatModelId, type RunpodCompletionModelId, type RunpodImageModelId, type RunpodProvider, type RunpodProviderSettings, createRunpod, runpod };
package/dist/index.js CHANGED
@@ -20,7 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
- createRunPod: () => createRunPod,
23
+ createRunpod: () => createRunpod,
24
24
  runpod: () => runpod
25
25
  });
26
26
  module.exports = __toCommonJS(index_exports);
@@ -325,12 +325,12 @@ var MODEL_ID_TO_OPENAI_NAME = {
325
325
  "deep-cogito/deep-cogito-v2-llama-70b": "deepcogito/cogito-v2-preview-llama-70B",
326
326
  "qwen/qwen3-32b-awq": "Qwen/Qwen3-32B-AWQ"
327
327
  };
328
- function createRunPod(options = {}) {
328
+ function createRunpod(options = {}) {
329
329
  const getHeaders = () => ({
330
330
  Authorization: `Bearer ${(0, import_provider_utils2.loadApiKey)({
331
331
  apiKey: options.apiKey,
332
332
  environmentVariableName: "RUNPOD_API_KEY",
333
- description: "RunPod"
333
+ description: "Runpod"
334
334
  })}`,
335
335
  ...options.headers
336
336
  });
@@ -338,7 +338,7 @@ function createRunPod(options = {}) {
338
338
  const baseURL = MODEL_ID_TO_ENDPOINT_URL[modelId];
339
339
  if (!baseURL) {
340
340
  throw new Error(
341
- `Unsupported RunPod model: ${modelId}. Supported models: ${Object.keys(
341
+ `Unsupported Runpod model: ${modelId}. Supported models: ${Object.keys(
342
342
  MODEL_ID_TO_ENDPOINT_URL
343
343
  ).join(", ")}`
344
344
  );
@@ -387,10 +387,10 @@ function createRunPod(options = {}) {
387
387
  provider.imageModel = createImageModel;
388
388
  return provider;
389
389
  }
390
- var runpod = createRunPod();
390
+ var runpod = createRunpod();
391
391
  // Annotate the CommonJS export names for ESM import in node:
392
392
  0 && (module.exports = {
393
- createRunPod,
393
+ createRunpod,
394
394
  runpod
395
395
  });
396
396
  //# sourceMappingURL=index.js.map
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 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"]}
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":"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","names":["import_provider_utils"]}
package/dist/index.mjs CHANGED
@@ -311,12 +311,12 @@ var MODEL_ID_TO_OPENAI_NAME = {
311
311
  "deep-cogito/deep-cogito-v2-llama-70b": "deepcogito/cogito-v2-preview-llama-70B",
312
312
  "qwen/qwen3-32b-awq": "Qwen/Qwen3-32B-AWQ"
313
313
  };
314
- function createRunPod(options = {}) {
314
+ function createRunpod(options = {}) {
315
315
  const getHeaders = () => ({
316
316
  Authorization: `Bearer ${loadApiKey({
317
317
  apiKey: options.apiKey,
318
318
  environmentVariableName: "RUNPOD_API_KEY",
319
- description: "RunPod"
319
+ description: "Runpod"
320
320
  })}`,
321
321
  ...options.headers
322
322
  });
@@ -324,7 +324,7 @@ function createRunPod(options = {}) {
324
324
  const baseURL = MODEL_ID_TO_ENDPOINT_URL[modelId];
325
325
  if (!baseURL) {
326
326
  throw new Error(
327
- `Unsupported RunPod model: ${modelId}. Supported models: ${Object.keys(
327
+ `Unsupported Runpod model: ${modelId}. Supported models: ${Object.keys(
328
328
  MODEL_ID_TO_ENDPOINT_URL
329
329
  ).join(", ")}`
330
330
  );
@@ -373,9 +373,9 @@ function createRunPod(options = {}) {
373
373
  provider.imageModel = createImageModel;
374
374
  return provider;
375
375
  }
376
- var runpod = createRunPod();
376
+ var runpod = createRunpod();
377
377
  export {
378
- createRunPod,
378
+ createRunpod,
379
379
  runpod
380
380
  };
381
381
  //# sourceMappingURL=index.mjs.map
@@ -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 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":[]}
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.2.1",
3
+ "version": "0.3.0",
4
4
  "license": "Apache-2.0",
5
5
  "sideEffects": false,
6
6
  "main": "./dist/index.js",
@@ -19,9 +19,9 @@
19
19
  }
20
20
  },
21
21
  "dependencies": {
22
- "@ai-sdk/openai-compatible": "^1.0.7",
22
+ "@ai-sdk/openai-compatible": "^1.0.10",
23
23
  "@ai-sdk/provider": "^2.0.0",
24
- "@ai-sdk/provider-utils": "^3.0.0"
24
+ "@ai-sdk/provider-utils": "^3.0.4"
25
25
  },
26
26
  "devDependencies": {
27
27
  "@changesets/cli": "^2.29.6",