@runpod/ai-sdk-provider 0.11.1 → 0.12.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,18 @@
1
1
  # @runpod/ai-sdk-provider
2
2
 
3
+ ## 0.12.0
4
+
5
+ ### Minor Changes
6
+
7
+ - dcc2cc5: Add support for speech generation with `resembleai/chatterbox-turbo` model:
8
+ - `speechModel()` and `speech()` methods for text-to-speech
9
+ - Voice cloning via URL (5-10 seconds of audio)
10
+ - 20 built-in voices
11
+
12
+ ### Patch Changes
13
+
14
+ - ace58c2: Add comprehensive documentation for Pruna and Nano Banana Pro models, including all supported aspect ratios, resolutions, and output formats. Update examples to use standard AI SDK options where possible.
15
+
3
16
  ## 0.11.1
4
17
 
5
18
  ### Patch Changes
package/README.md CHANGED
@@ -224,24 +224,69 @@ writeFileSync('landscape.jpg', image.uint8Array);
224
224
 
225
225
  ### Model Capabilities
226
226
 
227
- | Model ID | Description | Supported Aspect Ratios |
228
- | -------------------------------------- | ------------------------------- | ------------------------------------- |
229
- | `bytedance/seedream-3.0` | Advanced text-to-image model | 1:1, 4:3, 3:4 |
230
- | `bytedance/seedream-4.0` | Text-to-image (v4) | 1:1 (supports 1024, 2048, 4096) |
231
- | `bytedance/seedream-4.0-edit` | Image editing (v4, multi-image) | 1:1 (supports 1024, 1536, 2048, 4096) |
232
- | `black-forest-labs/flux-1-schnell` | Fast image generation (4 steps) | 1:1, 4:3, 3:4 |
233
- | `black-forest-labs/flux-1-dev` | High-quality image generation | 1:1, 4:3, 3:4 |
234
- | `black-forest-labs/flux-1-kontext-dev` | Context-aware image generation | 1:1, 4:3, 3:4 |
235
- | `qwen/qwen-image` | Text-to-image generation | 1:1, 4:3, 3:4 |
236
- | `qwen/qwen-image-edit` | Image editing (prompt-guided) | 1:1, 4:3, 3:4 |
237
- | `nano-banana-edit` | Image editing (multi-image) | 1:1, 4:3, 3:4 |
238
- | `google/nano-banana-pro-edit` | Image editing (Gemini-powered) | Uses resolution param (1k, 2k) |
239
- | `pruna/p-image-t2i` | Pruna text-to-image | 1:1, 16:9, 9:16, 4:3, 3:4, etc. |
240
- | `pruna/p-image-edit` | Pruna image editing | match_input_image, 1:1, 16:9, etc. |
241
-
242
- **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.
227
+ | Model ID | Type |
228
+ | -------------------------------------- | ---- |
229
+ | `bytedance/seedream-3.0` | t2i |
230
+ | `bytedance/seedream-4.0` | t2i |
231
+ | `bytedance/seedream-4.0-edit` | edit |
232
+ | `black-forest-labs/flux-1-schnell` | t2i |
233
+ | `black-forest-labs/flux-1-dev` | t2i |
234
+ | `black-forest-labs/flux-1-kontext-dev` | edit |
235
+ | `qwen/qwen-image` | t2i |
236
+ | `qwen/qwen-image-edit` | edit |
237
+ | `nano-banana-edit` | edit |
238
+ | `google/nano-banana-pro-edit` | edit |
239
+ | `pruna/p-image-t2i` | t2i |
240
+ | `pruna/p-image-edit` | edit |
241
+
242
+ For the full list of models, see the [Runpod Public Endpoint Reference](https://docs.runpod.io/hub/public-endpoint-reference).
243
+
244
+ ### Pruna Models
245
+
246
+ Supported models: `pruna/p-image-t2i`, `pruna/p-image-edit`
247
+
248
+ | Parameter | Supported Values | Notes |
249
+ | :---------------------------------------- | :------------------------------------------------ | :---------------------------------------------------- |
250
+ | `aspectRatio` | `1:1`, `16:9`, `9:16`, `4:3`, `3:4`, `3:2`, `2:3` | Standard AI SDK parameter |
251
+ | `aspectRatio` (t2i only) | `custom` | Requires `width` & `height` in providerOptions |
252
+ | `providerOptions.runpod.width` / `height` | `256` - `1440` | Custom dimensions (t2i only). Must be multiple of 16. |
253
+ | `providerOptions.runpod.images` | `string[]` | Required for `p-image-edit`. Supports 1-5 images. |
254
+
255
+ **Example: Custom Resolution (t2i)**
243
256
 
244
- **Note:** This list is not complete. For a full list of all available models, see the [Runpod Public Endpoint Reference](https://docs.runpod.io/hub/public-endpoint-reference).
257
+ ```ts
258
+ const { image } = await generateImage({
259
+ model: runpod.imageModel('pruna/p-image-t2i'),
260
+ prompt: 'A robot',
261
+ providerOptions: {
262
+ runpod: {
263
+ aspect_ratio: 'custom',
264
+ width: 512,
265
+ height: 768,
266
+ },
267
+ },
268
+ });
269
+ ```
270
+
271
+ ### Google Models
272
+
273
+ #### Nano Banana Pro
274
+
275
+ Supported model: `google/nano-banana-pro-edit`
276
+
277
+ | Parameter | Supported Values | Notes |
278
+ | :------------------------------ | :---------------------------------------------------------------- | :-------------------------------- |
279
+ | `aspectRatio` | `1:1`, `16:9`, `9:16`, `4:3`, `3:4`, `3:2`, `2:3`, `21:9`, `9:21` | Standard AI SDK parameter |
280
+ | `resolution` | `1k`, `2k`, `4k` | Output resolution quality |
281
+ | `output_format` | `jpeg`, `png`, `webp` | Output image format |
282
+ | `providerOptions.runpod.images` | `string[]` | Required. Input image(s) to edit. |
283
+
284
+ ### Other Models
285
+
286
+ Most other models (Flux, Seedream, Qwen, etc.) support standard `1:1`, `4:3`, and `3:4` aspect ratios.
287
+
288
+ - **Flux models**: Support `num_inference_steps` and `guidance` settings.
289
+ - **Edit models**: Require an input image via `providerOptions.runpod.image` (single) or `images` (multiple).
245
290
 
246
291
  ### Advanced Parameters
247
292
 
@@ -352,24 +397,122 @@ const { image } = await generateImage({
352
397
 
353
398
  ### Provider Options
354
399
 
355
- Runpod image models support flexible provider options through the `providerOptions.runpod` object:
356
-
357
- | Option | Type | Default | Description |
358
- | ------------------------ | ---------- | ------- | ------------------------------------------------------------------------ |
359
- | `negative_prompt` | `string` | `""` | Text describing what you don't want in the image |
360
- | `enable_safety_checker` | `boolean` | `true` | Enable content safety filtering |
361
- | `disable_safety_checker` | `boolean` | `false` | Disable safety checker (Pruna models) |
362
- | `image` | `string` | - | Single input image: URL or base64 data URI (Flux Kontext) |
363
- | `images` | `string[]` | - | Multiple input images (e.g., for `nano-banana-edit` multi-image editing) |
364
- | `aspect_ratio` | `string` | `"1:1"` | Aspect ratio string (Pruna: "16:9", "match_input_image", etc.) |
365
- | `resolution` | `string` | `"1k"` | Output resolution (Nano Banana Pro: "1k", "2k") |
366
- | `num_inference_steps` | `number` | Auto | Number of denoising steps (Flux: 4 for schnell, 28 for others) |
367
- | `guidance` | `number` | Auto | Guidance scale for prompt adherence (Flux: 7 for schnell, 2 for others) |
368
- | `output_format` | `string` | `"png"` | Output image format ("png", "jpg", or "jpeg") |
369
- | `enable_base64_output` | `boolean` | `false` | Return base64 instead of URL (Nano Banana Pro) |
370
- | `enable_sync_mode` | `boolean` | `false` | Enable synchronous mode (some models) |
371
- | `maxPollAttempts` | `number` | `60` | Maximum polling attempts for async generation |
372
- | `pollIntervalMillis` | `number` | `5000` | Polling interval in milliseconds (5 seconds) |
400
+ Use `providerOptions.runpod` for model-specific parameters:
401
+
402
+ | Option | Type | Default | Description |
403
+ | ------------------------ | ---------- | ------- | ----------------------------------------------- |
404
+ | `negative_prompt` | `string` | `""` | What to avoid in the image |
405
+ | `enable_safety_checker` | `boolean` | `true` | Content safety filtering |
406
+ | `disable_safety_checker` | `boolean` | `false` | Disable safety checker (Pruna) |
407
+ | `image` | `string` | - | Input image URL or base64 (Flux Kontext) |
408
+ | `images` | `string[]` | - | Multiple input images (edit models) |
409
+ | `resolution` | `string` | `"1k"` | Output resolution: 1k, 2k, 4k (Nano Banana Pro) |
410
+ | `width` / `height` | `number` | - | Custom dimensions (Pruna t2i, 256-1440) |
411
+ | `num_inference_steps` | `number` | Auto | Denoising steps |
412
+ | `guidance` | `number` | Auto | Prompt adherence strength |
413
+ | `output_format` | `string` | `"png"` | Output format: png, jpg, jpeg, webp |
414
+ | `maxPollAttempts` | `number` | `60` | Max polling attempts |
415
+ | `pollIntervalMillis` | `number` | `5000` | Polling interval (ms) |
416
+
417
+ ## Speech
418
+
419
+ You can generate speech using the AI SDK's `experimental_generateSpeech` and a Runpod speech model created via `runpod.speechModel()` (or the shorthand `runpod.speech()`).
420
+
421
+ ### Basic Usage
422
+
423
+ ```ts
424
+ import { runpod } from '@runpod/ai-sdk-provider';
425
+ import { experimental_generateSpeech as generateSpeech } from 'ai';
426
+
427
+ const result = await generateSpeech({
428
+ model: runpod.speechModel('resembleai/chatterbox-turbo'),
429
+ text: 'Hello, this is Chatterbox Turbo running on Runpod.',
430
+ voice: 'lucy',
431
+ });
432
+
433
+ // Save to filesystem:
434
+ import { writeFileSync } from 'fs';
435
+ writeFileSync('speech.wav', result.audio.uint8Array);
436
+ ```
437
+
438
+ **Returns:**
439
+
440
+ - `result.audio.uint8Array` - Binary audio data (efficient for processing/saving)
441
+ - `result.audio.base64` - Base64 encoded audio (useful for web embedding)
442
+ - `result.audio.mediaType` - MIME type (e.g. `audio/wav`)
443
+ - `result.audio.format` - Format (e.g. `wav`)
444
+ - `result.warnings` - Array of any warnings about unsupported parameters
445
+ - `result.providerMetadata.runpod.audioUrl` - Public URL to the generated audio
446
+ - `result.providerMetadata.runpod.cost` - Cost information (if available)
447
+
448
+ ### Supported Models
449
+
450
+ Supported model: `resembleai/chatterbox-turbo`
451
+
452
+ ### Parameters
453
+
454
+ | Parameter | Type | Default | Description |
455
+ | --------- | -------- | -------- | ---------------------------------------- |
456
+ | `text` | `string` | - | Required. The text to convert to speech. |
457
+ | `voice` | `string` | `"lucy"` | Built-in voice name (see list below). |
458
+
459
+ ### Provider Options
460
+
461
+ Use `providerOptions.runpod` for model-specific parameters:
462
+
463
+ | Option | Type | Default | Description |
464
+ | ----------- | -------- | ------- | ------------------------------------------- |
465
+ | `voice_url` | `string` | - | URL to audio file (5–10s) for voice cloning |
466
+ | `voiceUrl` | `string` | - | Alias for `voice_url` |
467
+
468
+ > Note: If `voice_url` is provided, the built-in `voice` is ignored.
469
+ >
470
+ > Note: This speech endpoint currently returns WAV only; `outputFormat` is ignored.
471
+
472
+ ### Voices
473
+
474
+ `voice` selects one of the built-in voices (default: `lucy`):
475
+
476
+ ```ts
477
+ [
478
+ 'aaron',
479
+ 'abigail',
480
+ 'anaya',
481
+ 'andy',
482
+ 'archer',
483
+ 'brian',
484
+ 'chloe',
485
+ 'dylan',
486
+ 'emmanuel',
487
+ 'ethan',
488
+ 'evelyn',
489
+ 'gavin',
490
+ 'gordon',
491
+ 'ivan',
492
+ 'laura',
493
+ 'lucy',
494
+ 'madison',
495
+ 'marisol',
496
+ 'meera',
497
+ 'walter',
498
+ ];
499
+ ```
500
+
501
+ ### Voice cloning (via URL)
502
+
503
+ You can provide a `voice_url` (5–10s audio) through `providerOptions.runpod`:
504
+
505
+ ```ts
506
+ const result = await generateSpeech({
507
+ model: runpod.speech('resembleai/chatterbox-turbo'),
508
+ text: 'Hello!',
509
+ providerOptions: {
510
+ runpod: {
511
+ voice_url: 'https://example.com/voice.wav',
512
+ },
513
+ },
514
+ });
515
+ ```
373
516
 
374
517
  ## About Runpod
375
518
 
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { LanguageModelV2, ImageModelV2 } from '@ai-sdk/provider';
1
+ import { LanguageModelV2, ImageModelV2, SpeechModelV2 } from '@ai-sdk/provider';
2
2
  import { FetchFunction } from '@ai-sdk/provider-utils';
3
3
  export { OpenAICompatibleErrorData as RunpodErrorData } from '@ai-sdk/openai-compatible';
4
4
  import { z } from 'zod';
@@ -44,6 +44,14 @@ interface RunpodProvider {
44
44
  Creates an image model for image generation.
45
45
  */
46
46
  imageModel(modelId: string): ImageModelV2;
47
+ /**
48
+ Creates a speech model for speech generation.
49
+ */
50
+ speechModel(modelId: string): SpeechModelV2;
51
+ /**
52
+ Creates a speech model for speech generation.
53
+ */
54
+ speech(modelId: string): SpeechModelV2;
47
55
  }
48
56
  declare function createRunpod(options?: RunpodProviderSettings): RunpodProvider;
49
57
  declare const runpod: RunpodProvider;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { LanguageModelV2, ImageModelV2 } from '@ai-sdk/provider';
1
+ import { LanguageModelV2, ImageModelV2, SpeechModelV2 } from '@ai-sdk/provider';
2
2
  import { FetchFunction } from '@ai-sdk/provider-utils';
3
3
  export { OpenAICompatibleErrorData as RunpodErrorData } from '@ai-sdk/openai-compatible';
4
4
  import { z } from 'zod';
@@ -44,6 +44,14 @@ interface RunpodProvider {
44
44
  Creates an image model for image generation.
45
45
  */
46
46
  imageModel(modelId: string): ImageModelV2;
47
+ /**
48
+ Creates a speech model for speech generation.
49
+ */
50
+ speechModel(modelId: string): SpeechModelV2;
51
+ /**
52
+ Creates a speech model for speech generation.
53
+ */
54
+ speech(modelId: string): SpeechModelV2;
47
55
  }
48
56
  declare function createRunpod(options?: RunpodProviderSettings): RunpodProvider;
49
57
  declare const runpod: RunpodProvider;
package/dist/index.js CHANGED
@@ -27,7 +27,7 @@ module.exports = __toCommonJS(index_exports);
27
27
 
28
28
  // src/runpod-provider.ts
29
29
  var import_openai_compatible = require("@ai-sdk/openai-compatible");
30
- var import_provider_utils3 = require("@ai-sdk/provider-utils");
30
+ var import_provider_utils4 = require("@ai-sdk/provider-utils");
31
31
 
32
32
  // src/runpod-image-model.ts
33
33
  var import_provider_utils2 = require("@ai-sdk/provider-utils");
@@ -307,7 +307,7 @@ var RunpodImageModel = class {
307
307
  if (isPrunaEdit) {
308
308
  const editPayload = {
309
309
  prompt,
310
- aspect_ratio: runpodOptions?.aspect_ratio ?? aspectRatio ?? "match_input_image",
310
+ aspect_ratio: runpodOptions?.aspect_ratio ?? aspectRatio ?? "1:1",
311
311
  disable_safety_checker: runpodOptions?.disable_safety_checker ?? false
312
312
  };
313
313
  if (seed !== void 0) {
@@ -392,6 +392,148 @@ var runpodImageStatusSchema = import_zod2.z.object({
392
392
  // Error message if FAILED
393
393
  });
394
394
 
395
+ // src/runpod-speech-model.ts
396
+ var import_provider_utils3 = require("@ai-sdk/provider-utils");
397
+ function isRecord(value) {
398
+ return typeof value === "object" && value !== null;
399
+ }
400
+ function replaceNewlinesWithSpaces(value) {
401
+ return value.replace(/[\r\n]+/g, " ");
402
+ }
403
+ var RunpodSpeechModel = class {
404
+ constructor(modelId, config) {
405
+ this.modelId = modelId;
406
+ this.config = config;
407
+ this.specificationVersion = "v2";
408
+ }
409
+ get provider() {
410
+ return this.config.provider;
411
+ }
412
+ getRunpodRunSyncUrl() {
413
+ const baseURL = (0, import_provider_utils3.withoutTrailingSlash)(this.config.baseURL) ?? this.config.baseURL;
414
+ if (baseURL.endsWith("/run") || baseURL.endsWith("/runsync")) {
415
+ return baseURL;
416
+ }
417
+ return `${baseURL}/runsync`;
418
+ }
419
+ async doGenerate(options) {
420
+ const currentDate = this.config._internal?.currentDate?.() ?? /* @__PURE__ */ new Date();
421
+ const warnings = [];
422
+ const {
423
+ text,
424
+ voice,
425
+ outputFormat,
426
+ instructions,
427
+ speed,
428
+ language,
429
+ providerOptions,
430
+ abortSignal,
431
+ headers
432
+ } = options;
433
+ if (outputFormat != null && outputFormat !== "wav") {
434
+ warnings.push({
435
+ type: "unsupported-setting",
436
+ setting: "outputFormat",
437
+ details: `Unsupported outputFormat: ${outputFormat}. This endpoint returns 'wav'.`
438
+ });
439
+ }
440
+ if (instructions != null) {
441
+ warnings.push({
442
+ type: "unsupported-setting",
443
+ setting: "instructions",
444
+ details: `Instructions are not supported by this speech endpoint.`
445
+ });
446
+ }
447
+ if (speed != null) {
448
+ warnings.push({
449
+ type: "unsupported-setting",
450
+ setting: "speed",
451
+ details: `Speed is not supported by this speech endpoint.`
452
+ });
453
+ }
454
+ if (language != null) {
455
+ warnings.push({
456
+ type: "unsupported-setting",
457
+ setting: "language",
458
+ details: `Language selection is not supported by this speech endpoint.`
459
+ });
460
+ }
461
+ const runpodProviderOptions = isRecord(providerOptions) ? providerOptions.runpod : void 0;
462
+ const voiceUrl = isRecord(runpodProviderOptions) && (typeof runpodProviderOptions.voice_url === "string" || typeof runpodProviderOptions.voiceUrl === "string") ? runpodProviderOptions.voice_url ?? runpodProviderOptions.voiceUrl ?? void 0 : void 0;
463
+ const input = {
464
+ prompt: replaceNewlinesWithSpaces(text)
465
+ };
466
+ if (voiceUrl) {
467
+ input.voice_url = voiceUrl;
468
+ } else if (voice) {
469
+ input.voice = voice;
470
+ }
471
+ const requestBody = { input };
472
+ const url = this.getRunpodRunSyncUrl();
473
+ const fetchFn = this.config.fetch ?? fetch;
474
+ const requestHeaders = {
475
+ "Content-Type": "application/json",
476
+ ...this.config.headers()
477
+ };
478
+ if (headers) {
479
+ for (const [key, value] of Object.entries(headers)) {
480
+ if (value != null) {
481
+ requestHeaders[key] = value;
482
+ }
483
+ }
484
+ }
485
+ const response = await fetchFn(url, {
486
+ method: "POST",
487
+ headers: requestHeaders,
488
+ body: JSON.stringify(requestBody),
489
+ signal: abortSignal
490
+ });
491
+ const responseHeaders = Object.fromEntries(response.headers.entries());
492
+ const rawBodyText = await response.text();
493
+ let parsed = void 0;
494
+ try {
495
+ parsed = rawBodyText ? JSON.parse(rawBodyText) : void 0;
496
+ } catch {
497
+ }
498
+ if (!response.ok) {
499
+ const message = parsed && typeof parsed.error === "string" && parsed.error || rawBodyText || `HTTP ${response.status}`;
500
+ throw new Error(`Runpod speech request failed: ${message}`);
501
+ }
502
+ const output = parsed?.output ?? parsed;
503
+ const audioUrl = output?.audio_url;
504
+ if (typeof audioUrl !== "string" || audioUrl.length === 0) {
505
+ throw new Error("Runpod speech response did not include an audio_url.");
506
+ }
507
+ const audioResponse = await fetchFn(audioUrl, { signal: abortSignal });
508
+ if (!audioResponse.ok) {
509
+ throw new Error(
510
+ `Failed to download generated audio (${audioResponse.status}).`
511
+ );
512
+ }
513
+ const audio = new Uint8Array(await audioResponse.arrayBuffer());
514
+ const providerMetadata = {
515
+ runpod: {
516
+ audioUrl,
517
+ ...typeof output?.cost === "number" ? { cost: output.cost } : {}
518
+ }
519
+ };
520
+ return {
521
+ audio,
522
+ warnings,
523
+ request: {
524
+ body: JSON.stringify(requestBody)
525
+ },
526
+ response: {
527
+ timestamp: currentDate,
528
+ modelId: this.modelId,
529
+ headers: responseHeaders,
530
+ body: rawBodyText
531
+ },
532
+ providerMetadata
533
+ };
534
+ }
535
+ };
536
+
395
537
  // src/runpod-provider.ts
396
538
  var MODEL_ID_TO_ENDPOINT_URL = {
397
539
  "qwen/qwen3-32b-awq": "https://api.runpod.ai/v2/qwen3-32b-awq/openai/v1",
@@ -419,6 +561,9 @@ var IMAGE_MODEL_ID_TO_ENDPOINT_URL = {
419
561
  "pruna/p-image-t2i": "https://api.runpod.ai/v2/p-image-t2i",
420
562
  "pruna/p-image-edit": "https://api.runpod.ai/v2/p-image-edit"
421
563
  };
564
+ var SPEECH_MODEL_ID_TO_ENDPOINT_URL = {
565
+ "resembleai/chatterbox-turbo": "https://api.runpod.ai/v2/chatterbox-turbo/"
566
+ };
422
567
  var MODEL_ID_TO_OPENAI_NAME = {
423
568
  "qwen/qwen3-32b-awq": "Qwen/Qwen3-32B-AWQ",
424
569
  "deepcogito/cogito-671b-v2.1-fp8": "deepcogito/cogito-671b-v2.1-FP8",
@@ -428,9 +573,26 @@ function deriveEndpointURL(modelId) {
428
573
  const normalized = modelId.replace(/\//g, "-");
429
574
  return `https://api.runpod.ai/v2/${normalized}/openai/v1`;
430
575
  }
576
+ function parseRunpodConsoleEndpointId(modelIdOrUrl) {
577
+ if (!modelIdOrUrl.startsWith("http")) {
578
+ return null;
579
+ }
580
+ try {
581
+ const url = new URL(modelIdOrUrl);
582
+ if (url.hostname !== "console.runpod.io") {
583
+ return null;
584
+ }
585
+ const parts = url.pathname.split("/").filter(Boolean);
586
+ const idx = parts.lastIndexOf("endpoint");
587
+ const endpointId = idx !== -1 ? parts[idx + 1] : void 0;
588
+ return endpointId || null;
589
+ } catch {
590
+ return null;
591
+ }
592
+ }
431
593
  function createRunpod(options = {}) {
432
594
  const getHeaders = () => ({
433
- Authorization: `Bearer ${(0, import_provider_utils3.loadApiKey)({
595
+ Authorization: `Bearer ${(0, import_provider_utils4.loadApiKey)({
434
596
  apiKey: options.apiKey,
435
597
  environmentVariableName: "RUNPOD_API_KEY",
436
598
  description: "Runpod"
@@ -460,7 +622,7 @@ function createRunpod(options = {}) {
460
622
  }
461
623
  return {
462
624
  provider: `runpod.${modelType}`,
463
- url: ({ path }) => `${(0, import_provider_utils3.withoutTrailingSlash)(baseURL)}${path}`,
625
+ url: ({ path }) => `${(0, import_provider_utils4.withoutTrailingSlash)(baseURL)}${path}`,
464
626
  headers: getHeaders,
465
627
  fetch: runpodFetch
466
628
  };
@@ -493,11 +655,25 @@ function createRunpod(options = {}) {
493
655
  fetch: options.fetch
494
656
  });
495
657
  };
658
+ const createSpeechModel = (modelId) => {
659
+ const endpointIdFromConsole = parseRunpodConsoleEndpointId(modelId);
660
+ const normalizedModelId = endpointIdFromConsole ?? modelId;
661
+ const mappedBaseURL = SPEECH_MODEL_ID_TO_ENDPOINT_URL[normalizedModelId];
662
+ const baseURL = mappedBaseURL ?? (normalizedModelId.startsWith("http") ? normalizedModelId : `https://api.runpod.ai/v2/${normalizedModelId}`);
663
+ return new RunpodSpeechModel(normalizedModelId, {
664
+ provider: "runpod.speech",
665
+ baseURL,
666
+ headers: getHeaders,
667
+ fetch: runpodFetch
668
+ });
669
+ };
496
670
  const provider = (modelId) => createChatModel(modelId);
497
671
  provider.completionModel = createCompletionModel;
498
672
  provider.languageModel = createChatModel;
499
673
  provider.chatModel = createChatModel;
500
674
  provider.imageModel = createImageModel;
675
+ provider.speechModel = createSpeechModel;
676
+ provider.speech = createSpeechModel;
501
677
  return provider;
502
678
  }
503
679
  var runpod = createRunpod();
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/runpod-provider.ts","../src/runpod-image-model.ts","../src/runpod-error.ts"],"sourcesContent":["export { createRunpod, runpod } from './runpod-provider';\nexport type { RunpodProvider, RunpodProviderSettings } from './runpod-provider';\nexport type { RunpodChatModelId } from './runpod-chat-options';\nexport type { RunpodCompletionModelId } from './runpod-completion-options';\nexport type { RunpodImageModelId } from './runpod-image-options';\nexport type { OpenAICompatibleErrorData as RunpodErrorData } from '@ai-sdk/openai-compatible';\nexport type { RunpodImageErrorData } from './runpod-error';\n","import { LanguageModelV2, ImageModelV2 } from '@ai-sdk/provider';\nimport {\n OpenAICompatibleChatLanguageModel,\n OpenAICompatibleCompletionLanguageModel,\n} from '@ai-sdk/openai-compatible';\nimport {\n FetchFunction,\n loadApiKey,\n withoutTrailingSlash,\n} from '@ai-sdk/provider-utils';\nimport { RunpodImageModel } from './runpod-image-model';\n\nexport interface RunpodProviderSettings {\n /**\nRunpod API key.\n*/\n apiKey?: string;\n /**\nCustom base URL for Runpod API. Use this to point to custom endpoints or different Runpod deployments.\nExample: 'https://api.runpod.ai/v2/your-endpoint-id/openai/v1'\n*/\n baseURL?: string;\n /**\nCustom headers to include in the requests.\n*/\n headers?: Record<string, string>;\n /**\nCustom fetch implementation. You can use it as a middleware to intercept requests,\nor to provide a custom fetch implementation for e.g. testing.\n*/\n fetch?: FetchFunction;\n}\n\nexport interface RunpodProvider {\n /**\nCreates a model for text generation.\n*/\n (modelId: string): LanguageModelV2;\n\n /**\nCreates a chat model for text generation.\n*/\n chatModel(modelId: string): LanguageModelV2;\n\n /**\nCreates a chat model for text generation.\n*/\n languageModel(modelId: string): LanguageModelV2;\n\n /**\nCreates a completion model for text generation.\n*/\n completionModel(modelId: string): LanguageModelV2;\n\n /**\nCreates an image model for image generation.\n*/\n imageModel(modelId: string): ImageModelV2;\n}\n\n// Mapping of Runpod model IDs to their endpoint URLs\nconst MODEL_ID_TO_ENDPOINT_URL: Record<string, string> = {\n 'qwen/qwen3-32b-awq': 'https://api.runpod.ai/v2/qwen3-32b-awq/openai/v1',\n 'ibm-granite/granite-4.0-h-small': 'https://api.runpod.ai/v2/granite-4-0-h-small/openai/v1',\n 'gpt-oss-120b': 'https://api.runpod.ai/v2/gpt-oss-120b/openai/v1',\n 'openai/gpt-oss-120b': 'https://api.runpod.ai/v2/gpt-oss-120b/openai/v1',\n 'deepcogito/cogito-671b-v2.1-fp8': 'https://api.runpod.ai/v2/cogito-671b-v2-1-fp8-dynamic/openai/v1',\n 'deepcogito/cogito-671b-v2.1-FP8': 'https://api.runpod.ai/v2/cogito-671b-v2-1-fp8-dynamic/openai/v1',\n};\n\n// Mapping of Runpod image model IDs to their endpoint URLs\nconst IMAGE_MODEL_ID_TO_ENDPOINT_URL: Record<string, string> = {\n 'qwen/qwen-image': 'https://api.runpod.ai/v2/qwen-image-t2i',\n 'qwen/qwen-image-edit': 'https://api.runpod.ai/v2/qwen-image-edit',\n 'bytedance/seedream-3.0': 'https://api.runpod.ai/v2/seedream-3-0-t2i',\n // Seadream v4 (t2i and edit)\n 'bytedance/seedream-4.0': 'https://api.runpod.ai/v2/seedream-v4-t2i',\n 'bytedance/seedream-4.0-edit': 'https://api.runpod.ai/v2/seedream-v4-edit',\n 'black-forest-labs/flux-1-kontext-dev':\n 'https://api.runpod.ai/v2/black-forest-labs-flux-1-kontext-dev',\n 'black-forest-labs/flux-1-schnell':\n 'https://api.runpod.ai/v2/black-forest-labs-flux-1-schnell',\n 'black-forest-labs/flux-1-dev':\n 'https://api.runpod.ai/v2/black-forest-labs-flux-1-dev',\n // Nano Banana (edit only)\n 'nano-banana-edit': 'https://api.runpod.ai/v2/nano-banana-edit',\n // Nano Banana Pro (edit only)\n 'google/nano-banana-pro-edit': 'https://api.runpod.ai/v2/nano-banana-pro-edit',\n // Pruna (t2i and edit)\n 'pruna/p-image-t2i': 'https://api.runpod.ai/v2/p-image-t2i',\n 'pruna/p-image-edit': 'https://api.runpod.ai/v2/p-image-edit',\n};\n\n// Mapping of Runpod model IDs to their OpenAI model names\nconst MODEL_ID_TO_OPENAI_NAME: Record<string, string> = {\n 'qwen/qwen3-32b-awq': 'Qwen/Qwen3-32B-AWQ',\n 'deepcogito/cogito-671b-v2.1-fp8': 'deepcogito/cogito-671b-v2.1-FP8',\n 'deepcogito/cogito-671b-v2.1-FP8': 'deepcogito/cogito-671b-v2.1-FP8',\n};\n\n/**\n * Derives the endpoint URL for a model by replacing slashes with hyphens.\n * Example: 'ibm-granite/granite-4.0-h-small' -> 'https://api.runpod.ai/v2/ibm-granite-granite-4.0-h-small/openai/v1'\n */\nfunction deriveEndpointURL(modelId: string): string {\n const normalized = modelId.replace(/\\//g, '-');\n return `https://api.runpod.ai/v2/${normalized}/openai/v1`;\n}\n\nexport function createRunpod(\n options: RunpodProviderSettings = {}\n): RunpodProvider {\n const getHeaders = () => ({\n Authorization: `Bearer ${loadApiKey({\n apiKey: options.apiKey,\n environmentVariableName: 'RUNPOD_API_KEY',\n description: 'Runpod',\n })}`,\n ...options.headers,\n });\n\n const runpodFetch: FetchFunction = async (url, requestInit) => {\n if (requestInit?.body) {\n try {\n const body = JSON.parse(requestInit.body as string);\n if (body.stream === true && !body.stream_options) {\n body.stream_options = { include_usage: true };\n requestInit.body = JSON.stringify(body);\n }\n } catch {}\n }\n const fetchFn = options.fetch || fetch;\n return fetchFn(url, requestInit);\n };\n\n interface CommonModelConfig {\n provider: string;\n url: ({ path }: { path: string }) => string;\n headers: () => Record<string, string>;\n fetch?: FetchFunction;\n }\n\n const getModelConfig = (\n modelId: string,\n modelType: string\n ): CommonModelConfig => {\n let baseURL: string;\n\n if (options.baseURL) {\n baseURL = options.baseURL;\n } else {\n // Use hardcoded mapping if available, otherwise derive endpoint\n baseURL = MODEL_ID_TO_ENDPOINT_URL[modelId] || deriveEndpointURL(modelId);\n }\n\n return {\n provider: `runpod.${modelType}`,\n url: ({ path }) => `${withoutTrailingSlash(baseURL)}${path}`,\n headers: getHeaders,\n fetch: runpodFetch,\n };\n };\n\n const createChatModel = (modelId: string) => {\n const openaiModelName = MODEL_ID_TO_OPENAI_NAME[modelId] || modelId;\n return new OpenAICompatibleChatLanguageModel(openaiModelName, {\n ...getModelConfig(modelId, 'chat'),\n includeUsage: true,\n });\n };\n\n const createCompletionModel = (modelId: string) => {\n const openaiModelName = MODEL_ID_TO_OPENAI_NAME[modelId] || modelId;\n return new OpenAICompatibleCompletionLanguageModel(openaiModelName, {\n ...getModelConfig(modelId, 'completion'),\n includeUsage: true,\n });\n };\n\n const createImageModel = (modelId: string) => {\n let baseURL: string;\n\n if (options.baseURL) {\n baseURL = options.baseURL;\n } else {\n // Use hardcoded mapping if available, otherwise derive endpoint\n baseURL =\n IMAGE_MODEL_ID_TO_ENDPOINT_URL[modelId] || deriveEndpointURL(modelId);\n }\n\n return new RunpodImageModel(modelId, {\n provider: 'runpod.image',\n baseURL,\n headers: getHeaders,\n fetch: options.fetch,\n });\n };\n\n const provider = (modelId: string) => createChatModel(modelId);\n\n provider.completionModel = createCompletionModel;\n provider.languageModel = createChatModel;\n provider.chatModel = createChatModel;\n provider.imageModel = createImageModel;\n\n return provider;\n}\n\nexport const runpod = createRunpod();\n","import { ImageModelV2, ImageModelV2CallWarning } from '@ai-sdk/provider';\nimport {\n combineHeaders,\n createJsonResponseHandler,\n createBinaryResponseHandler,\n FetchFunction,\n postJsonToApi,\n getFromApi,\n} from '@ai-sdk/provider-utils';\nimport { InvalidArgumentError } from '@ai-sdk/provider';\nimport { z } from 'zod';\nimport { runpodImageFailedResponseHandler } from './runpod-error';\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\ninterface RunpodImageModelConfig {\n provider: string;\n baseURL: string;\n headers: () => Record<string, string>;\n fetch?: FetchFunction;\n _internal?: {\n currentDate?: () => Date;\n };\n}\n\n// Runpod supported aspect ratios (only validated working sizes)\nconst SUPPORTED_ASPECT_RATIOS: Record<string, string> = {\n '1:1': '1328*1328', // ✅ Native support\n '4:3': '1472*1140', // ✅ Native support\n '3:4': '1140*1472', // ✅ Native support\n};\n\n// Runpod supported sizes (validated working sizes)\nconst SUPPORTED_SIZES = new Set([\n // Native aspect ratio sizes\n '1328*1328', // 1:1\n '1472*1140', // 4:3\n '1140*1472', // 3:4\n // Additional validated sizes\n '512*512',\n '768*768',\n '1024*1024',\n '1536*1536',\n '2048*2048',\n '4096*4096',\n '512*768',\n '768*512',\n '1024*768',\n '768*1024',\n]);\n\nexport class RunpodImageModel implements ImageModelV2 {\n readonly specificationVersion = 'v2';\n readonly maxImagesPerCall = 1;\n\n get provider(): string {\n return this.config.provider;\n }\n\n constructor(\n readonly modelId: string,\n private config: RunpodImageModelConfig\n ) {}\n\n async doGenerate({\n prompt,\n n = 1,\n size,\n aspectRatio,\n seed,\n providerOptions,\n headers,\n abortSignal,\n }: Parameters<ImageModelV2['doGenerate']>[0]): Promise<\n Awaited<ReturnType<ImageModelV2['doGenerate']>>\n > {\n const warnings: Array<ImageModelV2CallWarning> = [];\n\n // Check if this is a Pruna model (skip standard size/aspectRatio validation)\n const isPrunaModel =\n this.modelId.includes('pruna') || this.modelId.includes('p-image');\n\n // Check if this is a Nano Banana Pro model (skip standard size/aspectRatio validation)\n const isNanoBananaProModel = this.modelId.includes('nano-banana-pro');\n\n // Determine the size to use\n let runpodSize: string;\n\n if (isPrunaModel || isNanoBananaProModel) {\n // These models use aspect_ratio string directly, skip size validation\n // Pass through the aspectRatio or use default, validation happens at API level\n runpodSize = aspectRatio || '1:1';\n } else if (size) {\n // Convert AI SDK format \"1328x1328\" to Runpod format \"1328*1328\"\n const runpodSizeCandidate = size.replace('x', '*');\n\n // Validate size is supported\n if (!SUPPORTED_SIZES.has(runpodSizeCandidate)) {\n throw new InvalidArgumentError({\n argument: 'size',\n message: `Size ${size} is not supported by Runpod. Supported sizes: ${Array.from(\n SUPPORTED_SIZES\n )\n .map((s) => s.replace('*', 'x'))\n .join(', ')}`,\n });\n }\n\n runpodSize = runpodSizeCandidate;\n } else if (aspectRatio) {\n // Validate aspect ratio is supported\n if (!SUPPORTED_ASPECT_RATIOS[aspectRatio]) {\n throw new InvalidArgumentError({\n argument: 'aspectRatio',\n message: `Aspect ratio ${aspectRatio} is not supported by Runpod. Supported aspect ratios: ${Object.keys(SUPPORTED_ASPECT_RATIOS).join(', ')}`,\n });\n }\n\n // Use supported aspect ratio mapping\n runpodSize = SUPPORTED_ASPECT_RATIOS[aspectRatio];\n } else {\n // Default to square format\n runpodSize = '1328*1328';\n }\n\n // Handle multiple images warning\n if (n > 1) {\n warnings.push({\n type: 'unsupported-setting',\n setting: 'n',\n details:\n 'Runpod image models only support generating 1 image at a time. Using n=1.',\n });\n }\n\n const currentDate = this.config._internal?.currentDate?.() ?? new Date();\n\n // Runpod uses a different request format - /runsync endpoint with input wrapper\n const inputPayload = this.buildInputPayload(\n prompt,\n runpodSize,\n seed,\n providerOptions.runpod,\n aspectRatio\n );\n\n const { value: response, responseHeaders } = await postJsonToApi({\n url: `${this.config.baseURL}/runsync`,\n headers: combineHeaders(this.config.headers(), headers),\n body: {\n input: inputPayload,\n },\n failedResponseHandler: runpodImageFailedResponseHandler,\n successfulResponseHandler: createJsonResponseHandler(\n runpodImageResponseSchema as any\n ),\n abortSignal,\n fetch: this.config.fetch,\n });\n\n // Handle both sync and async responses from Runpod\n const typedResponse = response as any;\n if (\n typedResponse.status === 'COMPLETED' &&\n (typedResponse.output?.result || typedResponse.output?.image_url)\n ) {\n // Sync response - image is ready\n // Different models use different response formats: result vs image_url\n const imageUrl =\n typedResponse.output.result || typedResponse.output.image_url;\n const imageData = await this.downloadImage(imageUrl, abortSignal);\n\n return {\n images: [imageData],\n warnings,\n response: {\n timestamp: currentDate,\n modelId: this.modelId,\n headers: responseHeaders,\n },\n providerMetadata: {\n runpod: {\n images: [\n {\n url: imageUrl,\n cost: typedResponse.output?.cost,\n },\n ],\n },\n },\n };\n } else if (\n typedResponse.status === 'IN_QUEUE' ||\n typedResponse.status === 'IN_PROGRESS'\n ) {\n // Async response - need to poll for completion\n const pollOptions = {\n maxAttempts: providerOptions.runpod?.maxPollAttempts as number,\n pollIntervalMillis: providerOptions.runpod\n ?.pollIntervalMillis as number,\n };\n const imageUrl = await this.pollForCompletion(\n typedResponse.id,\n abortSignal,\n pollOptions\n );\n const imageData = await this.downloadImage(imageUrl, abortSignal);\n\n return {\n images: [imageData],\n warnings,\n response: {\n timestamp: currentDate,\n modelId: this.modelId,\n headers: responseHeaders,\n },\n providerMetadata: {\n runpod: {\n images: [\n {\n url: imageUrl,\n jobId: typedResponse.id,\n },\n ],\n },\n },\n };\n } else {\n throw new Error(`Unexpected response status: ${typedResponse.status}`);\n }\n }\n\n private async downloadImage(\n imageUrl: string,\n abortSignal?: AbortSignal\n ): Promise<Uint8Array> {\n const { value: imageData } = await getFromApi({\n url: imageUrl,\n successfulResponseHandler: createBinaryResponseHandler(),\n failedResponseHandler: runpodImageFailedResponseHandler,\n abortSignal,\n fetch: this.config.fetch,\n });\n return imageData;\n }\n\n private async pollForCompletion(\n jobId: string,\n abortSignal?: AbortSignal,\n pollOptions?: { maxAttempts?: number; pollIntervalMillis?: number }\n ): Promise<string> {\n const maxAttempts = pollOptions?.maxAttempts ?? 60; // 5 minutes with 5-second intervals\n const pollInterval = pollOptions?.pollIntervalMillis ?? 5000; // 5 seconds\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n if (abortSignal?.aborted) {\n throw new Error('Image generation was aborted');\n }\n\n const { value: statusResponse } = await getFromApi({\n url: `${this.config.baseURL}/status/${jobId}`,\n headers: this.config.headers(),\n successfulResponseHandler: createJsonResponseHandler(\n runpodImageStatusSchema as any\n ),\n failedResponseHandler: runpodImageFailedResponseHandler,\n abortSignal,\n fetch: this.config.fetch,\n });\n\n const typedStatusResponse = statusResponse as any;\n if (\n typedStatusResponse.status === 'COMPLETED' &&\n (typedStatusResponse.output?.result ||\n typedStatusResponse.output?.image_url)\n ) {\n return (\n typedStatusResponse.output.result ||\n typedStatusResponse.output.image_url\n );\n }\n\n if (typedStatusResponse.status === 'FAILED') {\n throw new Error(\n `Image generation failed: ${typedStatusResponse.error || 'Unknown error'}`\n );\n }\n\n // Wait before next poll\n await new Promise((resolve) => setTimeout(resolve, pollInterval));\n }\n\n throw new Error(\n `Image generation timed out after ${maxAttempts} attempts (${(maxAttempts * pollInterval) / 1000}s)`\n );\n }\n\n private buildInputPayload(\n prompt: string,\n runpodSize: string,\n seed?: number,\n runpodOptions?: Record<string, unknown>,\n aspectRatio?: string\n ): Record<string, unknown> {\n // Check if this is a Flux model that uses different parameters\n const isFluxModel =\n this.modelId.includes('flux') ||\n this.modelId.includes('black-forest-labs');\n\n if (isFluxModel) {\n // Check if this is Flux Kontext (uses different parameters)\n const isKontext = this.modelId.includes('kontext');\n\n if (isKontext) {\n // Flux Kontext uses size format and has image input\n return {\n prompt,\n negative_prompt: runpodOptions?.negative_prompt ?? '',\n seed: seed ?? -1,\n num_inference_steps: 28,\n guidance: 2,\n size: runpodSize,\n output_format: 'png',\n enable_safety_checker: runpodOptions?.enable_safety_checker ?? true,\n ...runpodOptions, // This will include the 'image' parameter if provided\n };\n } else {\n // Regular Flux models use width/height\n const [width, height] = runpodSize.split('*').map(Number);\n\n return {\n prompt,\n negative_prompt: runpodOptions?.negative_prompt ?? '',\n seed: seed ?? -1,\n num_inference_steps: this.modelId.includes('schnell') ? 4 : 28,\n guidance: this.modelId.includes('schnell') ? 7 : 2,\n width,\n height,\n image_format: 'png',\n ...runpodOptions,\n };\n }\n }\n\n // Check if this is a Pruna model\n const isPrunaModel =\n this.modelId.includes('pruna') || this.modelId.includes('p-image');\n if (isPrunaModel) {\n const isPrunaEdit = this.modelId.includes('edit');\n\n if (isPrunaEdit) {\n // Pruna image edit\n // Supported aspect_ratio: \"match_input_image\", \"1:1\", \"16:9\", \"9:16\", \"4:3\", \"3:4\", \"3:2\", \"2:3\"\n // Supports 1-5 images via providerOptions.runpod.images\n const editPayload: Record<string, unknown> = {\n prompt,\n aspect_ratio:\n (runpodOptions?.aspect_ratio as string) ??\n aspectRatio ??\n 'match_input_image',\n disable_safety_checker:\n (runpodOptions?.disable_safety_checker as boolean) ?? false,\n };\n\n // Add seed if provided\n if (seed !== undefined) {\n editPayload.seed = seed;\n } else if (runpodOptions?.seed !== undefined) {\n editPayload.seed = runpodOptions.seed;\n }\n\n // Add images array (required, 1-5 images)\n if (runpodOptions?.images) {\n editPayload.images = runpodOptions.images;\n }\n\n return editPayload;\n } else {\n // Pruna text-to-image\n // Supported aspect_ratio: \"1:1\", \"16:9\", \"9:16\", \"4:3\", \"3:4\", \"3:2\", \"2:3\", \"custom\"\n // For custom: width/height 256-1440, must be multiple of 16\n const t2iPayload: Record<string, unknown> = {\n prompt,\n aspect_ratio:\n (runpodOptions?.aspect_ratio as string) ?? aspectRatio ?? '1:1',\n disable_safety_checker:\n (runpodOptions?.disable_safety_checker as boolean) ?? false,\n };\n\n // Add seed if provided\n if (seed !== undefined) {\n t2iPayload.seed = seed;\n } else if (runpodOptions?.seed !== undefined) {\n t2iPayload.seed = runpodOptions.seed;\n }\n\n // Handle custom aspect ratio with width/height\n if (t2iPayload.aspect_ratio === 'custom') {\n if (runpodOptions?.width) {\n t2iPayload.width = runpodOptions.width;\n }\n if (runpodOptions?.height) {\n t2iPayload.height = runpodOptions.height;\n }\n }\n\n return t2iPayload;\n }\n }\n\n // Check if this is a Nano Banana Pro model (google/nano-banana-pro-edit)\n const isNanaBananaProModel = this.modelId.includes('nano-banana-pro');\n if (isNanaBananaProModel) {\n // Nano Banana Pro image edit\n // Supported aspect_ratio: \"1:1\", \"16:9\", \"9:16\", \"4:3\", \"3:4\", \"3:2\", \"2:3\", \"21:9\", \"9:21\"\n // Supported resolution: \"1k\", \"2k\", \"4k\"\n // Supported output_format: \"jpeg\", \"png\", \"webp\"\n const nanoBananaPayload: Record<string, unknown> = {\n prompt,\n aspect_ratio:\n (runpodOptions?.aspect_ratio as string) ?? aspectRatio ?? '1:1',\n resolution: (runpodOptions?.resolution as string) ?? '1k',\n output_format: (runpodOptions?.output_format as string) ?? 'jpeg',\n enable_base64_output:\n (runpodOptions?.enable_base64_output as boolean) ?? false,\n enable_sync_mode:\n (runpodOptions?.enable_sync_mode as boolean) ?? false,\n };\n\n // Add images array (required)\n if (runpodOptions?.images) {\n nanoBananaPayload.images = runpodOptions.images;\n }\n\n return nanoBananaPayload;\n }\n\n // Default format for Qwen and other models\n return {\n prompt,\n negative_prompt: runpodOptions?.negative_prompt ?? '',\n size: runpodSize,\n seed: seed ?? -1,\n enable_safety_checker: runpodOptions?.enable_safety_checker ?? true,\n ...runpodOptions,\n };\n }\n}\n\n// Runpod image API response schema (handles both sync and async responses)\nconst runpodImageResponseSchema = z.object({\n id: z.string(),\n status: z.enum(['COMPLETED', 'IN_QUEUE', 'IN_PROGRESS', 'FAILED']),\n delayTime: z.number().optional(),\n executionTime: z.number().optional(),\n output: z\n .object({\n cost: z.number().optional(),\n result: z.string().optional(), // URL to the generated image (Qwen format)\n image_url: z.string().optional(), // URL to the generated image (Flux format)\n })\n .optional(), // Optional for IN_QUEUE/IN_PROGRESS responses\n});\n\n// Schema for polling status endpoint\nconst runpodImageStatusSchema = z.object({\n id: z.string(),\n status: z.enum(['COMPLETED', 'IN_QUEUE', 'IN_PROGRESS', 'FAILED']),\n output: z\n .object({\n cost: z.number().optional(),\n result: z.string().optional(),\n image_url: z.string().optional(),\n })\n .optional(),\n error: z.string().optional(), // Error message if FAILED\n});\n","import { z } from 'zod';\r\nimport { createJsonErrorResponseHandler } from '@ai-sdk/provider-utils';\r\n\r\n// Runpod image API error schema (supports both error formats)\r\nexport const runpodImageErrorSchema = z.object({\r\n error: z.string().optional(),\r\n message: z.string().optional(),\r\n});\r\n\r\nexport type RunpodImageErrorData = z.infer<typeof runpodImageErrorSchema>;\r\n\r\nexport const runpodImageFailedResponseHandler = createJsonErrorResponseHandler({\r\n errorSchema: runpodImageErrorSchema as any,\r\n errorToMessage: (data: RunpodImageErrorData) => {\r\n // Prefer message if available (more descriptive)\r\n if (data.message) {\r\n return data.message;\r\n }\r\n \r\n // If error field exists, try to extract nested JSON message\r\n if (data.error) {\r\n // Runpod sometimes returns nested JSON in the error field like:\r\n // \"Error submitting task: 400, {\\\"code\\\":400,\\\"message\\\":\\\"...\\\"}\"\r\n // Try to extract the inner message for cleaner error messages\r\n // Find the last occurrence of { which likely starts the JSON object\r\n const lastBraceIndex = data.error.lastIndexOf('{');\r\n if (lastBraceIndex !== -1) {\r\n try {\r\n const jsonStr = data.error.substring(lastBraceIndex);\r\n const nestedError = JSON.parse(jsonStr);\r\n if (nestedError.message && typeof nestedError.message === 'string') {\r\n return nestedError.message;\r\n }\r\n } catch {\r\n // If parsing fails, fall back to the original error string\r\n }\r\n }\r\n return data.error;\r\n }\r\n \r\n return 'Unknown Runpod error';\r\n },\r\n});\r\n\r\n"],"mappings":"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","names":["import_provider_utils","import_provider_utils","import_zod"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/runpod-provider.ts","../src/runpod-image-model.ts","../src/runpod-error.ts","../src/runpod-speech-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';\nexport type { RunpodImageErrorData } from './runpod-error';\n","import { ImageModelV2, LanguageModelV2, SpeechModelV2 } from '@ai-sdk/provider';\nimport {\n OpenAICompatibleChatLanguageModel,\n OpenAICompatibleCompletionLanguageModel,\n} from '@ai-sdk/openai-compatible';\nimport {\n FetchFunction,\n loadApiKey,\n withoutTrailingSlash,\n} from '@ai-sdk/provider-utils';\nimport { RunpodImageModel } from './runpod-image-model';\nimport { RunpodSpeechModel } from './runpod-speech-model';\n\nexport interface RunpodProviderSettings {\n /**\nRunpod API key.\n*/\n apiKey?: string;\n /**\nCustom base URL for Runpod API. Use this to point to custom endpoints or different Runpod deployments.\nExample: 'https://api.runpod.ai/v2/your-endpoint-id/openai/v1'\n*/\n baseURL?: string;\n /**\nCustom headers to include in the requests.\n*/\n headers?: Record<string, string>;\n /**\nCustom fetch implementation. You can use it as a middleware to intercept requests,\nor to provide a custom fetch implementation for e.g. testing.\n*/\n fetch?: FetchFunction;\n}\n\nexport interface RunpodProvider {\n /**\nCreates a model for text generation.\n*/\n (modelId: string): LanguageModelV2;\n\n /**\nCreates a chat model for text generation.\n*/\n chatModel(modelId: string): LanguageModelV2;\n\n /**\nCreates a chat model for text generation.\n*/\n languageModel(modelId: string): LanguageModelV2;\n\n /**\nCreates a completion model for text generation.\n*/\n completionModel(modelId: string): LanguageModelV2;\n\n /**\nCreates an image model for image generation.\n*/\n imageModel(modelId: string): ImageModelV2;\n\n /**\nCreates a speech model for speech generation.\n*/\n speechModel(modelId: string): SpeechModelV2;\n\n /**\nCreates a speech model for speech generation.\n*/\n speech(modelId: string): SpeechModelV2;\n}\n\n// Mapping of Runpod model IDs to their endpoint URLs\nconst MODEL_ID_TO_ENDPOINT_URL: Record<string, string> = {\n 'qwen/qwen3-32b-awq': 'https://api.runpod.ai/v2/qwen3-32b-awq/openai/v1',\n 'ibm-granite/granite-4.0-h-small':\n 'https://api.runpod.ai/v2/granite-4-0-h-small/openai/v1',\n 'gpt-oss-120b': 'https://api.runpod.ai/v2/gpt-oss-120b/openai/v1',\n 'openai/gpt-oss-120b': 'https://api.runpod.ai/v2/gpt-oss-120b/openai/v1',\n 'deepcogito/cogito-671b-v2.1-fp8':\n 'https://api.runpod.ai/v2/cogito-671b-v2-1-fp8-dynamic/openai/v1',\n 'deepcogito/cogito-671b-v2.1-FP8':\n 'https://api.runpod.ai/v2/cogito-671b-v2-1-fp8-dynamic/openai/v1',\n};\n\n// Mapping of Runpod image model IDs to their endpoint URLs\nconst IMAGE_MODEL_ID_TO_ENDPOINT_URL: Record<string, string> = {\n 'qwen/qwen-image': 'https://api.runpod.ai/v2/qwen-image-t2i',\n 'qwen/qwen-image-edit': 'https://api.runpod.ai/v2/qwen-image-edit',\n 'bytedance/seedream-3.0': 'https://api.runpod.ai/v2/seedream-3-0-t2i',\n // Seadream v4 (t2i and edit)\n 'bytedance/seedream-4.0': 'https://api.runpod.ai/v2/seedream-v4-t2i',\n 'bytedance/seedream-4.0-edit': 'https://api.runpod.ai/v2/seedream-v4-edit',\n 'black-forest-labs/flux-1-kontext-dev':\n 'https://api.runpod.ai/v2/black-forest-labs-flux-1-kontext-dev',\n 'black-forest-labs/flux-1-schnell':\n 'https://api.runpod.ai/v2/black-forest-labs-flux-1-schnell',\n 'black-forest-labs/flux-1-dev':\n 'https://api.runpod.ai/v2/black-forest-labs-flux-1-dev',\n // Nano Banana (edit only)\n 'nano-banana-edit': 'https://api.runpod.ai/v2/nano-banana-edit',\n // Nano Banana Pro (edit only)\n 'google/nano-banana-pro-edit':\n 'https://api.runpod.ai/v2/nano-banana-pro-edit',\n // Pruna (t2i and edit)\n 'pruna/p-image-t2i': 'https://api.runpod.ai/v2/p-image-t2i',\n 'pruna/p-image-edit': 'https://api.runpod.ai/v2/p-image-edit',\n};\n\n// Mapping of Runpod speech model IDs to their serverless endpoint URLs\n// Note: This is intentionally a temporary mapping for a stealth release.\nconst SPEECH_MODEL_ID_TO_ENDPOINT_URL: Record<string, string> = {\n 'resembleai/chatterbox-turbo': 'https://api.runpod.ai/v2/chatterbox-turbo/',\n};\n\n// Mapping of Runpod model IDs to their OpenAI model names\nconst MODEL_ID_TO_OPENAI_NAME: Record<string, string> = {\n 'qwen/qwen3-32b-awq': 'Qwen/Qwen3-32B-AWQ',\n 'deepcogito/cogito-671b-v2.1-fp8': 'deepcogito/cogito-671b-v2.1-FP8',\n 'deepcogito/cogito-671b-v2.1-FP8': 'deepcogito/cogito-671b-v2.1-FP8',\n};\n\n/**\n * Derives the endpoint URL for a model by replacing slashes with hyphens.\n * Example: 'ibm-granite/granite-4.0-h-small' -> 'https://api.runpod.ai/v2/ibm-granite-granite-4.0-h-small/openai/v1'\n */\nfunction deriveEndpointURL(modelId: string): string {\n const normalized = modelId.replace(/\\//g, '-');\n return `https://api.runpod.ai/v2/${normalized}/openai/v1`;\n}\n\nfunction parseRunpodConsoleEndpointId(modelIdOrUrl: string): string | null {\n if (!modelIdOrUrl.startsWith('http')) {\n return null;\n }\n\n try {\n const url = new URL(modelIdOrUrl);\n if (url.hostname !== 'console.runpod.io') {\n return null;\n }\n\n // Example:\n // https://console.runpod.io/serverless/user/endpoint/<ENDPOINT_ID>\n const parts = url.pathname.split('/').filter(Boolean);\n const idx = parts.lastIndexOf('endpoint');\n const endpointId = idx !== -1 ? parts[idx + 1] : undefined;\n\n return endpointId || null;\n } catch {\n return null;\n }\n}\n\nexport function createRunpod(\n options: RunpodProviderSettings = {}\n): RunpodProvider {\n const getHeaders = () => ({\n Authorization: `Bearer ${loadApiKey({\n apiKey: options.apiKey,\n environmentVariableName: 'RUNPOD_API_KEY',\n description: 'Runpod',\n })}`,\n ...options.headers,\n });\n\n const runpodFetch: FetchFunction = async (url, requestInit) => {\n if (requestInit?.body) {\n try {\n const body = JSON.parse(requestInit.body as string);\n if (body.stream === true && !body.stream_options) {\n body.stream_options = { include_usage: true };\n requestInit.body = JSON.stringify(body);\n }\n } catch {}\n }\n const fetchFn = options.fetch || fetch;\n return fetchFn(url, requestInit);\n };\n\n interface CommonModelConfig {\n provider: string;\n url: ({ path }: { path: string }) => string;\n headers: () => Record<string, string>;\n fetch?: FetchFunction;\n }\n\n const getModelConfig = (\n modelId: string,\n modelType: string\n ): CommonModelConfig => {\n let baseURL: string;\n\n if (options.baseURL) {\n baseURL = options.baseURL;\n } else {\n // Use hardcoded mapping if available, otherwise derive endpoint\n baseURL = MODEL_ID_TO_ENDPOINT_URL[modelId] || deriveEndpointURL(modelId);\n }\n\n return {\n provider: `runpod.${modelType}`,\n url: ({ path }) => `${withoutTrailingSlash(baseURL)}${path}`,\n headers: getHeaders,\n fetch: runpodFetch,\n };\n };\n\n const createChatModel = (modelId: string) => {\n const openaiModelName = MODEL_ID_TO_OPENAI_NAME[modelId] || modelId;\n return new OpenAICompatibleChatLanguageModel(openaiModelName, {\n ...getModelConfig(modelId, 'chat'),\n includeUsage: true,\n });\n };\n\n const createCompletionModel = (modelId: string) => {\n const openaiModelName = MODEL_ID_TO_OPENAI_NAME[modelId] || modelId;\n return new OpenAICompatibleCompletionLanguageModel(openaiModelName, {\n ...getModelConfig(modelId, 'completion'),\n includeUsage: true,\n });\n };\n\n const createImageModel = (modelId: string) => {\n let baseURL: string;\n\n if (options.baseURL) {\n baseURL = options.baseURL;\n } else {\n // Use hardcoded mapping if available, otherwise derive endpoint\n baseURL =\n IMAGE_MODEL_ID_TO_ENDPOINT_URL[modelId] || deriveEndpointURL(modelId);\n }\n\n return new RunpodImageModel(modelId, {\n provider: 'runpod.image',\n baseURL,\n headers: getHeaders,\n fetch: options.fetch,\n });\n };\n\n const createSpeechModel = (modelId: string) => {\n const endpointIdFromConsole = parseRunpodConsoleEndpointId(modelId);\n const normalizedModelId = endpointIdFromConsole ?? modelId;\n\n // Prefer explicit mapping for known speech model IDs.\n const mappedBaseURL = SPEECH_MODEL_ID_TO_ENDPOINT_URL[normalizedModelId];\n\n const baseURL =\n mappedBaseURL ??\n (normalizedModelId.startsWith('http')\n ? normalizedModelId\n : `https://api.runpod.ai/v2/${normalizedModelId}`);\n\n return new RunpodSpeechModel(normalizedModelId, {\n provider: 'runpod.speech',\n baseURL,\n headers: getHeaders,\n fetch: runpodFetch,\n });\n };\n\n const provider = (modelId: string) => createChatModel(modelId);\n\n provider.completionModel = createCompletionModel;\n provider.languageModel = createChatModel;\n provider.chatModel = createChatModel;\n provider.imageModel = createImageModel;\n provider.speechModel = createSpeechModel;\n provider.speech = createSpeechModel;\n\n return provider;\n}\n\nexport const runpod = createRunpod();\n","import { ImageModelV2, ImageModelV2CallWarning } from '@ai-sdk/provider';\nimport {\n combineHeaders,\n createJsonResponseHandler,\n createBinaryResponseHandler,\n FetchFunction,\n postJsonToApi,\n getFromApi,\n} from '@ai-sdk/provider-utils';\nimport { InvalidArgumentError } from '@ai-sdk/provider';\nimport { z } from 'zod';\nimport { runpodImageFailedResponseHandler } from './runpod-error';\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\ninterface RunpodImageModelConfig {\n provider: string;\n baseURL: string;\n headers: () => Record<string, string>;\n fetch?: FetchFunction;\n _internal?: {\n currentDate?: () => Date;\n };\n}\n\n// Runpod supported aspect ratios (only validated working sizes)\nconst SUPPORTED_ASPECT_RATIOS: Record<string, string> = {\n '1:1': '1328*1328', // ✅ Native support\n '4:3': '1472*1140', // ✅ Native support\n '3:4': '1140*1472', // ✅ Native support\n};\n\n// Runpod supported sizes (validated working sizes)\nconst SUPPORTED_SIZES = new Set([\n // Native aspect ratio sizes\n '1328*1328', // 1:1\n '1472*1140', // 4:3\n '1140*1472', // 3:4\n // Additional validated sizes\n '512*512',\n '768*768',\n '1024*1024',\n '1536*1536',\n '2048*2048',\n '4096*4096',\n '512*768',\n '768*512',\n '1024*768',\n '768*1024',\n]);\n\nexport class RunpodImageModel implements ImageModelV2 {\n readonly specificationVersion = 'v2';\n readonly maxImagesPerCall = 1;\n\n get provider(): string {\n return this.config.provider;\n }\n\n constructor(\n readonly modelId: string,\n private config: RunpodImageModelConfig\n ) {}\n\n async doGenerate({\n prompt,\n n = 1,\n size,\n aspectRatio,\n seed,\n providerOptions,\n headers,\n abortSignal,\n }: Parameters<ImageModelV2['doGenerate']>[0]): Promise<\n Awaited<ReturnType<ImageModelV2['doGenerate']>>\n > {\n const warnings: Array<ImageModelV2CallWarning> = [];\n\n // Check if this is a Pruna model (skip standard size/aspectRatio validation)\n const isPrunaModel =\n this.modelId.includes('pruna') || this.modelId.includes('p-image');\n\n // Check if this is a Nano Banana Pro model (skip standard size/aspectRatio validation)\n const isNanoBananaProModel = this.modelId.includes('nano-banana-pro');\n\n // Determine the size to use\n let runpodSize: string;\n\n if (isPrunaModel || isNanoBananaProModel) {\n // These models use aspect_ratio string directly, skip size validation\n // Pass through the aspectRatio or use default, validation happens at API level\n runpodSize = aspectRatio || '1:1';\n } else if (size) {\n // Convert AI SDK format \"1328x1328\" to Runpod format \"1328*1328\"\n const runpodSizeCandidate = size.replace('x', '*');\n\n // Validate size is supported\n if (!SUPPORTED_SIZES.has(runpodSizeCandidate)) {\n throw new InvalidArgumentError({\n argument: 'size',\n message: `Size ${size} is not supported by Runpod. Supported sizes: ${Array.from(\n SUPPORTED_SIZES\n )\n .map((s) => s.replace('*', 'x'))\n .join(', ')}`,\n });\n }\n\n runpodSize = runpodSizeCandidate;\n } else if (aspectRatio) {\n // Validate aspect ratio is supported\n if (!SUPPORTED_ASPECT_RATIOS[aspectRatio]) {\n throw new InvalidArgumentError({\n argument: 'aspectRatio',\n message: `Aspect ratio ${aspectRatio} is not supported by Runpod. Supported aspect ratios: ${Object.keys(SUPPORTED_ASPECT_RATIOS).join(', ')}`,\n });\n }\n\n // Use supported aspect ratio mapping\n runpodSize = SUPPORTED_ASPECT_RATIOS[aspectRatio];\n } else {\n // Default to square format\n runpodSize = '1328*1328';\n }\n\n // Handle multiple images warning\n if (n > 1) {\n warnings.push({\n type: 'unsupported-setting',\n setting: 'n',\n details:\n 'Runpod image models only support generating 1 image at a time. Using n=1.',\n });\n }\n\n const currentDate = this.config._internal?.currentDate?.() ?? new Date();\n\n // Runpod uses a different request format - /runsync endpoint with input wrapper\n const inputPayload = this.buildInputPayload(\n prompt,\n runpodSize,\n seed,\n providerOptions.runpod,\n aspectRatio\n );\n\n const { value: response, responseHeaders } = await postJsonToApi({\n url: `${this.config.baseURL}/runsync`,\n headers: combineHeaders(this.config.headers(), headers),\n body: {\n input: inputPayload,\n },\n failedResponseHandler: runpodImageFailedResponseHandler,\n successfulResponseHandler: createJsonResponseHandler(\n runpodImageResponseSchema as any\n ),\n abortSignal,\n fetch: this.config.fetch,\n });\n\n // Handle both sync and async responses from Runpod\n const typedResponse = response as any;\n if (\n typedResponse.status === 'COMPLETED' &&\n (typedResponse.output?.result || typedResponse.output?.image_url)\n ) {\n // Sync response - image is ready\n // Different models use different response formats: result vs image_url\n const imageUrl =\n typedResponse.output.result || typedResponse.output.image_url;\n const imageData = await this.downloadImage(imageUrl, abortSignal);\n\n return {\n images: [imageData],\n warnings,\n response: {\n timestamp: currentDate,\n modelId: this.modelId,\n headers: responseHeaders,\n },\n providerMetadata: {\n runpod: {\n images: [\n {\n url: imageUrl,\n cost: typedResponse.output?.cost,\n },\n ],\n },\n },\n };\n } else if (\n typedResponse.status === 'IN_QUEUE' ||\n typedResponse.status === 'IN_PROGRESS'\n ) {\n // Async response - need to poll for completion\n const pollOptions = {\n maxAttempts: providerOptions.runpod?.maxPollAttempts as number,\n pollIntervalMillis: providerOptions.runpod\n ?.pollIntervalMillis as number,\n };\n const imageUrl = await this.pollForCompletion(\n typedResponse.id,\n abortSignal,\n pollOptions\n );\n const imageData = await this.downloadImage(imageUrl, abortSignal);\n\n return {\n images: [imageData],\n warnings,\n response: {\n timestamp: currentDate,\n modelId: this.modelId,\n headers: responseHeaders,\n },\n providerMetadata: {\n runpod: {\n images: [\n {\n url: imageUrl,\n jobId: typedResponse.id,\n },\n ],\n },\n },\n };\n } else {\n throw new Error(`Unexpected response status: ${typedResponse.status}`);\n }\n }\n\n private async downloadImage(\n imageUrl: string,\n abortSignal?: AbortSignal\n ): Promise<Uint8Array> {\n const { value: imageData } = await getFromApi({\n url: imageUrl,\n successfulResponseHandler: createBinaryResponseHandler(),\n failedResponseHandler: runpodImageFailedResponseHandler,\n abortSignal,\n fetch: this.config.fetch,\n });\n return imageData;\n }\n\n private async pollForCompletion(\n jobId: string,\n abortSignal?: AbortSignal,\n pollOptions?: { maxAttempts?: number; pollIntervalMillis?: number }\n ): Promise<string> {\n const maxAttempts = pollOptions?.maxAttempts ?? 60; // 5 minutes with 5-second intervals\n const pollInterval = pollOptions?.pollIntervalMillis ?? 5000; // 5 seconds\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n if (abortSignal?.aborted) {\n throw new Error('Image generation was aborted');\n }\n\n const { value: statusResponse } = await getFromApi({\n url: `${this.config.baseURL}/status/${jobId}`,\n headers: this.config.headers(),\n successfulResponseHandler: createJsonResponseHandler(\n runpodImageStatusSchema as any\n ),\n failedResponseHandler: runpodImageFailedResponseHandler,\n abortSignal,\n fetch: this.config.fetch,\n });\n\n const typedStatusResponse = statusResponse as any;\n if (\n typedStatusResponse.status === 'COMPLETED' &&\n (typedStatusResponse.output?.result ||\n typedStatusResponse.output?.image_url)\n ) {\n return (\n typedStatusResponse.output.result ||\n typedStatusResponse.output.image_url\n );\n }\n\n if (typedStatusResponse.status === 'FAILED') {\n throw new Error(\n `Image generation failed: ${typedStatusResponse.error || 'Unknown error'}`\n );\n }\n\n // Wait before next poll\n await new Promise((resolve) => setTimeout(resolve, pollInterval));\n }\n\n throw new Error(\n `Image generation timed out after ${maxAttempts} attempts (${(maxAttempts * pollInterval) / 1000}s)`\n );\n }\n\n private buildInputPayload(\n prompt: string,\n runpodSize: string,\n seed?: number,\n runpodOptions?: Record<string, unknown>,\n aspectRatio?: string\n ): Record<string, unknown> {\n // Check if this is a Flux model that uses different parameters\n const isFluxModel =\n this.modelId.includes('flux') ||\n this.modelId.includes('black-forest-labs');\n\n if (isFluxModel) {\n // Check if this is Flux Kontext (uses different parameters)\n const isKontext = this.modelId.includes('kontext');\n\n if (isKontext) {\n // Flux Kontext uses size format and has image input\n return {\n prompt,\n negative_prompt: runpodOptions?.negative_prompt ?? '',\n seed: seed ?? -1,\n num_inference_steps: 28,\n guidance: 2,\n size: runpodSize,\n output_format: 'png',\n enable_safety_checker: runpodOptions?.enable_safety_checker ?? true,\n ...runpodOptions, // This will include the 'image' parameter if provided\n };\n } else {\n // Regular Flux models use width/height\n const [width, height] = runpodSize.split('*').map(Number);\n\n return {\n prompt,\n negative_prompt: runpodOptions?.negative_prompt ?? '',\n seed: seed ?? -1,\n num_inference_steps: this.modelId.includes('schnell') ? 4 : 28,\n guidance: this.modelId.includes('schnell') ? 7 : 2,\n width,\n height,\n image_format: 'png',\n ...runpodOptions,\n };\n }\n }\n\n // Check if this is a Pruna model\n const isPrunaModel =\n this.modelId.includes('pruna') || this.modelId.includes('p-image');\n if (isPrunaModel) {\n const isPrunaEdit = this.modelId.includes('edit');\n\n if (isPrunaEdit) {\n // Pruna image edit\n // Supported aspect_ratio: \"1:1\", \"16:9\", \"9:16\", \"4:3\", \"3:4\", \"3:2\", \"2:3\"\n // Supports 1-5 images via providerOptions.runpod.images\n const editPayload: Record<string, unknown> = {\n prompt,\n aspect_ratio:\n (runpodOptions?.aspect_ratio as string) ?? aspectRatio ?? '1:1',\n disable_safety_checker:\n (runpodOptions?.disable_safety_checker as boolean) ?? false,\n };\n\n // Add seed if provided\n if (seed !== undefined) {\n editPayload.seed = seed;\n } else if (runpodOptions?.seed !== undefined) {\n editPayload.seed = runpodOptions.seed;\n }\n\n // Add images array (required, 1-5 images)\n if (runpodOptions?.images) {\n editPayload.images = runpodOptions.images;\n }\n\n return editPayload;\n } else {\n // Pruna text-to-image\n // Supported aspect_ratio: \"1:1\", \"16:9\", \"9:16\", \"4:3\", \"3:4\", \"3:2\", \"2:3\", \"custom\"\n // For custom: width/height 256-1440, must be multiple of 16\n const t2iPayload: Record<string, unknown> = {\n prompt,\n aspect_ratio:\n (runpodOptions?.aspect_ratio as string) ?? aspectRatio ?? '1:1',\n disable_safety_checker:\n (runpodOptions?.disable_safety_checker as boolean) ?? false,\n };\n\n // Add seed if provided\n if (seed !== undefined) {\n t2iPayload.seed = seed;\n } else if (runpodOptions?.seed !== undefined) {\n t2iPayload.seed = runpodOptions.seed;\n }\n\n // Handle custom aspect ratio with width/height\n if (t2iPayload.aspect_ratio === 'custom') {\n if (runpodOptions?.width) {\n t2iPayload.width = runpodOptions.width;\n }\n if (runpodOptions?.height) {\n t2iPayload.height = runpodOptions.height;\n }\n }\n\n return t2iPayload;\n }\n }\n\n // Check if this is a Nano Banana Pro model (google/nano-banana-pro-edit)\n const isNanaBananaProModel = this.modelId.includes('nano-banana-pro');\n if (isNanaBananaProModel) {\n // Nano Banana Pro image edit\n // Supported aspect_ratio: \"1:1\", \"16:9\", \"9:16\", \"4:3\", \"3:4\", \"3:2\", \"2:3\", \"21:9\", \"9:21\"\n // Supported resolution: \"1k\", \"2k\", \"4k\"\n // Supported output_format: \"jpeg\", \"png\", \"webp\"\n const nanoBananaPayload: Record<string, unknown> = {\n prompt,\n aspect_ratio:\n (runpodOptions?.aspect_ratio as string) ?? aspectRatio ?? '1:1',\n resolution: (runpodOptions?.resolution as string) ?? '1k',\n output_format: (runpodOptions?.output_format as string) ?? 'jpeg',\n enable_base64_output:\n (runpodOptions?.enable_base64_output as boolean) ?? false,\n enable_sync_mode:\n (runpodOptions?.enable_sync_mode as boolean) ?? false,\n };\n\n // Add images array (required)\n if (runpodOptions?.images) {\n nanoBananaPayload.images = runpodOptions.images;\n }\n\n return nanoBananaPayload;\n }\n\n // Default format for Qwen and other models\n return {\n prompt,\n negative_prompt: runpodOptions?.negative_prompt ?? '',\n size: runpodSize,\n seed: seed ?? -1,\n enable_safety_checker: runpodOptions?.enable_safety_checker ?? true,\n ...runpodOptions,\n };\n }\n}\n\n// Runpod image API response schema (handles both sync and async responses)\nconst runpodImageResponseSchema = z.object({\n id: z.string(),\n status: z.enum(['COMPLETED', 'IN_QUEUE', 'IN_PROGRESS', 'FAILED']),\n delayTime: z.number().optional(),\n executionTime: z.number().optional(),\n output: z\n .object({\n cost: z.number().optional(),\n result: z.string().optional(), // URL to the generated image (Qwen format)\n image_url: z.string().optional(), // URL to the generated image (Flux format)\n })\n .optional(), // Optional for IN_QUEUE/IN_PROGRESS responses\n});\n\n// Schema for polling status endpoint\nconst runpodImageStatusSchema = z.object({\n id: z.string(),\n status: z.enum(['COMPLETED', 'IN_QUEUE', 'IN_PROGRESS', 'FAILED']),\n output: z\n .object({\n cost: z.number().optional(),\n result: z.string().optional(),\n image_url: z.string().optional(),\n })\n .optional(),\n error: z.string().optional(), // Error message if FAILED\n});\n","import { z } from 'zod';\r\nimport { createJsonErrorResponseHandler } from '@ai-sdk/provider-utils';\r\n\r\n// Runpod image API error schema (supports both error formats)\r\nexport const runpodImageErrorSchema = z.object({\r\n error: z.string().optional(),\r\n message: z.string().optional(),\r\n});\r\n\r\nexport type RunpodImageErrorData = z.infer<typeof runpodImageErrorSchema>;\r\n\r\nexport const runpodImageFailedResponseHandler = createJsonErrorResponseHandler({\r\n errorSchema: runpodImageErrorSchema as any,\r\n errorToMessage: (data: RunpodImageErrorData) => {\r\n // Prefer message if available (more descriptive)\r\n if (data.message) {\r\n return data.message;\r\n }\r\n \r\n // If error field exists, try to extract nested JSON message\r\n if (data.error) {\r\n // Runpod sometimes returns nested JSON in the error field like:\r\n // \"Error submitting task: 400, {\\\"code\\\":400,\\\"message\\\":\\\"...\\\"}\"\r\n // Try to extract the inner message for cleaner error messages\r\n // Find the last occurrence of { which likely starts the JSON object\r\n const lastBraceIndex = data.error.lastIndexOf('{');\r\n if (lastBraceIndex !== -1) {\r\n try {\r\n const jsonStr = data.error.substring(lastBraceIndex);\r\n const nestedError = JSON.parse(jsonStr);\r\n if (nestedError.message && typeof nestedError.message === 'string') {\r\n return nestedError.message;\r\n }\r\n } catch {\r\n // If parsing fails, fall back to the original error string\r\n }\r\n }\r\n return data.error;\r\n }\r\n \r\n return 'Unknown Runpod error';\r\n },\r\n});\r\n\r\n","import {\n JSONValue,\n SpeechModelV2,\n SpeechModelV2CallWarning,\n} from '@ai-sdk/provider';\nimport { FetchFunction, withoutTrailingSlash } from '@ai-sdk/provider-utils';\n\nexport interface RunpodSpeechModelConfig {\n provider: string;\n baseURL: string;\n headers: () => Record<string, string>;\n fetch?: FetchFunction;\n _internal?: {\n currentDate?: () => Date;\n };\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction replaceNewlinesWithSpaces(value: string): string {\n return value.replace(/[\\r\\n]+/g, ' ');\n}\n\nexport class RunpodSpeechModel implements SpeechModelV2 {\n readonly specificationVersion = 'v2';\n\n get provider(): string {\n return this.config.provider;\n }\n\n constructor(\n readonly modelId: string,\n private readonly config: RunpodSpeechModelConfig\n ) {}\n\n private getRunpodRunSyncUrl(): string {\n // `withoutTrailingSlash` is typed to potentially return undefined, but in our\n // case `config.baseURL` is always a string.\n const baseURL =\n withoutTrailingSlash(this.config.baseURL) ?? this.config.baseURL;\n\n // Allow users to pass /run or /runsync directly.\n if (baseURL.endsWith('/run') || baseURL.endsWith('/runsync')) {\n return baseURL;\n }\n\n return `${baseURL}/runsync`;\n }\n\n async doGenerate(\n options: Parameters<SpeechModelV2['doGenerate']>[0]\n ): Promise<Awaited<ReturnType<SpeechModelV2['doGenerate']>>> {\n const currentDate = this.config._internal?.currentDate?.() ?? new Date();\n\n const warnings: SpeechModelV2CallWarning[] = [];\n\n const {\n text,\n voice,\n outputFormat,\n instructions,\n speed,\n language,\n providerOptions,\n abortSignal,\n headers,\n } = options;\n\n // This endpoint currently returns wav. Warn and ignore other formats.\n if (outputFormat != null && outputFormat !== 'wav') {\n warnings.push({\n type: 'unsupported-setting',\n setting: 'outputFormat',\n details: `Unsupported outputFormat: ${outputFormat}. This endpoint returns 'wav'.`,\n });\n }\n\n if (instructions != null) {\n warnings.push({\n type: 'unsupported-setting',\n setting: 'instructions',\n details: `Instructions are not supported by this speech endpoint.`,\n });\n }\n\n if (speed != null) {\n warnings.push({\n type: 'unsupported-setting',\n setting: 'speed',\n details: `Speed is not supported by this speech endpoint.`,\n });\n }\n\n if (language != null) {\n warnings.push({\n type: 'unsupported-setting',\n setting: 'language',\n details: `Language selection is not supported by this speech endpoint.`,\n });\n }\n\n const runpodProviderOptions = isRecord(providerOptions)\n ? (providerOptions as any).runpod\n : undefined;\n\n const voiceUrl =\n isRecord(runpodProviderOptions) &&\n (typeof runpodProviderOptions.voice_url === 'string' ||\n typeof runpodProviderOptions.voiceUrl === 'string')\n ? (runpodProviderOptions.voice_url ??\n runpodProviderOptions.voiceUrl ??\n undefined)\n : undefined;\n\n const input: Record<string, unknown> = {\n prompt: replaceNewlinesWithSpaces(text),\n };\n\n // The endpoint supports either a built-in voice name or a voice_url prompt.\n if (voiceUrl) {\n input.voice_url = voiceUrl;\n } else if (voice) {\n input.voice = voice;\n }\n\n const requestBody = { input };\n const url = this.getRunpodRunSyncUrl();\n\n const fetchFn = this.config.fetch ?? fetch;\n\n const requestHeaders: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...this.config.headers(),\n };\n\n if (headers) {\n for (const [key, value] of Object.entries(headers)) {\n if (value != null) {\n requestHeaders[key] = value;\n }\n }\n }\n\n const response = await fetchFn(url, {\n method: 'POST',\n headers: requestHeaders,\n body: JSON.stringify(requestBody),\n signal: abortSignal,\n });\n\n const responseHeaders = Object.fromEntries(response.headers.entries());\n const rawBodyText = await response.text();\n\n let parsed: any = undefined;\n try {\n parsed = rawBodyText ? JSON.parse(rawBodyText) : undefined;\n } catch {\n // ignore - we'll surface the raw body in the error below\n }\n\n if (!response.ok) {\n const message =\n (parsed && typeof parsed.error === 'string' && parsed.error) ||\n rawBodyText ||\n `HTTP ${response.status}`;\n throw new Error(`Runpod speech request failed: ${message}`);\n }\n\n const output = parsed?.output ?? parsed;\n\n const audioUrl = output?.audio_url;\n if (typeof audioUrl !== 'string' || audioUrl.length === 0) {\n throw new Error('Runpod speech response did not include an audio_url.');\n }\n\n const audioResponse = await fetchFn(audioUrl, { signal: abortSignal });\n if (!audioResponse.ok) {\n throw new Error(\n `Failed to download generated audio (${audioResponse.status}).`\n );\n }\n\n const audio = new Uint8Array(await audioResponse.arrayBuffer());\n\n const providerMetadata: Record<string, Record<string, JSONValue>> = {\n runpod: {\n audioUrl,\n ...(typeof output?.cost === 'number' ? { cost: output.cost } : {}),\n },\n };\n\n return {\n audio,\n warnings,\n request: {\n body: JSON.stringify(requestBody),\n },\n response: {\n timestamp: currentDate,\n modelId: this.modelId,\n headers: responseHeaders as any,\n body: rawBodyText,\n },\n providerMetadata,\n };\n }\n}\n"],"mappings":"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","names":["import_provider_utils","import_provider_utils","import_zod","import_provider_utils"]}
package/dist/index.mjs CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  } from "@ai-sdk/openai-compatible";
6
6
  import {
7
7
  loadApiKey,
8
- withoutTrailingSlash
8
+ withoutTrailingSlash as withoutTrailingSlash2
9
9
  } from "@ai-sdk/provider-utils";
10
10
 
11
11
  // src/runpod-image-model.ts
@@ -292,7 +292,7 @@ var RunpodImageModel = class {
292
292
  if (isPrunaEdit) {
293
293
  const editPayload = {
294
294
  prompt,
295
- aspect_ratio: runpodOptions?.aspect_ratio ?? aspectRatio ?? "match_input_image",
295
+ aspect_ratio: runpodOptions?.aspect_ratio ?? aspectRatio ?? "1:1",
296
296
  disable_safety_checker: runpodOptions?.disable_safety_checker ?? false
297
297
  };
298
298
  if (seed !== void 0) {
@@ -377,6 +377,148 @@ var runpodImageStatusSchema = z2.object({
377
377
  // Error message if FAILED
378
378
  });
379
379
 
380
+ // src/runpod-speech-model.ts
381
+ import { withoutTrailingSlash } from "@ai-sdk/provider-utils";
382
+ function isRecord(value) {
383
+ return typeof value === "object" && value !== null;
384
+ }
385
+ function replaceNewlinesWithSpaces(value) {
386
+ return value.replace(/[\r\n]+/g, " ");
387
+ }
388
+ var RunpodSpeechModel = class {
389
+ constructor(modelId, config) {
390
+ this.modelId = modelId;
391
+ this.config = config;
392
+ this.specificationVersion = "v2";
393
+ }
394
+ get provider() {
395
+ return this.config.provider;
396
+ }
397
+ getRunpodRunSyncUrl() {
398
+ const baseURL = withoutTrailingSlash(this.config.baseURL) ?? this.config.baseURL;
399
+ if (baseURL.endsWith("/run") || baseURL.endsWith("/runsync")) {
400
+ return baseURL;
401
+ }
402
+ return `${baseURL}/runsync`;
403
+ }
404
+ async doGenerate(options) {
405
+ const currentDate = this.config._internal?.currentDate?.() ?? /* @__PURE__ */ new Date();
406
+ const warnings = [];
407
+ const {
408
+ text,
409
+ voice,
410
+ outputFormat,
411
+ instructions,
412
+ speed,
413
+ language,
414
+ providerOptions,
415
+ abortSignal,
416
+ headers
417
+ } = options;
418
+ if (outputFormat != null && outputFormat !== "wav") {
419
+ warnings.push({
420
+ type: "unsupported-setting",
421
+ setting: "outputFormat",
422
+ details: `Unsupported outputFormat: ${outputFormat}. This endpoint returns 'wav'.`
423
+ });
424
+ }
425
+ if (instructions != null) {
426
+ warnings.push({
427
+ type: "unsupported-setting",
428
+ setting: "instructions",
429
+ details: `Instructions are not supported by this speech endpoint.`
430
+ });
431
+ }
432
+ if (speed != null) {
433
+ warnings.push({
434
+ type: "unsupported-setting",
435
+ setting: "speed",
436
+ details: `Speed is not supported by this speech endpoint.`
437
+ });
438
+ }
439
+ if (language != null) {
440
+ warnings.push({
441
+ type: "unsupported-setting",
442
+ setting: "language",
443
+ details: `Language selection is not supported by this speech endpoint.`
444
+ });
445
+ }
446
+ const runpodProviderOptions = isRecord(providerOptions) ? providerOptions.runpod : void 0;
447
+ const voiceUrl = isRecord(runpodProviderOptions) && (typeof runpodProviderOptions.voice_url === "string" || typeof runpodProviderOptions.voiceUrl === "string") ? runpodProviderOptions.voice_url ?? runpodProviderOptions.voiceUrl ?? void 0 : void 0;
448
+ const input = {
449
+ prompt: replaceNewlinesWithSpaces(text)
450
+ };
451
+ if (voiceUrl) {
452
+ input.voice_url = voiceUrl;
453
+ } else if (voice) {
454
+ input.voice = voice;
455
+ }
456
+ const requestBody = { input };
457
+ const url = this.getRunpodRunSyncUrl();
458
+ const fetchFn = this.config.fetch ?? fetch;
459
+ const requestHeaders = {
460
+ "Content-Type": "application/json",
461
+ ...this.config.headers()
462
+ };
463
+ if (headers) {
464
+ for (const [key, value] of Object.entries(headers)) {
465
+ if (value != null) {
466
+ requestHeaders[key] = value;
467
+ }
468
+ }
469
+ }
470
+ const response = await fetchFn(url, {
471
+ method: "POST",
472
+ headers: requestHeaders,
473
+ body: JSON.stringify(requestBody),
474
+ signal: abortSignal
475
+ });
476
+ const responseHeaders = Object.fromEntries(response.headers.entries());
477
+ const rawBodyText = await response.text();
478
+ let parsed = void 0;
479
+ try {
480
+ parsed = rawBodyText ? JSON.parse(rawBodyText) : void 0;
481
+ } catch {
482
+ }
483
+ if (!response.ok) {
484
+ const message = parsed && typeof parsed.error === "string" && parsed.error || rawBodyText || `HTTP ${response.status}`;
485
+ throw new Error(`Runpod speech request failed: ${message}`);
486
+ }
487
+ const output = parsed?.output ?? parsed;
488
+ const audioUrl = output?.audio_url;
489
+ if (typeof audioUrl !== "string" || audioUrl.length === 0) {
490
+ throw new Error("Runpod speech response did not include an audio_url.");
491
+ }
492
+ const audioResponse = await fetchFn(audioUrl, { signal: abortSignal });
493
+ if (!audioResponse.ok) {
494
+ throw new Error(
495
+ `Failed to download generated audio (${audioResponse.status}).`
496
+ );
497
+ }
498
+ const audio = new Uint8Array(await audioResponse.arrayBuffer());
499
+ const providerMetadata = {
500
+ runpod: {
501
+ audioUrl,
502
+ ...typeof output?.cost === "number" ? { cost: output.cost } : {}
503
+ }
504
+ };
505
+ return {
506
+ audio,
507
+ warnings,
508
+ request: {
509
+ body: JSON.stringify(requestBody)
510
+ },
511
+ response: {
512
+ timestamp: currentDate,
513
+ modelId: this.modelId,
514
+ headers: responseHeaders,
515
+ body: rawBodyText
516
+ },
517
+ providerMetadata
518
+ };
519
+ }
520
+ };
521
+
380
522
  // src/runpod-provider.ts
381
523
  var MODEL_ID_TO_ENDPOINT_URL = {
382
524
  "qwen/qwen3-32b-awq": "https://api.runpod.ai/v2/qwen3-32b-awq/openai/v1",
@@ -404,6 +546,9 @@ var IMAGE_MODEL_ID_TO_ENDPOINT_URL = {
404
546
  "pruna/p-image-t2i": "https://api.runpod.ai/v2/p-image-t2i",
405
547
  "pruna/p-image-edit": "https://api.runpod.ai/v2/p-image-edit"
406
548
  };
549
+ var SPEECH_MODEL_ID_TO_ENDPOINT_URL = {
550
+ "resembleai/chatterbox-turbo": "https://api.runpod.ai/v2/chatterbox-turbo/"
551
+ };
407
552
  var MODEL_ID_TO_OPENAI_NAME = {
408
553
  "qwen/qwen3-32b-awq": "Qwen/Qwen3-32B-AWQ",
409
554
  "deepcogito/cogito-671b-v2.1-fp8": "deepcogito/cogito-671b-v2.1-FP8",
@@ -413,6 +558,23 @@ function deriveEndpointURL(modelId) {
413
558
  const normalized = modelId.replace(/\//g, "-");
414
559
  return `https://api.runpod.ai/v2/${normalized}/openai/v1`;
415
560
  }
561
+ function parseRunpodConsoleEndpointId(modelIdOrUrl) {
562
+ if (!modelIdOrUrl.startsWith("http")) {
563
+ return null;
564
+ }
565
+ try {
566
+ const url = new URL(modelIdOrUrl);
567
+ if (url.hostname !== "console.runpod.io") {
568
+ return null;
569
+ }
570
+ const parts = url.pathname.split("/").filter(Boolean);
571
+ const idx = parts.lastIndexOf("endpoint");
572
+ const endpointId = idx !== -1 ? parts[idx + 1] : void 0;
573
+ return endpointId || null;
574
+ } catch {
575
+ return null;
576
+ }
577
+ }
416
578
  function createRunpod(options = {}) {
417
579
  const getHeaders = () => ({
418
580
  Authorization: `Bearer ${loadApiKey({
@@ -445,7 +607,7 @@ function createRunpod(options = {}) {
445
607
  }
446
608
  return {
447
609
  provider: `runpod.${modelType}`,
448
- url: ({ path }) => `${withoutTrailingSlash(baseURL)}${path}`,
610
+ url: ({ path }) => `${withoutTrailingSlash2(baseURL)}${path}`,
449
611
  headers: getHeaders,
450
612
  fetch: runpodFetch
451
613
  };
@@ -478,11 +640,25 @@ function createRunpod(options = {}) {
478
640
  fetch: options.fetch
479
641
  });
480
642
  };
643
+ const createSpeechModel = (modelId) => {
644
+ const endpointIdFromConsole = parseRunpodConsoleEndpointId(modelId);
645
+ const normalizedModelId = endpointIdFromConsole ?? modelId;
646
+ const mappedBaseURL = SPEECH_MODEL_ID_TO_ENDPOINT_URL[normalizedModelId];
647
+ const baseURL = mappedBaseURL ?? (normalizedModelId.startsWith("http") ? normalizedModelId : `https://api.runpod.ai/v2/${normalizedModelId}`);
648
+ return new RunpodSpeechModel(normalizedModelId, {
649
+ provider: "runpod.speech",
650
+ baseURL,
651
+ headers: getHeaders,
652
+ fetch: runpodFetch
653
+ });
654
+ };
481
655
  const provider = (modelId) => createChatModel(modelId);
482
656
  provider.completionModel = createCompletionModel;
483
657
  provider.languageModel = createChatModel;
484
658
  provider.chatModel = createChatModel;
485
659
  provider.imageModel = createImageModel;
660
+ provider.speechModel = createSpeechModel;
661
+ provider.speech = createSpeechModel;
486
662
  return provider;
487
663
  }
488
664
  var runpod = createRunpod();
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/runpod-provider.ts","../src/runpod-image-model.ts","../src/runpod-error.ts"],"sourcesContent":["import { LanguageModelV2, ImageModelV2 } from '@ai-sdk/provider';\nimport {\n OpenAICompatibleChatLanguageModel,\n OpenAICompatibleCompletionLanguageModel,\n} from '@ai-sdk/openai-compatible';\nimport {\n FetchFunction,\n loadApiKey,\n withoutTrailingSlash,\n} from '@ai-sdk/provider-utils';\nimport { RunpodImageModel } from './runpod-image-model';\n\nexport interface RunpodProviderSettings {\n /**\nRunpod API key.\n*/\n apiKey?: string;\n /**\nCustom base URL for Runpod API. Use this to point to custom endpoints or different Runpod deployments.\nExample: 'https://api.runpod.ai/v2/your-endpoint-id/openai/v1'\n*/\n baseURL?: string;\n /**\nCustom headers to include in the requests.\n*/\n headers?: Record<string, string>;\n /**\nCustom fetch implementation. You can use it as a middleware to intercept requests,\nor to provide a custom fetch implementation for e.g. testing.\n*/\n fetch?: FetchFunction;\n}\n\nexport interface RunpodProvider {\n /**\nCreates a model for text generation.\n*/\n (modelId: string): LanguageModelV2;\n\n /**\nCreates a chat model for text generation.\n*/\n chatModel(modelId: string): LanguageModelV2;\n\n /**\nCreates a chat model for text generation.\n*/\n languageModel(modelId: string): LanguageModelV2;\n\n /**\nCreates a completion model for text generation.\n*/\n completionModel(modelId: string): LanguageModelV2;\n\n /**\nCreates an image model for image generation.\n*/\n imageModel(modelId: string): ImageModelV2;\n}\n\n// Mapping of Runpod model IDs to their endpoint URLs\nconst MODEL_ID_TO_ENDPOINT_URL: Record<string, string> = {\n 'qwen/qwen3-32b-awq': 'https://api.runpod.ai/v2/qwen3-32b-awq/openai/v1',\n 'ibm-granite/granite-4.0-h-small': 'https://api.runpod.ai/v2/granite-4-0-h-small/openai/v1',\n 'gpt-oss-120b': 'https://api.runpod.ai/v2/gpt-oss-120b/openai/v1',\n 'openai/gpt-oss-120b': 'https://api.runpod.ai/v2/gpt-oss-120b/openai/v1',\n 'deepcogito/cogito-671b-v2.1-fp8': 'https://api.runpod.ai/v2/cogito-671b-v2-1-fp8-dynamic/openai/v1',\n 'deepcogito/cogito-671b-v2.1-FP8': 'https://api.runpod.ai/v2/cogito-671b-v2-1-fp8-dynamic/openai/v1',\n};\n\n// Mapping of Runpod image model IDs to their endpoint URLs\nconst IMAGE_MODEL_ID_TO_ENDPOINT_URL: Record<string, string> = {\n 'qwen/qwen-image': 'https://api.runpod.ai/v2/qwen-image-t2i',\n 'qwen/qwen-image-edit': 'https://api.runpod.ai/v2/qwen-image-edit',\n 'bytedance/seedream-3.0': 'https://api.runpod.ai/v2/seedream-3-0-t2i',\n // Seadream v4 (t2i and edit)\n 'bytedance/seedream-4.0': 'https://api.runpod.ai/v2/seedream-v4-t2i',\n 'bytedance/seedream-4.0-edit': 'https://api.runpod.ai/v2/seedream-v4-edit',\n 'black-forest-labs/flux-1-kontext-dev':\n 'https://api.runpod.ai/v2/black-forest-labs-flux-1-kontext-dev',\n 'black-forest-labs/flux-1-schnell':\n 'https://api.runpod.ai/v2/black-forest-labs-flux-1-schnell',\n 'black-forest-labs/flux-1-dev':\n 'https://api.runpod.ai/v2/black-forest-labs-flux-1-dev',\n // Nano Banana (edit only)\n 'nano-banana-edit': 'https://api.runpod.ai/v2/nano-banana-edit',\n // Nano Banana Pro (edit only)\n 'google/nano-banana-pro-edit': 'https://api.runpod.ai/v2/nano-banana-pro-edit',\n // Pruna (t2i and edit)\n 'pruna/p-image-t2i': 'https://api.runpod.ai/v2/p-image-t2i',\n 'pruna/p-image-edit': 'https://api.runpod.ai/v2/p-image-edit',\n};\n\n// Mapping of Runpod model IDs to their OpenAI model names\nconst MODEL_ID_TO_OPENAI_NAME: Record<string, string> = {\n 'qwen/qwen3-32b-awq': 'Qwen/Qwen3-32B-AWQ',\n 'deepcogito/cogito-671b-v2.1-fp8': 'deepcogito/cogito-671b-v2.1-FP8',\n 'deepcogito/cogito-671b-v2.1-FP8': 'deepcogito/cogito-671b-v2.1-FP8',\n};\n\n/**\n * Derives the endpoint URL for a model by replacing slashes with hyphens.\n * Example: 'ibm-granite/granite-4.0-h-small' -> 'https://api.runpod.ai/v2/ibm-granite-granite-4.0-h-small/openai/v1'\n */\nfunction deriveEndpointURL(modelId: string): string {\n const normalized = modelId.replace(/\\//g, '-');\n return `https://api.runpod.ai/v2/${normalized}/openai/v1`;\n}\n\nexport function createRunpod(\n options: RunpodProviderSettings = {}\n): RunpodProvider {\n const getHeaders = () => ({\n Authorization: `Bearer ${loadApiKey({\n apiKey: options.apiKey,\n environmentVariableName: 'RUNPOD_API_KEY',\n description: 'Runpod',\n })}`,\n ...options.headers,\n });\n\n const runpodFetch: FetchFunction = async (url, requestInit) => {\n if (requestInit?.body) {\n try {\n const body = JSON.parse(requestInit.body as string);\n if (body.stream === true && !body.stream_options) {\n body.stream_options = { include_usage: true };\n requestInit.body = JSON.stringify(body);\n }\n } catch {}\n }\n const fetchFn = options.fetch || fetch;\n return fetchFn(url, requestInit);\n };\n\n interface CommonModelConfig {\n provider: string;\n url: ({ path }: { path: string }) => string;\n headers: () => Record<string, string>;\n fetch?: FetchFunction;\n }\n\n const getModelConfig = (\n modelId: string,\n modelType: string\n ): CommonModelConfig => {\n let baseURL: string;\n\n if (options.baseURL) {\n baseURL = options.baseURL;\n } else {\n // Use hardcoded mapping if available, otherwise derive endpoint\n baseURL = MODEL_ID_TO_ENDPOINT_URL[modelId] || deriveEndpointURL(modelId);\n }\n\n return {\n provider: `runpod.${modelType}`,\n url: ({ path }) => `${withoutTrailingSlash(baseURL)}${path}`,\n headers: getHeaders,\n fetch: runpodFetch,\n };\n };\n\n const createChatModel = (modelId: string) => {\n const openaiModelName = MODEL_ID_TO_OPENAI_NAME[modelId] || modelId;\n return new OpenAICompatibleChatLanguageModel(openaiModelName, {\n ...getModelConfig(modelId, 'chat'),\n includeUsage: true,\n });\n };\n\n const createCompletionModel = (modelId: string) => {\n const openaiModelName = MODEL_ID_TO_OPENAI_NAME[modelId] || modelId;\n return new OpenAICompatibleCompletionLanguageModel(openaiModelName, {\n ...getModelConfig(modelId, 'completion'),\n includeUsage: true,\n });\n };\n\n const createImageModel = (modelId: string) => {\n let baseURL: string;\n\n if (options.baseURL) {\n baseURL = options.baseURL;\n } else {\n // Use hardcoded mapping if available, otherwise derive endpoint\n baseURL =\n IMAGE_MODEL_ID_TO_ENDPOINT_URL[modelId] || deriveEndpointURL(modelId);\n }\n\n return new RunpodImageModel(modelId, {\n provider: 'runpod.image',\n baseURL,\n headers: getHeaders,\n fetch: options.fetch,\n });\n };\n\n const provider = (modelId: string) => createChatModel(modelId);\n\n provider.completionModel = createCompletionModel;\n provider.languageModel = createChatModel;\n provider.chatModel = createChatModel;\n provider.imageModel = createImageModel;\n\n return provider;\n}\n\nexport const runpod = createRunpod();\n","import { ImageModelV2, ImageModelV2CallWarning } from '@ai-sdk/provider';\nimport {\n combineHeaders,\n createJsonResponseHandler,\n createBinaryResponseHandler,\n FetchFunction,\n postJsonToApi,\n getFromApi,\n} from '@ai-sdk/provider-utils';\nimport { InvalidArgumentError } from '@ai-sdk/provider';\nimport { z } from 'zod';\nimport { runpodImageFailedResponseHandler } from './runpod-error';\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\ninterface RunpodImageModelConfig {\n provider: string;\n baseURL: string;\n headers: () => Record<string, string>;\n fetch?: FetchFunction;\n _internal?: {\n currentDate?: () => Date;\n };\n}\n\n// Runpod supported aspect ratios (only validated working sizes)\nconst SUPPORTED_ASPECT_RATIOS: Record<string, string> = {\n '1:1': '1328*1328', // ✅ Native support\n '4:3': '1472*1140', // ✅ Native support\n '3:4': '1140*1472', // ✅ Native support\n};\n\n// Runpod supported sizes (validated working sizes)\nconst SUPPORTED_SIZES = new Set([\n // Native aspect ratio sizes\n '1328*1328', // 1:1\n '1472*1140', // 4:3\n '1140*1472', // 3:4\n // Additional validated sizes\n '512*512',\n '768*768',\n '1024*1024',\n '1536*1536',\n '2048*2048',\n '4096*4096',\n '512*768',\n '768*512',\n '1024*768',\n '768*1024',\n]);\n\nexport class RunpodImageModel implements ImageModelV2 {\n readonly specificationVersion = 'v2';\n readonly maxImagesPerCall = 1;\n\n get provider(): string {\n return this.config.provider;\n }\n\n constructor(\n readonly modelId: string,\n private config: RunpodImageModelConfig\n ) {}\n\n async doGenerate({\n prompt,\n n = 1,\n size,\n aspectRatio,\n seed,\n providerOptions,\n headers,\n abortSignal,\n }: Parameters<ImageModelV2['doGenerate']>[0]): Promise<\n Awaited<ReturnType<ImageModelV2['doGenerate']>>\n > {\n const warnings: Array<ImageModelV2CallWarning> = [];\n\n // Check if this is a Pruna model (skip standard size/aspectRatio validation)\n const isPrunaModel =\n this.modelId.includes('pruna') || this.modelId.includes('p-image');\n\n // Check if this is a Nano Banana Pro model (skip standard size/aspectRatio validation)\n const isNanoBananaProModel = this.modelId.includes('nano-banana-pro');\n\n // Determine the size to use\n let runpodSize: string;\n\n if (isPrunaModel || isNanoBananaProModel) {\n // These models use aspect_ratio string directly, skip size validation\n // Pass through the aspectRatio or use default, validation happens at API level\n runpodSize = aspectRatio || '1:1';\n } else if (size) {\n // Convert AI SDK format \"1328x1328\" to Runpod format \"1328*1328\"\n const runpodSizeCandidate = size.replace('x', '*');\n\n // Validate size is supported\n if (!SUPPORTED_SIZES.has(runpodSizeCandidate)) {\n throw new InvalidArgumentError({\n argument: 'size',\n message: `Size ${size} is not supported by Runpod. Supported sizes: ${Array.from(\n SUPPORTED_SIZES\n )\n .map((s) => s.replace('*', 'x'))\n .join(', ')}`,\n });\n }\n\n runpodSize = runpodSizeCandidate;\n } else if (aspectRatio) {\n // Validate aspect ratio is supported\n if (!SUPPORTED_ASPECT_RATIOS[aspectRatio]) {\n throw new InvalidArgumentError({\n argument: 'aspectRatio',\n message: `Aspect ratio ${aspectRatio} is not supported by Runpod. Supported aspect ratios: ${Object.keys(SUPPORTED_ASPECT_RATIOS).join(', ')}`,\n });\n }\n\n // Use supported aspect ratio mapping\n runpodSize = SUPPORTED_ASPECT_RATIOS[aspectRatio];\n } else {\n // Default to square format\n runpodSize = '1328*1328';\n }\n\n // Handle multiple images warning\n if (n > 1) {\n warnings.push({\n type: 'unsupported-setting',\n setting: 'n',\n details:\n 'Runpod image models only support generating 1 image at a time. Using n=1.',\n });\n }\n\n const currentDate = this.config._internal?.currentDate?.() ?? new Date();\n\n // Runpod uses a different request format - /runsync endpoint with input wrapper\n const inputPayload = this.buildInputPayload(\n prompt,\n runpodSize,\n seed,\n providerOptions.runpod,\n aspectRatio\n );\n\n const { value: response, responseHeaders } = await postJsonToApi({\n url: `${this.config.baseURL}/runsync`,\n headers: combineHeaders(this.config.headers(), headers),\n body: {\n input: inputPayload,\n },\n failedResponseHandler: runpodImageFailedResponseHandler,\n successfulResponseHandler: createJsonResponseHandler(\n runpodImageResponseSchema as any\n ),\n abortSignal,\n fetch: this.config.fetch,\n });\n\n // Handle both sync and async responses from Runpod\n const typedResponse = response as any;\n if (\n typedResponse.status === 'COMPLETED' &&\n (typedResponse.output?.result || typedResponse.output?.image_url)\n ) {\n // Sync response - image is ready\n // Different models use different response formats: result vs image_url\n const imageUrl =\n typedResponse.output.result || typedResponse.output.image_url;\n const imageData = await this.downloadImage(imageUrl, abortSignal);\n\n return {\n images: [imageData],\n warnings,\n response: {\n timestamp: currentDate,\n modelId: this.modelId,\n headers: responseHeaders,\n },\n providerMetadata: {\n runpod: {\n images: [\n {\n url: imageUrl,\n cost: typedResponse.output?.cost,\n },\n ],\n },\n },\n };\n } else if (\n typedResponse.status === 'IN_QUEUE' ||\n typedResponse.status === 'IN_PROGRESS'\n ) {\n // Async response - need to poll for completion\n const pollOptions = {\n maxAttempts: providerOptions.runpod?.maxPollAttempts as number,\n pollIntervalMillis: providerOptions.runpod\n ?.pollIntervalMillis as number,\n };\n const imageUrl = await this.pollForCompletion(\n typedResponse.id,\n abortSignal,\n pollOptions\n );\n const imageData = await this.downloadImage(imageUrl, abortSignal);\n\n return {\n images: [imageData],\n warnings,\n response: {\n timestamp: currentDate,\n modelId: this.modelId,\n headers: responseHeaders,\n },\n providerMetadata: {\n runpod: {\n images: [\n {\n url: imageUrl,\n jobId: typedResponse.id,\n },\n ],\n },\n },\n };\n } else {\n throw new Error(`Unexpected response status: ${typedResponse.status}`);\n }\n }\n\n private async downloadImage(\n imageUrl: string,\n abortSignal?: AbortSignal\n ): Promise<Uint8Array> {\n const { value: imageData } = await getFromApi({\n url: imageUrl,\n successfulResponseHandler: createBinaryResponseHandler(),\n failedResponseHandler: runpodImageFailedResponseHandler,\n abortSignal,\n fetch: this.config.fetch,\n });\n return imageData;\n }\n\n private async pollForCompletion(\n jobId: string,\n abortSignal?: AbortSignal,\n pollOptions?: { maxAttempts?: number; pollIntervalMillis?: number }\n ): Promise<string> {\n const maxAttempts = pollOptions?.maxAttempts ?? 60; // 5 minutes with 5-second intervals\n const pollInterval = pollOptions?.pollIntervalMillis ?? 5000; // 5 seconds\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n if (abortSignal?.aborted) {\n throw new Error('Image generation was aborted');\n }\n\n const { value: statusResponse } = await getFromApi({\n url: `${this.config.baseURL}/status/${jobId}`,\n headers: this.config.headers(),\n successfulResponseHandler: createJsonResponseHandler(\n runpodImageStatusSchema as any\n ),\n failedResponseHandler: runpodImageFailedResponseHandler,\n abortSignal,\n fetch: this.config.fetch,\n });\n\n const typedStatusResponse = statusResponse as any;\n if (\n typedStatusResponse.status === 'COMPLETED' &&\n (typedStatusResponse.output?.result ||\n typedStatusResponse.output?.image_url)\n ) {\n return (\n typedStatusResponse.output.result ||\n typedStatusResponse.output.image_url\n );\n }\n\n if (typedStatusResponse.status === 'FAILED') {\n throw new Error(\n `Image generation failed: ${typedStatusResponse.error || 'Unknown error'}`\n );\n }\n\n // Wait before next poll\n await new Promise((resolve) => setTimeout(resolve, pollInterval));\n }\n\n throw new Error(\n `Image generation timed out after ${maxAttempts} attempts (${(maxAttempts * pollInterval) / 1000}s)`\n );\n }\n\n private buildInputPayload(\n prompt: string,\n runpodSize: string,\n seed?: number,\n runpodOptions?: Record<string, unknown>,\n aspectRatio?: string\n ): Record<string, unknown> {\n // Check if this is a Flux model that uses different parameters\n const isFluxModel =\n this.modelId.includes('flux') ||\n this.modelId.includes('black-forest-labs');\n\n if (isFluxModel) {\n // Check if this is Flux Kontext (uses different parameters)\n const isKontext = this.modelId.includes('kontext');\n\n if (isKontext) {\n // Flux Kontext uses size format and has image input\n return {\n prompt,\n negative_prompt: runpodOptions?.negative_prompt ?? '',\n seed: seed ?? -1,\n num_inference_steps: 28,\n guidance: 2,\n size: runpodSize,\n output_format: 'png',\n enable_safety_checker: runpodOptions?.enable_safety_checker ?? true,\n ...runpodOptions, // This will include the 'image' parameter if provided\n };\n } else {\n // Regular Flux models use width/height\n const [width, height] = runpodSize.split('*').map(Number);\n\n return {\n prompt,\n negative_prompt: runpodOptions?.negative_prompt ?? '',\n seed: seed ?? -1,\n num_inference_steps: this.modelId.includes('schnell') ? 4 : 28,\n guidance: this.modelId.includes('schnell') ? 7 : 2,\n width,\n height,\n image_format: 'png',\n ...runpodOptions,\n };\n }\n }\n\n // Check if this is a Pruna model\n const isPrunaModel =\n this.modelId.includes('pruna') || this.modelId.includes('p-image');\n if (isPrunaModel) {\n const isPrunaEdit = this.modelId.includes('edit');\n\n if (isPrunaEdit) {\n // Pruna image edit\n // Supported aspect_ratio: \"match_input_image\", \"1:1\", \"16:9\", \"9:16\", \"4:3\", \"3:4\", \"3:2\", \"2:3\"\n // Supports 1-5 images via providerOptions.runpod.images\n const editPayload: Record<string, unknown> = {\n prompt,\n aspect_ratio:\n (runpodOptions?.aspect_ratio as string) ??\n aspectRatio ??\n 'match_input_image',\n disable_safety_checker:\n (runpodOptions?.disable_safety_checker as boolean) ?? false,\n };\n\n // Add seed if provided\n if (seed !== undefined) {\n editPayload.seed = seed;\n } else if (runpodOptions?.seed !== undefined) {\n editPayload.seed = runpodOptions.seed;\n }\n\n // Add images array (required, 1-5 images)\n if (runpodOptions?.images) {\n editPayload.images = runpodOptions.images;\n }\n\n return editPayload;\n } else {\n // Pruna text-to-image\n // Supported aspect_ratio: \"1:1\", \"16:9\", \"9:16\", \"4:3\", \"3:4\", \"3:2\", \"2:3\", \"custom\"\n // For custom: width/height 256-1440, must be multiple of 16\n const t2iPayload: Record<string, unknown> = {\n prompt,\n aspect_ratio:\n (runpodOptions?.aspect_ratio as string) ?? aspectRatio ?? '1:1',\n disable_safety_checker:\n (runpodOptions?.disable_safety_checker as boolean) ?? false,\n };\n\n // Add seed if provided\n if (seed !== undefined) {\n t2iPayload.seed = seed;\n } else if (runpodOptions?.seed !== undefined) {\n t2iPayload.seed = runpodOptions.seed;\n }\n\n // Handle custom aspect ratio with width/height\n if (t2iPayload.aspect_ratio === 'custom') {\n if (runpodOptions?.width) {\n t2iPayload.width = runpodOptions.width;\n }\n if (runpodOptions?.height) {\n t2iPayload.height = runpodOptions.height;\n }\n }\n\n return t2iPayload;\n }\n }\n\n // Check if this is a Nano Banana Pro model (google/nano-banana-pro-edit)\n const isNanaBananaProModel = this.modelId.includes('nano-banana-pro');\n if (isNanaBananaProModel) {\n // Nano Banana Pro image edit\n // Supported aspect_ratio: \"1:1\", \"16:9\", \"9:16\", \"4:3\", \"3:4\", \"3:2\", \"2:3\", \"21:9\", \"9:21\"\n // Supported resolution: \"1k\", \"2k\", \"4k\"\n // Supported output_format: \"jpeg\", \"png\", \"webp\"\n const nanoBananaPayload: Record<string, unknown> = {\n prompt,\n aspect_ratio:\n (runpodOptions?.aspect_ratio as string) ?? aspectRatio ?? '1:1',\n resolution: (runpodOptions?.resolution as string) ?? '1k',\n output_format: (runpodOptions?.output_format as string) ?? 'jpeg',\n enable_base64_output:\n (runpodOptions?.enable_base64_output as boolean) ?? false,\n enable_sync_mode:\n (runpodOptions?.enable_sync_mode as boolean) ?? false,\n };\n\n // Add images array (required)\n if (runpodOptions?.images) {\n nanoBananaPayload.images = runpodOptions.images;\n }\n\n return nanoBananaPayload;\n }\n\n // Default format for Qwen and other models\n return {\n prompt,\n negative_prompt: runpodOptions?.negative_prompt ?? '',\n size: runpodSize,\n seed: seed ?? -1,\n enable_safety_checker: runpodOptions?.enable_safety_checker ?? true,\n ...runpodOptions,\n };\n }\n}\n\n// Runpod image API response schema (handles both sync and async responses)\nconst runpodImageResponseSchema = z.object({\n id: z.string(),\n status: z.enum(['COMPLETED', 'IN_QUEUE', 'IN_PROGRESS', 'FAILED']),\n delayTime: z.number().optional(),\n executionTime: z.number().optional(),\n output: z\n .object({\n cost: z.number().optional(),\n result: z.string().optional(), // URL to the generated image (Qwen format)\n image_url: z.string().optional(), // URL to the generated image (Flux format)\n })\n .optional(), // Optional for IN_QUEUE/IN_PROGRESS responses\n});\n\n// Schema for polling status endpoint\nconst runpodImageStatusSchema = z.object({\n id: z.string(),\n status: z.enum(['COMPLETED', 'IN_QUEUE', 'IN_PROGRESS', 'FAILED']),\n output: z\n .object({\n cost: z.number().optional(),\n result: z.string().optional(),\n image_url: z.string().optional(),\n })\n .optional(),\n error: z.string().optional(), // Error message if FAILED\n});\n","import { z } from 'zod';\r\nimport { createJsonErrorResponseHandler } from '@ai-sdk/provider-utils';\r\n\r\n// Runpod image API error schema (supports both error formats)\r\nexport const runpodImageErrorSchema = z.object({\r\n error: z.string().optional(),\r\n message: z.string().optional(),\r\n});\r\n\r\nexport type RunpodImageErrorData = z.infer<typeof runpodImageErrorSchema>;\r\n\r\nexport const runpodImageFailedResponseHandler = createJsonErrorResponseHandler({\r\n errorSchema: runpodImageErrorSchema as any,\r\n errorToMessage: (data: RunpodImageErrorData) => {\r\n // Prefer message if available (more descriptive)\r\n if (data.message) {\r\n return data.message;\r\n }\r\n \r\n // If error field exists, try to extract nested JSON message\r\n if (data.error) {\r\n // Runpod sometimes returns nested JSON in the error field like:\r\n // \"Error submitting task: 400, {\\\"code\\\":400,\\\"message\\\":\\\"...\\\"}\"\r\n // Try to extract the inner message for cleaner error messages\r\n // Find the last occurrence of { which likely starts the JSON object\r\n const lastBraceIndex = data.error.lastIndexOf('{');\r\n if (lastBraceIndex !== -1) {\r\n try {\r\n const jsonStr = data.error.substring(lastBraceIndex);\r\n const nestedError = JSON.parse(jsonStr);\r\n if (nestedError.message && typeof nestedError.message === 'string') {\r\n return nestedError.message;\r\n }\r\n } catch {\r\n // If parsing fails, fall back to the original error string\r\n }\r\n }\r\n return data.error;\r\n }\r\n \r\n return 'Unknown Runpod error';\r\n },\r\n});\r\n\r\n"],"mappings":"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","names":["z","z"]}
1
+ {"version":3,"sources":["../src/runpod-provider.ts","../src/runpod-image-model.ts","../src/runpod-error.ts","../src/runpod-speech-model.ts"],"sourcesContent":["import { ImageModelV2, LanguageModelV2, SpeechModelV2 } from '@ai-sdk/provider';\nimport {\n OpenAICompatibleChatLanguageModel,\n OpenAICompatibleCompletionLanguageModel,\n} from '@ai-sdk/openai-compatible';\nimport {\n FetchFunction,\n loadApiKey,\n withoutTrailingSlash,\n} from '@ai-sdk/provider-utils';\nimport { RunpodImageModel } from './runpod-image-model';\nimport { RunpodSpeechModel } from './runpod-speech-model';\n\nexport interface RunpodProviderSettings {\n /**\nRunpod API key.\n*/\n apiKey?: string;\n /**\nCustom base URL for Runpod API. Use this to point to custom endpoints or different Runpod deployments.\nExample: 'https://api.runpod.ai/v2/your-endpoint-id/openai/v1'\n*/\n baseURL?: string;\n /**\nCustom headers to include in the requests.\n*/\n headers?: Record<string, string>;\n /**\nCustom fetch implementation. You can use it as a middleware to intercept requests,\nor to provide a custom fetch implementation for e.g. testing.\n*/\n fetch?: FetchFunction;\n}\n\nexport interface RunpodProvider {\n /**\nCreates a model for text generation.\n*/\n (modelId: string): LanguageModelV2;\n\n /**\nCreates a chat model for text generation.\n*/\n chatModel(modelId: string): LanguageModelV2;\n\n /**\nCreates a chat model for text generation.\n*/\n languageModel(modelId: string): LanguageModelV2;\n\n /**\nCreates a completion model for text generation.\n*/\n completionModel(modelId: string): LanguageModelV2;\n\n /**\nCreates an image model for image generation.\n*/\n imageModel(modelId: string): ImageModelV2;\n\n /**\nCreates a speech model for speech generation.\n*/\n speechModel(modelId: string): SpeechModelV2;\n\n /**\nCreates a speech model for speech generation.\n*/\n speech(modelId: string): SpeechModelV2;\n}\n\n// Mapping of Runpod model IDs to their endpoint URLs\nconst MODEL_ID_TO_ENDPOINT_URL: Record<string, string> = {\n 'qwen/qwen3-32b-awq': 'https://api.runpod.ai/v2/qwen3-32b-awq/openai/v1',\n 'ibm-granite/granite-4.0-h-small':\n 'https://api.runpod.ai/v2/granite-4-0-h-small/openai/v1',\n 'gpt-oss-120b': 'https://api.runpod.ai/v2/gpt-oss-120b/openai/v1',\n 'openai/gpt-oss-120b': 'https://api.runpod.ai/v2/gpt-oss-120b/openai/v1',\n 'deepcogito/cogito-671b-v2.1-fp8':\n 'https://api.runpod.ai/v2/cogito-671b-v2-1-fp8-dynamic/openai/v1',\n 'deepcogito/cogito-671b-v2.1-FP8':\n 'https://api.runpod.ai/v2/cogito-671b-v2-1-fp8-dynamic/openai/v1',\n};\n\n// Mapping of Runpod image model IDs to their endpoint URLs\nconst IMAGE_MODEL_ID_TO_ENDPOINT_URL: Record<string, string> = {\n 'qwen/qwen-image': 'https://api.runpod.ai/v2/qwen-image-t2i',\n 'qwen/qwen-image-edit': 'https://api.runpod.ai/v2/qwen-image-edit',\n 'bytedance/seedream-3.0': 'https://api.runpod.ai/v2/seedream-3-0-t2i',\n // Seadream v4 (t2i and edit)\n 'bytedance/seedream-4.0': 'https://api.runpod.ai/v2/seedream-v4-t2i',\n 'bytedance/seedream-4.0-edit': 'https://api.runpod.ai/v2/seedream-v4-edit',\n 'black-forest-labs/flux-1-kontext-dev':\n 'https://api.runpod.ai/v2/black-forest-labs-flux-1-kontext-dev',\n 'black-forest-labs/flux-1-schnell':\n 'https://api.runpod.ai/v2/black-forest-labs-flux-1-schnell',\n 'black-forest-labs/flux-1-dev':\n 'https://api.runpod.ai/v2/black-forest-labs-flux-1-dev',\n // Nano Banana (edit only)\n 'nano-banana-edit': 'https://api.runpod.ai/v2/nano-banana-edit',\n // Nano Banana Pro (edit only)\n 'google/nano-banana-pro-edit':\n 'https://api.runpod.ai/v2/nano-banana-pro-edit',\n // Pruna (t2i and edit)\n 'pruna/p-image-t2i': 'https://api.runpod.ai/v2/p-image-t2i',\n 'pruna/p-image-edit': 'https://api.runpod.ai/v2/p-image-edit',\n};\n\n// Mapping of Runpod speech model IDs to their serverless endpoint URLs\n// Note: This is intentionally a temporary mapping for a stealth release.\nconst SPEECH_MODEL_ID_TO_ENDPOINT_URL: Record<string, string> = {\n 'resembleai/chatterbox-turbo': 'https://api.runpod.ai/v2/chatterbox-turbo/',\n};\n\n// Mapping of Runpod model IDs to their OpenAI model names\nconst MODEL_ID_TO_OPENAI_NAME: Record<string, string> = {\n 'qwen/qwen3-32b-awq': 'Qwen/Qwen3-32B-AWQ',\n 'deepcogito/cogito-671b-v2.1-fp8': 'deepcogito/cogito-671b-v2.1-FP8',\n 'deepcogito/cogito-671b-v2.1-FP8': 'deepcogito/cogito-671b-v2.1-FP8',\n};\n\n/**\n * Derives the endpoint URL for a model by replacing slashes with hyphens.\n * Example: 'ibm-granite/granite-4.0-h-small' -> 'https://api.runpod.ai/v2/ibm-granite-granite-4.0-h-small/openai/v1'\n */\nfunction deriveEndpointURL(modelId: string): string {\n const normalized = modelId.replace(/\\//g, '-');\n return `https://api.runpod.ai/v2/${normalized}/openai/v1`;\n}\n\nfunction parseRunpodConsoleEndpointId(modelIdOrUrl: string): string | null {\n if (!modelIdOrUrl.startsWith('http')) {\n return null;\n }\n\n try {\n const url = new URL(modelIdOrUrl);\n if (url.hostname !== 'console.runpod.io') {\n return null;\n }\n\n // Example:\n // https://console.runpod.io/serverless/user/endpoint/<ENDPOINT_ID>\n const parts = url.pathname.split('/').filter(Boolean);\n const idx = parts.lastIndexOf('endpoint');\n const endpointId = idx !== -1 ? parts[idx + 1] : undefined;\n\n return endpointId || null;\n } catch {\n return null;\n }\n}\n\nexport function createRunpod(\n options: RunpodProviderSettings = {}\n): RunpodProvider {\n const getHeaders = () => ({\n Authorization: `Bearer ${loadApiKey({\n apiKey: options.apiKey,\n environmentVariableName: 'RUNPOD_API_KEY',\n description: 'Runpod',\n })}`,\n ...options.headers,\n });\n\n const runpodFetch: FetchFunction = async (url, requestInit) => {\n if (requestInit?.body) {\n try {\n const body = JSON.parse(requestInit.body as string);\n if (body.stream === true && !body.stream_options) {\n body.stream_options = { include_usage: true };\n requestInit.body = JSON.stringify(body);\n }\n } catch {}\n }\n const fetchFn = options.fetch || fetch;\n return fetchFn(url, requestInit);\n };\n\n interface CommonModelConfig {\n provider: string;\n url: ({ path }: { path: string }) => string;\n headers: () => Record<string, string>;\n fetch?: FetchFunction;\n }\n\n const getModelConfig = (\n modelId: string,\n modelType: string\n ): CommonModelConfig => {\n let baseURL: string;\n\n if (options.baseURL) {\n baseURL = options.baseURL;\n } else {\n // Use hardcoded mapping if available, otherwise derive endpoint\n baseURL = MODEL_ID_TO_ENDPOINT_URL[modelId] || deriveEndpointURL(modelId);\n }\n\n return {\n provider: `runpod.${modelType}`,\n url: ({ path }) => `${withoutTrailingSlash(baseURL)}${path}`,\n headers: getHeaders,\n fetch: runpodFetch,\n };\n };\n\n const createChatModel = (modelId: string) => {\n const openaiModelName = MODEL_ID_TO_OPENAI_NAME[modelId] || modelId;\n return new OpenAICompatibleChatLanguageModel(openaiModelName, {\n ...getModelConfig(modelId, 'chat'),\n includeUsage: true,\n });\n };\n\n const createCompletionModel = (modelId: string) => {\n const openaiModelName = MODEL_ID_TO_OPENAI_NAME[modelId] || modelId;\n return new OpenAICompatibleCompletionLanguageModel(openaiModelName, {\n ...getModelConfig(modelId, 'completion'),\n includeUsage: true,\n });\n };\n\n const createImageModel = (modelId: string) => {\n let baseURL: string;\n\n if (options.baseURL) {\n baseURL = options.baseURL;\n } else {\n // Use hardcoded mapping if available, otherwise derive endpoint\n baseURL =\n IMAGE_MODEL_ID_TO_ENDPOINT_URL[modelId] || deriveEndpointURL(modelId);\n }\n\n return new RunpodImageModel(modelId, {\n provider: 'runpod.image',\n baseURL,\n headers: getHeaders,\n fetch: options.fetch,\n });\n };\n\n const createSpeechModel = (modelId: string) => {\n const endpointIdFromConsole = parseRunpodConsoleEndpointId(modelId);\n const normalizedModelId = endpointIdFromConsole ?? modelId;\n\n // Prefer explicit mapping for known speech model IDs.\n const mappedBaseURL = SPEECH_MODEL_ID_TO_ENDPOINT_URL[normalizedModelId];\n\n const baseURL =\n mappedBaseURL ??\n (normalizedModelId.startsWith('http')\n ? normalizedModelId\n : `https://api.runpod.ai/v2/${normalizedModelId}`);\n\n return new RunpodSpeechModel(normalizedModelId, {\n provider: 'runpod.speech',\n baseURL,\n headers: getHeaders,\n fetch: runpodFetch,\n });\n };\n\n const provider = (modelId: string) => createChatModel(modelId);\n\n provider.completionModel = createCompletionModel;\n provider.languageModel = createChatModel;\n provider.chatModel = createChatModel;\n provider.imageModel = createImageModel;\n provider.speechModel = createSpeechModel;\n provider.speech = createSpeechModel;\n\n return provider;\n}\n\nexport const runpod = createRunpod();\n","import { ImageModelV2, ImageModelV2CallWarning } from '@ai-sdk/provider';\nimport {\n combineHeaders,\n createJsonResponseHandler,\n createBinaryResponseHandler,\n FetchFunction,\n postJsonToApi,\n getFromApi,\n} from '@ai-sdk/provider-utils';\nimport { InvalidArgumentError } from '@ai-sdk/provider';\nimport { z } from 'zod';\nimport { runpodImageFailedResponseHandler } from './runpod-error';\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\ninterface RunpodImageModelConfig {\n provider: string;\n baseURL: string;\n headers: () => Record<string, string>;\n fetch?: FetchFunction;\n _internal?: {\n currentDate?: () => Date;\n };\n}\n\n// Runpod supported aspect ratios (only validated working sizes)\nconst SUPPORTED_ASPECT_RATIOS: Record<string, string> = {\n '1:1': '1328*1328', // ✅ Native support\n '4:3': '1472*1140', // ✅ Native support\n '3:4': '1140*1472', // ✅ Native support\n};\n\n// Runpod supported sizes (validated working sizes)\nconst SUPPORTED_SIZES = new Set([\n // Native aspect ratio sizes\n '1328*1328', // 1:1\n '1472*1140', // 4:3\n '1140*1472', // 3:4\n // Additional validated sizes\n '512*512',\n '768*768',\n '1024*1024',\n '1536*1536',\n '2048*2048',\n '4096*4096',\n '512*768',\n '768*512',\n '1024*768',\n '768*1024',\n]);\n\nexport class RunpodImageModel implements ImageModelV2 {\n readonly specificationVersion = 'v2';\n readonly maxImagesPerCall = 1;\n\n get provider(): string {\n return this.config.provider;\n }\n\n constructor(\n readonly modelId: string,\n private config: RunpodImageModelConfig\n ) {}\n\n async doGenerate({\n prompt,\n n = 1,\n size,\n aspectRatio,\n seed,\n providerOptions,\n headers,\n abortSignal,\n }: Parameters<ImageModelV2['doGenerate']>[0]): Promise<\n Awaited<ReturnType<ImageModelV2['doGenerate']>>\n > {\n const warnings: Array<ImageModelV2CallWarning> = [];\n\n // Check if this is a Pruna model (skip standard size/aspectRatio validation)\n const isPrunaModel =\n this.modelId.includes('pruna') || this.modelId.includes('p-image');\n\n // Check if this is a Nano Banana Pro model (skip standard size/aspectRatio validation)\n const isNanoBananaProModel = this.modelId.includes('nano-banana-pro');\n\n // Determine the size to use\n let runpodSize: string;\n\n if (isPrunaModel || isNanoBananaProModel) {\n // These models use aspect_ratio string directly, skip size validation\n // Pass through the aspectRatio or use default, validation happens at API level\n runpodSize = aspectRatio || '1:1';\n } else if (size) {\n // Convert AI SDK format \"1328x1328\" to Runpod format \"1328*1328\"\n const runpodSizeCandidate = size.replace('x', '*');\n\n // Validate size is supported\n if (!SUPPORTED_SIZES.has(runpodSizeCandidate)) {\n throw new InvalidArgumentError({\n argument: 'size',\n message: `Size ${size} is not supported by Runpod. Supported sizes: ${Array.from(\n SUPPORTED_SIZES\n )\n .map((s) => s.replace('*', 'x'))\n .join(', ')}`,\n });\n }\n\n runpodSize = runpodSizeCandidate;\n } else if (aspectRatio) {\n // Validate aspect ratio is supported\n if (!SUPPORTED_ASPECT_RATIOS[aspectRatio]) {\n throw new InvalidArgumentError({\n argument: 'aspectRatio',\n message: `Aspect ratio ${aspectRatio} is not supported by Runpod. Supported aspect ratios: ${Object.keys(SUPPORTED_ASPECT_RATIOS).join(', ')}`,\n });\n }\n\n // Use supported aspect ratio mapping\n runpodSize = SUPPORTED_ASPECT_RATIOS[aspectRatio];\n } else {\n // Default to square format\n runpodSize = '1328*1328';\n }\n\n // Handle multiple images warning\n if (n > 1) {\n warnings.push({\n type: 'unsupported-setting',\n setting: 'n',\n details:\n 'Runpod image models only support generating 1 image at a time. Using n=1.',\n });\n }\n\n const currentDate = this.config._internal?.currentDate?.() ?? new Date();\n\n // Runpod uses a different request format - /runsync endpoint with input wrapper\n const inputPayload = this.buildInputPayload(\n prompt,\n runpodSize,\n seed,\n providerOptions.runpod,\n aspectRatio\n );\n\n const { value: response, responseHeaders } = await postJsonToApi({\n url: `${this.config.baseURL}/runsync`,\n headers: combineHeaders(this.config.headers(), headers),\n body: {\n input: inputPayload,\n },\n failedResponseHandler: runpodImageFailedResponseHandler,\n successfulResponseHandler: createJsonResponseHandler(\n runpodImageResponseSchema as any\n ),\n abortSignal,\n fetch: this.config.fetch,\n });\n\n // Handle both sync and async responses from Runpod\n const typedResponse = response as any;\n if (\n typedResponse.status === 'COMPLETED' &&\n (typedResponse.output?.result || typedResponse.output?.image_url)\n ) {\n // Sync response - image is ready\n // Different models use different response formats: result vs image_url\n const imageUrl =\n typedResponse.output.result || typedResponse.output.image_url;\n const imageData = await this.downloadImage(imageUrl, abortSignal);\n\n return {\n images: [imageData],\n warnings,\n response: {\n timestamp: currentDate,\n modelId: this.modelId,\n headers: responseHeaders,\n },\n providerMetadata: {\n runpod: {\n images: [\n {\n url: imageUrl,\n cost: typedResponse.output?.cost,\n },\n ],\n },\n },\n };\n } else if (\n typedResponse.status === 'IN_QUEUE' ||\n typedResponse.status === 'IN_PROGRESS'\n ) {\n // Async response - need to poll for completion\n const pollOptions = {\n maxAttempts: providerOptions.runpod?.maxPollAttempts as number,\n pollIntervalMillis: providerOptions.runpod\n ?.pollIntervalMillis as number,\n };\n const imageUrl = await this.pollForCompletion(\n typedResponse.id,\n abortSignal,\n pollOptions\n );\n const imageData = await this.downloadImage(imageUrl, abortSignal);\n\n return {\n images: [imageData],\n warnings,\n response: {\n timestamp: currentDate,\n modelId: this.modelId,\n headers: responseHeaders,\n },\n providerMetadata: {\n runpod: {\n images: [\n {\n url: imageUrl,\n jobId: typedResponse.id,\n },\n ],\n },\n },\n };\n } else {\n throw new Error(`Unexpected response status: ${typedResponse.status}`);\n }\n }\n\n private async downloadImage(\n imageUrl: string,\n abortSignal?: AbortSignal\n ): Promise<Uint8Array> {\n const { value: imageData } = await getFromApi({\n url: imageUrl,\n successfulResponseHandler: createBinaryResponseHandler(),\n failedResponseHandler: runpodImageFailedResponseHandler,\n abortSignal,\n fetch: this.config.fetch,\n });\n return imageData;\n }\n\n private async pollForCompletion(\n jobId: string,\n abortSignal?: AbortSignal,\n pollOptions?: { maxAttempts?: number; pollIntervalMillis?: number }\n ): Promise<string> {\n const maxAttempts = pollOptions?.maxAttempts ?? 60; // 5 minutes with 5-second intervals\n const pollInterval = pollOptions?.pollIntervalMillis ?? 5000; // 5 seconds\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n if (abortSignal?.aborted) {\n throw new Error('Image generation was aborted');\n }\n\n const { value: statusResponse } = await getFromApi({\n url: `${this.config.baseURL}/status/${jobId}`,\n headers: this.config.headers(),\n successfulResponseHandler: createJsonResponseHandler(\n runpodImageStatusSchema as any\n ),\n failedResponseHandler: runpodImageFailedResponseHandler,\n abortSignal,\n fetch: this.config.fetch,\n });\n\n const typedStatusResponse = statusResponse as any;\n if (\n typedStatusResponse.status === 'COMPLETED' &&\n (typedStatusResponse.output?.result ||\n typedStatusResponse.output?.image_url)\n ) {\n return (\n typedStatusResponse.output.result ||\n typedStatusResponse.output.image_url\n );\n }\n\n if (typedStatusResponse.status === 'FAILED') {\n throw new Error(\n `Image generation failed: ${typedStatusResponse.error || 'Unknown error'}`\n );\n }\n\n // Wait before next poll\n await new Promise((resolve) => setTimeout(resolve, pollInterval));\n }\n\n throw new Error(\n `Image generation timed out after ${maxAttempts} attempts (${(maxAttempts * pollInterval) / 1000}s)`\n );\n }\n\n private buildInputPayload(\n prompt: string,\n runpodSize: string,\n seed?: number,\n runpodOptions?: Record<string, unknown>,\n aspectRatio?: string\n ): Record<string, unknown> {\n // Check if this is a Flux model that uses different parameters\n const isFluxModel =\n this.modelId.includes('flux') ||\n this.modelId.includes('black-forest-labs');\n\n if (isFluxModel) {\n // Check if this is Flux Kontext (uses different parameters)\n const isKontext = this.modelId.includes('kontext');\n\n if (isKontext) {\n // Flux Kontext uses size format and has image input\n return {\n prompt,\n negative_prompt: runpodOptions?.negative_prompt ?? '',\n seed: seed ?? -1,\n num_inference_steps: 28,\n guidance: 2,\n size: runpodSize,\n output_format: 'png',\n enable_safety_checker: runpodOptions?.enable_safety_checker ?? true,\n ...runpodOptions, // This will include the 'image' parameter if provided\n };\n } else {\n // Regular Flux models use width/height\n const [width, height] = runpodSize.split('*').map(Number);\n\n return {\n prompt,\n negative_prompt: runpodOptions?.negative_prompt ?? '',\n seed: seed ?? -1,\n num_inference_steps: this.modelId.includes('schnell') ? 4 : 28,\n guidance: this.modelId.includes('schnell') ? 7 : 2,\n width,\n height,\n image_format: 'png',\n ...runpodOptions,\n };\n }\n }\n\n // Check if this is a Pruna model\n const isPrunaModel =\n this.modelId.includes('pruna') || this.modelId.includes('p-image');\n if (isPrunaModel) {\n const isPrunaEdit = this.modelId.includes('edit');\n\n if (isPrunaEdit) {\n // Pruna image edit\n // Supported aspect_ratio: \"1:1\", \"16:9\", \"9:16\", \"4:3\", \"3:4\", \"3:2\", \"2:3\"\n // Supports 1-5 images via providerOptions.runpod.images\n const editPayload: Record<string, unknown> = {\n prompt,\n aspect_ratio:\n (runpodOptions?.aspect_ratio as string) ?? aspectRatio ?? '1:1',\n disable_safety_checker:\n (runpodOptions?.disable_safety_checker as boolean) ?? false,\n };\n\n // Add seed if provided\n if (seed !== undefined) {\n editPayload.seed = seed;\n } else if (runpodOptions?.seed !== undefined) {\n editPayload.seed = runpodOptions.seed;\n }\n\n // Add images array (required, 1-5 images)\n if (runpodOptions?.images) {\n editPayload.images = runpodOptions.images;\n }\n\n return editPayload;\n } else {\n // Pruna text-to-image\n // Supported aspect_ratio: \"1:1\", \"16:9\", \"9:16\", \"4:3\", \"3:4\", \"3:2\", \"2:3\", \"custom\"\n // For custom: width/height 256-1440, must be multiple of 16\n const t2iPayload: Record<string, unknown> = {\n prompt,\n aspect_ratio:\n (runpodOptions?.aspect_ratio as string) ?? aspectRatio ?? '1:1',\n disable_safety_checker:\n (runpodOptions?.disable_safety_checker as boolean) ?? false,\n };\n\n // Add seed if provided\n if (seed !== undefined) {\n t2iPayload.seed = seed;\n } else if (runpodOptions?.seed !== undefined) {\n t2iPayload.seed = runpodOptions.seed;\n }\n\n // Handle custom aspect ratio with width/height\n if (t2iPayload.aspect_ratio === 'custom') {\n if (runpodOptions?.width) {\n t2iPayload.width = runpodOptions.width;\n }\n if (runpodOptions?.height) {\n t2iPayload.height = runpodOptions.height;\n }\n }\n\n return t2iPayload;\n }\n }\n\n // Check if this is a Nano Banana Pro model (google/nano-banana-pro-edit)\n const isNanaBananaProModel = this.modelId.includes('nano-banana-pro');\n if (isNanaBananaProModel) {\n // Nano Banana Pro image edit\n // Supported aspect_ratio: \"1:1\", \"16:9\", \"9:16\", \"4:3\", \"3:4\", \"3:2\", \"2:3\", \"21:9\", \"9:21\"\n // Supported resolution: \"1k\", \"2k\", \"4k\"\n // Supported output_format: \"jpeg\", \"png\", \"webp\"\n const nanoBananaPayload: Record<string, unknown> = {\n prompt,\n aspect_ratio:\n (runpodOptions?.aspect_ratio as string) ?? aspectRatio ?? '1:1',\n resolution: (runpodOptions?.resolution as string) ?? '1k',\n output_format: (runpodOptions?.output_format as string) ?? 'jpeg',\n enable_base64_output:\n (runpodOptions?.enable_base64_output as boolean) ?? false,\n enable_sync_mode:\n (runpodOptions?.enable_sync_mode as boolean) ?? false,\n };\n\n // Add images array (required)\n if (runpodOptions?.images) {\n nanoBananaPayload.images = runpodOptions.images;\n }\n\n return nanoBananaPayload;\n }\n\n // Default format for Qwen and other models\n return {\n prompt,\n negative_prompt: runpodOptions?.negative_prompt ?? '',\n size: runpodSize,\n seed: seed ?? -1,\n enable_safety_checker: runpodOptions?.enable_safety_checker ?? true,\n ...runpodOptions,\n };\n }\n}\n\n// Runpod image API response schema (handles both sync and async responses)\nconst runpodImageResponseSchema = z.object({\n id: z.string(),\n status: z.enum(['COMPLETED', 'IN_QUEUE', 'IN_PROGRESS', 'FAILED']),\n delayTime: z.number().optional(),\n executionTime: z.number().optional(),\n output: z\n .object({\n cost: z.number().optional(),\n result: z.string().optional(), // URL to the generated image (Qwen format)\n image_url: z.string().optional(), // URL to the generated image (Flux format)\n })\n .optional(), // Optional for IN_QUEUE/IN_PROGRESS responses\n});\n\n// Schema for polling status endpoint\nconst runpodImageStatusSchema = z.object({\n id: z.string(),\n status: z.enum(['COMPLETED', 'IN_QUEUE', 'IN_PROGRESS', 'FAILED']),\n output: z\n .object({\n cost: z.number().optional(),\n result: z.string().optional(),\n image_url: z.string().optional(),\n })\n .optional(),\n error: z.string().optional(), // Error message if FAILED\n});\n","import { z } from 'zod';\r\nimport { createJsonErrorResponseHandler } from '@ai-sdk/provider-utils';\r\n\r\n// Runpod image API error schema (supports both error formats)\r\nexport const runpodImageErrorSchema = z.object({\r\n error: z.string().optional(),\r\n message: z.string().optional(),\r\n});\r\n\r\nexport type RunpodImageErrorData = z.infer<typeof runpodImageErrorSchema>;\r\n\r\nexport const runpodImageFailedResponseHandler = createJsonErrorResponseHandler({\r\n errorSchema: runpodImageErrorSchema as any,\r\n errorToMessage: (data: RunpodImageErrorData) => {\r\n // Prefer message if available (more descriptive)\r\n if (data.message) {\r\n return data.message;\r\n }\r\n \r\n // If error field exists, try to extract nested JSON message\r\n if (data.error) {\r\n // Runpod sometimes returns nested JSON in the error field like:\r\n // \"Error submitting task: 400, {\\\"code\\\":400,\\\"message\\\":\\\"...\\\"}\"\r\n // Try to extract the inner message for cleaner error messages\r\n // Find the last occurrence of { which likely starts the JSON object\r\n const lastBraceIndex = data.error.lastIndexOf('{');\r\n if (lastBraceIndex !== -1) {\r\n try {\r\n const jsonStr = data.error.substring(lastBraceIndex);\r\n const nestedError = JSON.parse(jsonStr);\r\n if (nestedError.message && typeof nestedError.message === 'string') {\r\n return nestedError.message;\r\n }\r\n } catch {\r\n // If parsing fails, fall back to the original error string\r\n }\r\n }\r\n return data.error;\r\n }\r\n \r\n return 'Unknown Runpod error';\r\n },\r\n});\r\n\r\n","import {\n JSONValue,\n SpeechModelV2,\n SpeechModelV2CallWarning,\n} from '@ai-sdk/provider';\nimport { FetchFunction, withoutTrailingSlash } from '@ai-sdk/provider-utils';\n\nexport interface RunpodSpeechModelConfig {\n provider: string;\n baseURL: string;\n headers: () => Record<string, string>;\n fetch?: FetchFunction;\n _internal?: {\n currentDate?: () => Date;\n };\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction replaceNewlinesWithSpaces(value: string): string {\n return value.replace(/[\\r\\n]+/g, ' ');\n}\n\nexport class RunpodSpeechModel implements SpeechModelV2 {\n readonly specificationVersion = 'v2';\n\n get provider(): string {\n return this.config.provider;\n }\n\n constructor(\n readonly modelId: string,\n private readonly config: RunpodSpeechModelConfig\n ) {}\n\n private getRunpodRunSyncUrl(): string {\n // `withoutTrailingSlash` is typed to potentially return undefined, but in our\n // case `config.baseURL` is always a string.\n const baseURL =\n withoutTrailingSlash(this.config.baseURL) ?? this.config.baseURL;\n\n // Allow users to pass /run or /runsync directly.\n if (baseURL.endsWith('/run') || baseURL.endsWith('/runsync')) {\n return baseURL;\n }\n\n return `${baseURL}/runsync`;\n }\n\n async doGenerate(\n options: Parameters<SpeechModelV2['doGenerate']>[0]\n ): Promise<Awaited<ReturnType<SpeechModelV2['doGenerate']>>> {\n const currentDate = this.config._internal?.currentDate?.() ?? new Date();\n\n const warnings: SpeechModelV2CallWarning[] = [];\n\n const {\n text,\n voice,\n outputFormat,\n instructions,\n speed,\n language,\n providerOptions,\n abortSignal,\n headers,\n } = options;\n\n // This endpoint currently returns wav. Warn and ignore other formats.\n if (outputFormat != null && outputFormat !== 'wav') {\n warnings.push({\n type: 'unsupported-setting',\n setting: 'outputFormat',\n details: `Unsupported outputFormat: ${outputFormat}. This endpoint returns 'wav'.`,\n });\n }\n\n if (instructions != null) {\n warnings.push({\n type: 'unsupported-setting',\n setting: 'instructions',\n details: `Instructions are not supported by this speech endpoint.`,\n });\n }\n\n if (speed != null) {\n warnings.push({\n type: 'unsupported-setting',\n setting: 'speed',\n details: `Speed is not supported by this speech endpoint.`,\n });\n }\n\n if (language != null) {\n warnings.push({\n type: 'unsupported-setting',\n setting: 'language',\n details: `Language selection is not supported by this speech endpoint.`,\n });\n }\n\n const runpodProviderOptions = isRecord(providerOptions)\n ? (providerOptions as any).runpod\n : undefined;\n\n const voiceUrl =\n isRecord(runpodProviderOptions) &&\n (typeof runpodProviderOptions.voice_url === 'string' ||\n typeof runpodProviderOptions.voiceUrl === 'string')\n ? (runpodProviderOptions.voice_url ??\n runpodProviderOptions.voiceUrl ??\n undefined)\n : undefined;\n\n const input: Record<string, unknown> = {\n prompt: replaceNewlinesWithSpaces(text),\n };\n\n // The endpoint supports either a built-in voice name or a voice_url prompt.\n if (voiceUrl) {\n input.voice_url = voiceUrl;\n } else if (voice) {\n input.voice = voice;\n }\n\n const requestBody = { input };\n const url = this.getRunpodRunSyncUrl();\n\n const fetchFn = this.config.fetch ?? fetch;\n\n const requestHeaders: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...this.config.headers(),\n };\n\n if (headers) {\n for (const [key, value] of Object.entries(headers)) {\n if (value != null) {\n requestHeaders[key] = value;\n }\n }\n }\n\n const response = await fetchFn(url, {\n method: 'POST',\n headers: requestHeaders,\n body: JSON.stringify(requestBody),\n signal: abortSignal,\n });\n\n const responseHeaders = Object.fromEntries(response.headers.entries());\n const rawBodyText = await response.text();\n\n let parsed: any = undefined;\n try {\n parsed = rawBodyText ? JSON.parse(rawBodyText) : undefined;\n } catch {\n // ignore - we'll surface the raw body in the error below\n }\n\n if (!response.ok) {\n const message =\n (parsed && typeof parsed.error === 'string' && parsed.error) ||\n rawBodyText ||\n `HTTP ${response.status}`;\n throw new Error(`Runpod speech request failed: ${message}`);\n }\n\n const output = parsed?.output ?? parsed;\n\n const audioUrl = output?.audio_url;\n if (typeof audioUrl !== 'string' || audioUrl.length === 0) {\n throw new Error('Runpod speech response did not include an audio_url.');\n }\n\n const audioResponse = await fetchFn(audioUrl, { signal: abortSignal });\n if (!audioResponse.ok) {\n throw new Error(\n `Failed to download generated audio (${audioResponse.status}).`\n );\n }\n\n const audio = new Uint8Array(await audioResponse.arrayBuffer());\n\n const providerMetadata: Record<string, Record<string, JSONValue>> = {\n runpod: {\n audioUrl,\n ...(typeof output?.cost === 'number' ? { cost: output.cost } : {}),\n },\n };\n\n return {\n audio,\n warnings,\n request: {\n body: JSON.stringify(requestBody),\n },\n response: {\n timestamp: currentDate,\n modelId: this.modelId,\n headers: responseHeaders as any,\n body: rawBodyText,\n },\n providerMetadata,\n };\n }\n}\n"],"mappings":"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","names":["withoutTrailingSlash","z","z","withoutTrailingSlash"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@runpod/ai-sdk-provider",
3
- "version": "0.11.1",
3
+ "version": "0.12.0",
4
4
  "license": "Apache-2.0",
5
5
  "sideEffects": false,
6
6
  "main": "./dist/index.js",