@runpod/ai-sdk-provider 0.11.1 → 1.0.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/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
@@ -83,7 +83,7 @@ var RunpodImageModel = class {
83
83
  constructor(modelId, config) {
84
84
  this.modelId = modelId;
85
85
  this.config = config;
86
- this.specificationVersion = "v2";
86
+ this.specificationVersion = "v3";
87
87
  this.maxImagesPerCall = 1;
88
88
  }
89
89
  get provider() {
@@ -91,15 +91,25 @@ var RunpodImageModel = class {
91
91
  }
92
92
  async doGenerate({
93
93
  prompt,
94
- n = 1,
94
+ n,
95
95
  size,
96
96
  aspectRatio,
97
97
  seed,
98
+ files,
99
+ mask,
98
100
  providerOptions,
99
101
  headers,
100
102
  abortSignal
101
103
  }) {
102
104
  const warnings = [];
105
+ const standardizedImages = this.convertFilesToRunpodFormat(files);
106
+ if (mask) {
107
+ warnings.push({
108
+ type: "unsupported",
109
+ feature: "mask",
110
+ details: "Mask input for inpainting is not yet supported."
111
+ });
112
+ }
103
113
  const isPrunaModel = this.modelId.includes("pruna") || this.modelId.includes("p-image");
104
114
  const isNanoBananaProModel = this.modelId.includes("nano-banana-pro");
105
115
  let runpodSize;
@@ -129,18 +139,19 @@ var RunpodImageModel = class {
129
139
  }
130
140
  if (n > 1) {
131
141
  warnings.push({
132
- type: "unsupported-setting",
133
- setting: "n",
142
+ type: "unsupported",
143
+ feature: "multiple images (n > 1)",
134
144
  details: "Runpod image models only support generating 1 image at a time. Using n=1."
135
145
  });
136
146
  }
137
147
  const currentDate = this.config._internal?.currentDate?.() ?? /* @__PURE__ */ new Date();
138
148
  const inputPayload = this.buildInputPayload(
139
- prompt,
149
+ prompt ?? "",
140
150
  runpodSize,
141
151
  seed,
142
152
  providerOptions.runpod,
143
- aspectRatio
153
+ aspectRatio,
154
+ standardizedImages
144
155
  );
145
156
  const { value: response, responseHeaders } = await postJsonToApi({
146
157
  url: `${this.config.baseURL}/runsync`,
@@ -254,12 +265,44 @@ var RunpodImageModel = class {
254
265
  `Image generation timed out after ${maxAttempts} attempts (${maxAttempts * pollInterval / 1e3}s)`
255
266
  );
256
267
  }
257
- buildInputPayload(prompt, runpodSize, seed, runpodOptions, aspectRatio) {
268
+ /**
269
+ * Converts standardized ImageModelV3File[] to Runpod-compatible format.
270
+ * Returns URLs or base64 data URLs that Runpod API accepts.
271
+ */
272
+ convertFilesToRunpodFormat(files) {
273
+ if (!files || files.length === 0) {
274
+ return void 0;
275
+ }
276
+ return files.map((file) => {
277
+ if (file.type === "url") {
278
+ return file.url;
279
+ }
280
+ if (typeof file.data === "string") {
281
+ if (file.data.startsWith("data:")) {
282
+ return file.data;
283
+ }
284
+ return `data:${file.mediaType};base64,${file.data}`;
285
+ }
286
+ const base64 = this.uint8ArrayToBase64(file.data);
287
+ return `data:${file.mediaType};base64,${base64}`;
288
+ });
289
+ }
290
+ /**
291
+ * Converts Uint8Array to base64 string.
292
+ */
293
+ uint8ArrayToBase64(data) {
294
+ let binary = "";
295
+ for (let i = 0; i < data.length; i++) {
296
+ binary += String.fromCharCode(data[i]);
297
+ }
298
+ return btoa(binary);
299
+ }
300
+ buildInputPayload(prompt, runpodSize, seed, runpodOptions, aspectRatio, standardizedImages) {
258
301
  const isFluxModel = this.modelId.includes("flux") || this.modelId.includes("black-forest-labs");
259
302
  if (isFluxModel) {
260
303
  const isKontext = this.modelId.includes("kontext");
261
304
  if (isKontext) {
262
- return {
305
+ const kontextPayload = {
263
306
  prompt,
264
307
  negative_prompt: runpodOptions?.negative_prompt ?? "",
265
308
  seed: seed ?? -1,
@@ -269,8 +312,11 @@ var RunpodImageModel = class {
269
312
  output_format: "png",
270
313
  enable_safety_checker: runpodOptions?.enable_safety_checker ?? true,
271
314
  ...runpodOptions
272
- // This will include the 'image' parameter if provided
273
315
  };
316
+ if (standardizedImages && standardizedImages.length > 0) {
317
+ kontextPayload.image = standardizedImages[0];
318
+ }
319
+ return kontextPayload;
274
320
  } else {
275
321
  const [width, height] = runpodSize.split("*").map(Number);
276
322
  return {
@@ -292,7 +338,7 @@ var RunpodImageModel = class {
292
338
  if (isPrunaEdit) {
293
339
  const editPayload = {
294
340
  prompt,
295
- aspect_ratio: runpodOptions?.aspect_ratio ?? aspectRatio ?? "match_input_image",
341
+ aspect_ratio: runpodOptions?.aspect_ratio ?? aspectRatio ?? "1:1",
296
342
  disable_safety_checker: runpodOptions?.disable_safety_checker ?? false
297
343
  };
298
344
  if (seed !== void 0) {
@@ -300,7 +346,9 @@ var RunpodImageModel = class {
300
346
  } else if (runpodOptions?.seed !== void 0) {
301
347
  editPayload.seed = runpodOptions.seed;
302
348
  }
303
- if (runpodOptions?.images) {
349
+ if (standardizedImages && standardizedImages.length > 0) {
350
+ editPayload.images = standardizedImages;
351
+ } else if (runpodOptions?.images) {
304
352
  editPayload.images = runpodOptions.images;
305
353
  }
306
354
  return editPayload;
@@ -336,12 +384,14 @@ var RunpodImageModel = class {
336
384
  enable_base64_output: runpodOptions?.enable_base64_output ?? false,
337
385
  enable_sync_mode: runpodOptions?.enable_sync_mode ?? false
338
386
  };
339
- if (runpodOptions?.images) {
387
+ if (standardizedImages && standardizedImages.length > 0) {
388
+ nanoBananaPayload.images = standardizedImages;
389
+ } else if (runpodOptions?.images) {
340
390
  nanoBananaPayload.images = runpodOptions.images;
341
391
  }
342
392
  return nanoBananaPayload;
343
393
  }
344
- return {
394
+ const defaultPayload = {
345
395
  prompt,
346
396
  negative_prompt: runpodOptions?.negative_prompt ?? "",
347
397
  size: runpodSize,
@@ -349,6 +399,14 @@ var RunpodImageModel = class {
349
399
  enable_safety_checker: runpodOptions?.enable_safety_checker ?? true,
350
400
  ...runpodOptions
351
401
  };
402
+ if (standardizedImages && standardizedImages.length > 0) {
403
+ if (standardizedImages.length === 1) {
404
+ defaultPayload.image = standardizedImages[0];
405
+ } else {
406
+ defaultPayload.images = standardizedImages;
407
+ }
408
+ }
409
+ return defaultPayload;
352
410
  }
353
411
  };
354
412
  var runpodImageResponseSchema = z2.object({
@@ -377,6 +435,148 @@ var runpodImageStatusSchema = z2.object({
377
435
  // Error message if FAILED
378
436
  });
379
437
 
438
+ // src/runpod-speech-model.ts
439
+ import { withoutTrailingSlash } from "@ai-sdk/provider-utils";
440
+ function isRecord(value) {
441
+ return typeof value === "object" && value !== null;
442
+ }
443
+ function replaceNewlinesWithSpaces(value) {
444
+ return value.replace(/[\r\n]+/g, " ");
445
+ }
446
+ var RunpodSpeechModel = class {
447
+ constructor(modelId, config) {
448
+ this.modelId = modelId;
449
+ this.config = config;
450
+ this.specificationVersion = "v3";
451
+ }
452
+ get provider() {
453
+ return this.config.provider;
454
+ }
455
+ getRunpodRunSyncUrl() {
456
+ const baseURL = withoutTrailingSlash(this.config.baseURL) ?? this.config.baseURL;
457
+ if (baseURL.endsWith("/run") || baseURL.endsWith("/runsync")) {
458
+ return baseURL;
459
+ }
460
+ return `${baseURL}/runsync`;
461
+ }
462
+ async doGenerate(options) {
463
+ const currentDate = this.config._internal?.currentDate?.() ?? /* @__PURE__ */ new Date();
464
+ const warnings = [];
465
+ const {
466
+ text,
467
+ voice,
468
+ outputFormat,
469
+ instructions,
470
+ speed,
471
+ language,
472
+ providerOptions,
473
+ abortSignal,
474
+ headers
475
+ } = options;
476
+ if (outputFormat != null && outputFormat !== "wav") {
477
+ warnings.push({
478
+ type: "unsupported",
479
+ feature: "outputFormat",
480
+ details: `Unsupported outputFormat: ${outputFormat}. This endpoint returns 'wav'.`
481
+ });
482
+ }
483
+ if (instructions != null) {
484
+ warnings.push({
485
+ type: "unsupported",
486
+ feature: "instructions",
487
+ details: `Instructions are not supported by this speech endpoint.`
488
+ });
489
+ }
490
+ if (speed != null) {
491
+ warnings.push({
492
+ type: "unsupported",
493
+ feature: "speed",
494
+ details: `Speed is not supported by this speech endpoint.`
495
+ });
496
+ }
497
+ if (language != null) {
498
+ warnings.push({
499
+ type: "unsupported",
500
+ feature: "language",
501
+ details: `Language selection is not supported by this speech endpoint.`
502
+ });
503
+ }
504
+ const runpodProviderOptions = isRecord(providerOptions) ? providerOptions.runpod : void 0;
505
+ const voiceUrl = isRecord(runpodProviderOptions) && (typeof runpodProviderOptions.voice_url === "string" || typeof runpodProviderOptions.voiceUrl === "string") ? runpodProviderOptions.voice_url ?? runpodProviderOptions.voiceUrl ?? void 0 : void 0;
506
+ const input = {
507
+ prompt: replaceNewlinesWithSpaces(text)
508
+ };
509
+ if (voiceUrl) {
510
+ input.voice_url = voiceUrl;
511
+ } else if (voice) {
512
+ input.voice = voice;
513
+ }
514
+ const requestBody = { input };
515
+ const url = this.getRunpodRunSyncUrl();
516
+ const fetchFn = this.config.fetch ?? fetch;
517
+ const requestHeaders = {
518
+ "Content-Type": "application/json",
519
+ ...this.config.headers()
520
+ };
521
+ if (headers) {
522
+ for (const [key, value] of Object.entries(headers)) {
523
+ if (value != null) {
524
+ requestHeaders[key] = value;
525
+ }
526
+ }
527
+ }
528
+ const response = await fetchFn(url, {
529
+ method: "POST",
530
+ headers: requestHeaders,
531
+ body: JSON.stringify(requestBody),
532
+ signal: abortSignal
533
+ });
534
+ const responseHeaders = Object.fromEntries(response.headers.entries());
535
+ const rawBodyText = await response.text();
536
+ let parsed = void 0;
537
+ try {
538
+ parsed = rawBodyText ? JSON.parse(rawBodyText) : void 0;
539
+ } catch {
540
+ }
541
+ if (!response.ok) {
542
+ const message = parsed && typeof parsed.error === "string" && parsed.error || rawBodyText || `HTTP ${response.status}`;
543
+ throw new Error(`Runpod speech request failed: ${message}`);
544
+ }
545
+ const output = parsed?.output ?? parsed;
546
+ const audioUrl = output?.audio_url;
547
+ if (typeof audioUrl !== "string" || audioUrl.length === 0) {
548
+ throw new Error("Runpod speech response did not include an audio_url.");
549
+ }
550
+ const audioResponse = await fetchFn(audioUrl, { signal: abortSignal });
551
+ if (!audioResponse.ok) {
552
+ throw new Error(
553
+ `Failed to download generated audio (${audioResponse.status}).`
554
+ );
555
+ }
556
+ const audio = new Uint8Array(await audioResponse.arrayBuffer());
557
+ const providerMetadata = {
558
+ runpod: {
559
+ audioUrl,
560
+ ...typeof output?.cost === "number" ? { cost: output.cost } : {}
561
+ }
562
+ };
563
+ return {
564
+ audio,
565
+ warnings,
566
+ request: {
567
+ body: JSON.stringify(requestBody)
568
+ },
569
+ response: {
570
+ timestamp: currentDate,
571
+ modelId: this.modelId,
572
+ headers: responseHeaders,
573
+ body: rawBodyText
574
+ },
575
+ providerMetadata
576
+ };
577
+ }
578
+ };
579
+
380
580
  // src/runpod-provider.ts
381
581
  var MODEL_ID_TO_ENDPOINT_URL = {
382
582
  "qwen/qwen3-32b-awq": "https://api.runpod.ai/v2/qwen3-32b-awq/openai/v1",
@@ -404,6 +604,9 @@ var IMAGE_MODEL_ID_TO_ENDPOINT_URL = {
404
604
  "pruna/p-image-t2i": "https://api.runpod.ai/v2/p-image-t2i",
405
605
  "pruna/p-image-edit": "https://api.runpod.ai/v2/p-image-edit"
406
606
  };
607
+ var SPEECH_MODEL_ID_TO_ENDPOINT_URL = {
608
+ "resembleai/chatterbox-turbo": "https://api.runpod.ai/v2/chatterbox-turbo/"
609
+ };
407
610
  var MODEL_ID_TO_OPENAI_NAME = {
408
611
  "qwen/qwen3-32b-awq": "Qwen/Qwen3-32B-AWQ",
409
612
  "deepcogito/cogito-671b-v2.1-fp8": "deepcogito/cogito-671b-v2.1-FP8",
@@ -413,6 +616,23 @@ function deriveEndpointURL(modelId) {
413
616
  const normalized = modelId.replace(/\//g, "-");
414
617
  return `https://api.runpod.ai/v2/${normalized}/openai/v1`;
415
618
  }
619
+ function parseRunpodConsoleEndpointId(modelIdOrUrl) {
620
+ if (!modelIdOrUrl.startsWith("http")) {
621
+ return null;
622
+ }
623
+ try {
624
+ const url = new URL(modelIdOrUrl);
625
+ if (url.hostname !== "console.runpod.io") {
626
+ return null;
627
+ }
628
+ const parts = url.pathname.split("/").filter(Boolean);
629
+ const idx = parts.lastIndexOf("endpoint");
630
+ const endpointId = idx !== -1 ? parts[idx + 1] : void 0;
631
+ return endpointId || null;
632
+ } catch {
633
+ return null;
634
+ }
635
+ }
416
636
  function createRunpod(options = {}) {
417
637
  const getHeaders = () => ({
418
638
  Authorization: `Bearer ${loadApiKey({
@@ -445,7 +665,7 @@ function createRunpod(options = {}) {
445
665
  }
446
666
  return {
447
667
  provider: `runpod.${modelType}`,
448
- url: ({ path }) => `${withoutTrailingSlash(baseURL)}${path}`,
668
+ url: ({ path }) => `${withoutTrailingSlash2(baseURL)}${path}`,
449
669
  headers: getHeaders,
450
670
  fetch: runpodFetch
451
671
  };
@@ -478,11 +698,26 @@ function createRunpod(options = {}) {
478
698
  fetch: options.fetch
479
699
  });
480
700
  };
701
+ const createSpeechModel = (modelId) => {
702
+ const endpointIdFromConsole = parseRunpodConsoleEndpointId(modelId);
703
+ const normalizedModelId = endpointIdFromConsole ?? modelId;
704
+ const mappedBaseURL = SPEECH_MODEL_ID_TO_ENDPOINT_URL[normalizedModelId];
705
+ const baseURL = mappedBaseURL ?? (normalizedModelId.startsWith("http") ? normalizedModelId : `https://api.runpod.ai/v2/${normalizedModelId}`);
706
+ return new RunpodSpeechModel(normalizedModelId, {
707
+ provider: "runpod.speech",
708
+ baseURL,
709
+ headers: getHeaders,
710
+ fetch: runpodFetch
711
+ });
712
+ };
481
713
  const provider = (modelId) => createChatModel(modelId);
482
714
  provider.completionModel = createCompletionModel;
483
715
  provider.languageModel = createChatModel;
484
716
  provider.chatModel = createChatModel;
485
717
  provider.imageModel = createImageModel;
718
+ provider.image = createImageModel;
719
+ provider.speechModel = createSpeechModel;
720
+ provider.speech = createSpeechModel;
486
721
  return provider;
487
722
  }
488
723
  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 { ImageModelV3, LanguageModelV3, SpeechModelV3 } 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): LanguageModelV3;\n\n /**\nCreates a chat model for text generation.\n*/\n chatModel(modelId: string): LanguageModelV3;\n\n /**\nCreates a chat model for text generation.\n*/\n languageModel(modelId: string): LanguageModelV3;\n\n /**\nCreates a completion model for text generation.\n*/\n completionModel(modelId: string): LanguageModelV3;\n\n /**\nCreates an image model for image generation.\n*/\n imageModel(modelId: string): ImageModelV3;\n\n /**\nCreates an image model for image generation.\n*/\n image(modelId: string): ImageModelV3;\n\n /**\nCreates a speech model for speech generation.\n*/\n speechModel(modelId: string): SpeechModelV3;\n\n /**\nCreates a speech model for speech generation.\n*/\n speech(modelId: string): SpeechModelV3;\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.image = createImageModel;\n provider.speechModel = createSpeechModel;\n provider.speech = createSpeechModel;\n\n return provider;\n}\n\nexport const runpod = createRunpod();\n","import {\n ImageModelV3,\n ImageModelV3CallOptions,\n ImageModelV3File,\n SharedV3Warning,\n} 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 ImageModelV3 {\n readonly specificationVersion = 'v3';\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,\n size,\n aspectRatio,\n seed,\n files,\n mask,\n providerOptions,\n headers,\n abortSignal,\n }: ImageModelV3CallOptions): Promise<\n Awaited<ReturnType<ImageModelV3['doGenerate']>>\n > {\n const warnings: Array<SharedV3Warning> = [];\n\n // Convert standardized files to Runpod format (base64 data URLs or raw base64)\n const standardizedImages = this.convertFilesToRunpodFormat(files);\n\n if (mask) {\n warnings.push({\n type: 'unsupported',\n feature: 'mask',\n details: 'Mask input for inpainting is not yet supported.',\n });\n }\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',\n feature: 'multiple images (n > 1)',\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 as Record<string, unknown> | undefined,\n aspectRatio,\n standardizedImages\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 /**\n * Converts standardized ImageModelV3File[] to Runpod-compatible format.\n * Returns URLs or base64 data URLs that Runpod API accepts.\n */\n private convertFilesToRunpodFormat(\n files: ImageModelV3File[] | undefined\n ): string[] | undefined {\n if (!files || files.length === 0) {\n return undefined;\n }\n\n return files.map((file) => {\n // Handle URL type - return URL directly\n if (file.type === 'url') {\n return file.url;\n }\n\n // Handle file type with data\n if (typeof file.data === 'string') {\n // If it's already a data URL, return as-is\n if (file.data.startsWith('data:')) {\n return file.data;\n }\n // Otherwise, wrap as data URL with media type\n return `data:${file.mediaType};base64,${file.data}`;\n }\n\n // Convert Uint8Array to base64 data URL\n const base64 = this.uint8ArrayToBase64(file.data);\n return `data:${file.mediaType};base64,${base64}`;\n });\n }\n\n /**\n * Converts Uint8Array to base64 string.\n */\n private uint8ArrayToBase64(data: Uint8Array): string {\n let binary = '';\n for (let i = 0; i < data.length; i++) {\n binary += String.fromCharCode(data[i]);\n }\n return btoa(binary);\n }\n\n private buildInputPayload(\n prompt: string,\n runpodSize: string,\n seed?: number,\n runpodOptions?: Record<string, unknown>,\n aspectRatio?: string,\n standardizedImages?: 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 // Prioritize standardized files over providerOptions\n const kontextPayload: Record<string, unknown> = {\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,\n };\n\n // Use standardized files if provided (first image), otherwise use providerOptions.image\n if (standardizedImages && standardizedImages.length > 0) {\n kontextPayload.image = standardizedImages[0];\n }\n\n return kontextPayload;\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 // Use standardized files if provided, otherwise use providerOptions.images\n if (standardizedImages && standardizedImages.length > 0) {\n editPayload.images = standardizedImages;\n } else 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 // Use standardized files if provided, otherwise use providerOptions.images\n if (standardizedImages && standardizedImages.length > 0) {\n nanoBananaPayload.images = standardizedImages;\n } else if (runpodOptions?.images) {\n nanoBananaPayload.images = runpodOptions.images;\n }\n\n return nanoBananaPayload;\n }\n\n // Default format for Qwen and other models\n const defaultPayload: Record<string, unknown> = {\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 // For edit models, use standardized files if provided\n if (standardizedImages && standardizedImages.length > 0) {\n // Single image models use 'image', multi-image models use 'images'\n if (standardizedImages.length === 1) {\n defaultPayload.image = standardizedImages[0];\n } else {\n defaultPayload.images = standardizedImages;\n }\n }\n\n return defaultPayload;\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 SpeechModelV3,\n SpeechModelV3CallOptions,\n SharedV3Warning,\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 SpeechModelV3 {\n readonly specificationVersion = 'v3';\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: SpeechModelV3CallOptions\n ): Promise<Awaited<ReturnType<SpeechModelV3['doGenerate']>>> {\n const currentDate = this.config._internal?.currentDate?.() ?? new Date();\n\n const warnings: SharedV3Warning[] = [];\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',\n feature: 'outputFormat',\n details: `Unsupported outputFormat: ${outputFormat}. This endpoint returns 'wav'.`,\n });\n }\n\n if (instructions != null) {\n warnings.push({\n type: 'unsupported',\n feature: 'instructions',\n details: `Instructions are not supported by this speech endpoint.`,\n });\n }\n\n if (speed != null) {\n warnings.push({\n type: 'unsupported',\n feature: 'speed',\n details: `Speed is not supported by this speech endpoint.`,\n });\n }\n\n if (language != null) {\n warnings.push({\n type: 'unsupported',\n feature: '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": "1.0.0",
4
4
  "license": "Apache-2.0",
5
5
  "sideEffects": false,
6
6
  "main": "./dist/index.js",
@@ -19,9 +19,9 @@
19
19
  }
20
20
  },
21
21
  "dependencies": {
22
- "@ai-sdk/openai-compatible": "^1.0.11",
23
- "@ai-sdk/provider": "^2.0.0",
24
- "@ai-sdk/provider-utils": "^3.0.5"
22
+ "@ai-sdk/openai-compatible": "^2.0.0",
23
+ "@ai-sdk/provider": "^3.0.0",
24
+ "@ai-sdk/provider-utils": "^4.0.0"
25
25
  },
26
26
  "devDependencies": {
27
27
  "@changesets/cli": "^2.29.6",