@runpod/ai-sdk-provider 1.2.0 → 1.4.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/runpod-provider.ts","../src/runpod-image-model.ts","../src/runpod-error.ts","../src/runpod-speech-model.ts","../src/runpod-transcription-model.ts"],"sourcesContent":["import {\n ImageModelV3,\n LanguageModelV3,\n SpeechModelV3,\n TranscriptionModelV3,\n} 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';\nimport { RunpodTranscriptionModel } from './runpod-transcription-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 /**\nCreates a transcription model for audio transcription.\n*/\n transcriptionModel(modelId: string): TranscriptionModelV3;\n\n /**\nCreates a transcription model for audio transcription.\n*/\n transcription(modelId: string): TranscriptionModelV3;\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 'qwen/qwen-image-edit-2511': 'https://api.runpod.ai/v2/qwen-image-edit-2511',\n 'qwen/qwen-image-edit-2511-lora':\n 'https://api.runpod.ai/v2/qwen-image-edit-2511-lora',\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 // Alibaba Wan 2.6 (t2i)\n 'alibaba/wan-2.6': 'https://api.runpod.ai/v2/wan-2-6-t2i',\n // Nano Banana (edit only)\n 'google/nano-banana-edit': 'https://api.runpod.ai/v2/nano-banana-edit',\n 'nano-banana-edit': 'https://api.runpod.ai/v2/nano-banana-edit', // backwards compatibility\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 transcription model IDs to their serverless endpoint URLs\nconst TRANSCRIPTION_MODEL_ID_TO_ENDPOINT_URL: Record<string, string> = {\n 'pruna/whisper-v3-large': 'https://api.runpod.ai/v2/whisper-v3-large',\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 createTranscriptionModel = (modelId: string) => {\n const endpointIdFromConsole = parseRunpodConsoleEndpointId(modelId);\n const normalizedModelId = endpointIdFromConsole ?? modelId;\n\n // Prefer explicit mapping for known transcription model IDs.\n const mappedBaseURL =\n TRANSCRIPTION_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 RunpodTranscriptionModel(normalizedModelId, {\n provider: 'runpod.transcription',\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 provider.transcriptionModel = createTranscriptionModel;\n provider.transcription = createTranscriptionModel;\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 '1280*1280', // wan-2.6 max\n '1536*1536',\n '2048*2048',\n '4096*4096',\n '512*768',\n '768*512',\n '1024*768',\n '768*1024',\n]);\n\n// WAN 2.6 specific aspect ratio to size mappings\n// Total pixels must be between 768*768 (589,824) and 1280*1280 (1,638,400)\n// Aspect ratio must be between 1:4 and 4:1\nconst WAN_ASPECT_RATIOS: Record<string, string> = {\n '1:1': '1280*1280', // 1,638,400 pixels\n '2:3': '800*1200', // 960,000 pixels\n '3:2': '1200*800', // 960,000 pixels\n '3:4': '960*1280', // 1,228,800 pixels\n '4:3': '1280*960', // 1,228,800 pixels\n '9:16': '720*1280', // 921,600 pixels\n '16:9': '1280*720', // 921,600 pixels\n '21:9': '1344*576', // 774,144 pixels\n '9:21': '576*1344', // 774,144 pixels\n};\n\n// WAN 2.6 pixel constraints\nconst WAN_MIN_PIXELS = 768 * 768; // 589,824\nconst WAN_MAX_PIXELS = 1280 * 1280; // 1,638,400\nconst WAN_MIN_ASPECT_RATIO = 1 / 4; // 1:4\nconst WAN_MAX_ASPECT_RATIO = 4 / 1; // 4:1\n\n/**\n * Validates a size string for WAN 2.6 constraints.\n * Returns true if valid, throws InvalidArgumentError if not.\n */\nfunction validateWanSize(size: string): boolean {\n const [widthStr, heightStr] = size.split('*');\n const width = parseInt(widthStr, 10);\n const height = parseInt(heightStr, 10);\n\n if (isNaN(width) || isNaN(height)) {\n throw new InvalidArgumentError({\n argument: 'size',\n message: `Invalid size format: ${size}. Expected format: WIDTHxHEIGHT or WIDTH*HEIGHT`,\n });\n }\n\n const totalPixels = width * height;\n const aspectRatio = width / height;\n\n if (totalPixels < WAN_MIN_PIXELS || totalPixels > WAN_MAX_PIXELS) {\n throw new InvalidArgumentError({\n argument: 'size',\n message: `Size ${size} has ${totalPixels} pixels, which is outside the valid range for WAN 2.6 (${WAN_MIN_PIXELS} to ${WAN_MAX_PIXELS} pixels). Try 1280x1280 or 1024x1024.`,\n });\n }\n\n if (aspectRatio < WAN_MIN_ASPECT_RATIO || aspectRatio > WAN_MAX_ASPECT_RATIO) {\n throw new InvalidArgumentError({\n argument: 'size',\n message: `Size ${size} has aspect ratio ${aspectRatio.toFixed(2)}, which is outside the valid range for WAN 2.6 (1:4 to 4:1).`,\n });\n }\n\n return true;\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 // Check if this is a WAN model (uses WAN-specific pixel/aspect ratio constraints)\n const isWanModel = this.modelId.includes('wan-2');\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 (isWanModel) {\n // WAN 2.6 has specific pixel and aspect ratio constraints\n // Total pixels: 768*768 (589,824) to 1280*1280 (1,638,400)\n // Aspect ratio: 1:4 to 4:1\n if (size) {\n const runpodSizeCandidate = size.replace('x', '*');\n validateWanSize(runpodSizeCandidate);\n runpodSize = runpodSizeCandidate;\n } else if (aspectRatio) {\n if (!WAN_ASPECT_RATIOS[aspectRatio]) {\n throw new InvalidArgumentError({\n argument: 'aspectRatio',\n message: `Aspect ratio ${aspectRatio} is not supported by WAN 2.6. Supported aspect ratios: ${Object.keys(WAN_ASPECT_RATIOS).join(', ')}`,\n });\n }\n runpodSize = WAN_ASPECT_RATIOS[aspectRatio];\n } else {\n // Default to 1280*1280 for WAN models\n runpodSize = '1280*1280';\n }\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 // Determine the effective baseURL (may switch for LoRA models)\n let effectiveBaseURL = this.config.baseURL;\n const runpodOptions = providerOptions.runpod as\n | Record<string, unknown>\n | undefined;\n if (\n this.modelId.includes('qwen-image-edit-2511') &&\n !this.modelId.includes('lora') &&\n runpodOptions?.loras &&\n Array.isArray(runpodOptions.loras) &&\n runpodOptions.loras.length > 0\n ) {\n // Switch to LoRA endpoint when loras are provided\n effectiveBaseURL = this.config.baseURL.replace(\n 'qwen-image-edit-2511',\n 'qwen-image-edit-2511-lora'\n );\n }\n\n const { value: response, responseHeaders } = await postJsonToApi({\n url: `${effectiveBaseURL}/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 effectiveBaseURL\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 if (typedResponse.status === 'FAILED') {\n throw new Error(\n `Image generation failed: ${typedResponse.error || 'Unknown error'}`\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 effectiveBaseURL?: string\n ): Promise<string> {\n const maxAttempts = pollOptions?.maxAttempts ?? 60; // 5 minutes with 5-second intervals\n const pollInterval = pollOptions?.pollIntervalMillis ?? 5000; // 5 seconds\n const baseURL = effectiveBaseURL ?? this.config.baseURL;\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: `${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 // Check if this is a Nano Banana (non-pro) edit model\n const isNanaBananaEditModel =\n this.modelId.includes('nano-banana-edit') &&\n !this.modelId.includes('nano-banana-pro');\n if (isNanaBananaEditModel) {\n // Nano Banana edit uses simple format: prompt, images array, enable_safety_checker\n const nanoBananaEditPayload: Record<string, unknown> = {\n prompt,\n enable_safety_checker: runpodOptions?.enable_safety_checker ?? true,\n };\n\n // Always use images array format\n if (standardizedImages && standardizedImages.length > 0) {\n nanoBananaEditPayload.images = standardizedImages;\n } else if (runpodOptions?.images) {\n nanoBananaEditPayload.images = runpodOptions.images;\n }\n\n return nanoBananaEditPayload;\n }\n\n // Check if this is a Qwen Image Edit 2511 model (uses images array format)\n const isQwenImageEdit2511 = this.modelId.includes('qwen-image-edit-2511');\n if (isQwenImageEdit2511) {\n // Qwen Image Edit 2511 uses images array, output_format, and sync options\n const qwenEdit2511Payload: Record<string, unknown> = {\n prompt,\n size: runpodSize,\n seed: seed ?? -1,\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 ...runpodOptions,\n };\n\n // Always use images array format for this model\n if (standardizedImages && standardizedImages.length > 0) {\n qwenEdit2511Payload.images = standardizedImages;\n } else if (runpodOptions?.images) {\n qwenEdit2511Payload.images = runpodOptions.images;\n }\n\n return qwenEdit2511Payload;\n }\n\n // Check if this is an Alibaba Wan model\n const isWanModel = this.modelId.includes('wan-2');\n if (isWanModel) {\n // Alibaba Wan 2.6 uses standard t2i format with negative prompt in prompt string\n return {\n prompt,\n size: runpodSize,\n seed: seed ?? -1,\n enable_safety_checker: runpodOptions?.enable_safety_checker ?? true,\n ...runpodOptions,\n };\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 error: z.string().optional(), // Error message if FAILED\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\n// Helper function to extract error message from Runpod error data\r\nfunction extractErrorMessage(data: RunpodImageErrorData): string {\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\nexport const runpodImageFailedResponseHandler = createJsonErrorResponseHandler({\r\n errorSchema: runpodImageErrorSchema as any,\r\n errorToMessage: extractErrorMessage,\r\n});\r\n\r\nexport const runpodTranscriptionFailedResponseHandler = createJsonErrorResponseHandler({\r\n errorSchema: runpodImageErrorSchema as any,\r\n errorToMessage: extractErrorMessage,\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 // Check for FAILED status and surface the actual error message\n if (parsed?.status === 'FAILED') {\n throw new Error(\n `Speech generation failed: ${parsed.error || 'Unknown error'}`\n );\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","import {\n JSONValue,\n TranscriptionModelV3,\n TranscriptionModelV3CallOptions,\n SharedV3Warning,\n} from '@ai-sdk/provider';\nimport {\n FetchFunction,\n withoutTrailingSlash,\n createJsonResponseHandler,\n getFromApi,\n postJsonToApi,\n} from '@ai-sdk/provider-utils';\nimport { z } from 'zod';\nimport { runpodTranscriptionFailedResponseHandler } from './runpod-error';\n\nexport interface RunpodTranscriptionModelConfig {\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\n// Schema for the job submission response\nconst runpodJobResponseSchema = z.object({\n id: z.string(),\n status: z.string().optional(),\n});\n\n// Schema for the status polling response\n// Note: RunPod Whisper may return 'result' or 'text' depending on the worker version\nconst runpodStatusResponseSchema = z.object({\n id: z.string().optional(),\n status: z.string(),\n output: z\n .object({\n text: z.string().optional(),\n result: z.string().optional(), // Some workers use 'result' instead of 'text'\n segments: z\n .array(\n z.object({\n text: z.string().optional(),\n start: z.number().optional(),\n end: z.number().optional(),\n })\n )\n .optional(),\n language: z.string().optional(),\n duration: z.number().optional(),\n cost: z.number().optional(),\n })\n .optional(),\n error: z.string().optional(),\n});\n\nexport class RunpodTranscriptionModel implements TranscriptionModelV3 {\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: RunpodTranscriptionModelConfig\n ) {}\n\n private getRunpodRunUrl(): 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 // Use /run for async jobs (Whisper can take time)\n return `${baseURL}/run`;\n }\n\n async doGenerate(\n options: TranscriptionModelV3CallOptions\n ): Promise<Awaited<ReturnType<TranscriptionModelV3['doGenerate']>>> {\n const currentDate = this.config._internal?.currentDate?.() ?? new Date();\n\n const warnings: SharedV3Warning[] = [];\n\n const { audio, providerOptions, abortSignal, headers } = options;\n\n // Extract Runpod-specific options\n const runpodOptions = this.extractRunpodOptions(providerOptions);\n\n // Build input - RunPod Whisper accepts either 'audio' (URL) or 'audio_base64' (base64 string)\n const input: Record<string, unknown> = {};\n\n // Check if user provided an audio URL directly via providerOptions\n if (runpodOptions.audio && typeof runpodOptions.audio === 'string') {\n input.audio = runpodOptions.audio;\n } else {\n // Convert the AI SDK audio input to base64 for RunPod\n const base64Audio = this.convertAudioToBase64(audio);\n input.audio_base64 = base64Audio;\n }\n\n // Add optional parameters\n if (runpodOptions.prompt || runpodOptions.initial_prompt) {\n input.initial_prompt = runpodOptions.prompt ?? runpodOptions.initial_prompt;\n }\n if (runpodOptions.language) {\n input.language = runpodOptions.language;\n }\n if (runpodOptions.word_timestamps !== undefined) {\n input.word_timestamps = runpodOptions.word_timestamps;\n }\n // Pass through other Whisper-specific options\n if (runpodOptions.model) {\n input.model = runpodOptions.model;\n }\n if (runpodOptions.transcription) {\n input.transcription = runpodOptions.transcription;\n }\n if (runpodOptions.translate !== undefined) {\n input.translate = runpodOptions.translate;\n }\n if (runpodOptions.enable_vad !== undefined) {\n input.enable_vad = runpodOptions.enable_vad;\n }\n\n const requestBody = { input };\n const url = this.getRunpodRunUrl();\n const effectiveBaseURL =\n withoutTrailingSlash(this.config.baseURL) ?? this.config.baseURL;\n\n // Submit the job\n const { value: response, responseHeaders } = await postJsonToApi({\n url,\n headers: {\n ...this.config.headers(),\n ...headers,\n },\n body: requestBody,\n failedResponseHandler: runpodTranscriptionFailedResponseHandler,\n successfulResponseHandler: createJsonResponseHandler(\n runpodJobResponseSchema as any\n ),\n abortSignal,\n fetch: this.config.fetch,\n });\n\n const typedResponse = response as z.infer<typeof runpodJobResponseSchema>;\n\n // Get job ID for polling\n const jobId = typedResponse.id;\n if (!jobId) {\n throw new Error(\n 'Runpod transcription response did not include a job id.'\n );\n }\n\n // Poll for completion\n const pollOptions = {\n maxAttempts: (runpodOptions.maxPollAttempts as number | undefined) ?? 120,\n pollIntervalMillis: (runpodOptions.pollIntervalMillis as number | undefined) ?? 2000,\n };\n\n const result = await this.pollForCompletion(\n jobId,\n abortSignal,\n pollOptions,\n effectiveBaseURL\n );\n\n // Parse the transcription output\n // Note: RunPod Whisper may return 'result' or 'text' depending on the worker version\n const output = result.output;\n const text = output?.text ?? output?.result ?? '';\n const segments = this.parseSegments(output);\n const language = output?.language;\n const durationInSeconds = output?.duration;\n\n const providerMetadata: Record<string, Record<string, JSONValue>> = {\n runpod: {\n jobId,\n },\n };\n\n return {\n text,\n segments,\n language,\n durationInSeconds,\n warnings,\n request: {\n body: JSON.stringify(requestBody),\n },\n response: {\n timestamp: currentDate,\n modelId: this.modelId,\n headers: responseHeaders,\n body: JSON.stringify(result),\n },\n providerMetadata,\n };\n }\n\n private convertAudioToBase64(\n audio: TranscriptionModelV3CallOptions['audio']\n ): string {\n if (typeof audio === 'string') {\n // Already base64 encoded\n return audio;\n }\n\n // Convert Uint8Array to base64\n return this.uint8ArrayToBase64(audio);\n }\n\n private uint8ArrayToBase64(data: Uint8Array): string {\n // Use Buffer in Node.js environment for efficiency\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(data).toString('base64');\n }\n // Fallback for browser environment\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 extractRunpodOptions(\n providerOptions: Record<string, unknown> | undefined\n ): Record<string, unknown> {\n if (!providerOptions) return {};\n const runpod = providerOptions.runpod;\n if (isRecord(runpod)) {\n return runpod;\n }\n return {};\n }\n\n private async pollForCompletion(\n jobId: string,\n abortSignal?: AbortSignal,\n pollOptions?: { maxAttempts?: number; pollIntervalMillis?: number },\n effectiveBaseURL?: string\n ): Promise<z.infer<typeof runpodStatusResponseSchema>> {\n const maxAttempts = pollOptions?.maxAttempts ?? 120;\n const pollInterval = pollOptions?.pollIntervalMillis ?? 2000;\n const baseURL = effectiveBaseURL ?? this.config.baseURL;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n if (abortSignal?.aborted) {\n throw new Error('Transcription was aborted');\n }\n\n const { value: statusResponse } = await getFromApi({\n url: `${baseURL}/status/${jobId}`,\n headers: this.config.headers(),\n successfulResponseHandler: createJsonResponseHandler(\n runpodStatusResponseSchema as any\n ),\n failedResponseHandler: runpodTranscriptionFailedResponseHandler,\n abortSignal,\n fetch: this.config.fetch,\n });\n\n const typedStatusResponse =\n statusResponse as z.infer<typeof runpodStatusResponseSchema>;\n\n if (typedStatusResponse.status === 'COMPLETED') {\n return typedStatusResponse;\n }\n\n if (typedStatusResponse.status === 'FAILED') {\n throw new Error(\n `Transcription 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 `Transcription timed out after ${maxAttempts} attempts (${(maxAttempts * pollInterval) / 1000}s)`\n );\n }\n\n private parseSegments(\n output: z.infer<typeof runpodStatusResponseSchema>['output']\n ): Array<{ text: string; startSecond: number; endSecond: number }> {\n if (!output?.segments || !Array.isArray(output.segments)) {\n return [];\n }\n\n return output.segments.map((segment) => ({\n text: segment.text ?? '',\n startSecond: segment.start ?? 0,\n endSecond: segment.end ?? 0,\n }));\n }\n}\n"],"mappings":"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","names":["withoutTrailingSlash","z","z","withoutTrailingSlash","createJsonResponseHandler","getFromApi","postJsonToApi","z","isRecord","z","withoutTrailingSlash","postJsonToApi","createJsonResponseHandler","runpod","getFromApi","withoutTrailingSlash"]}
1
+ {"version":3,"sources":["../src/runpod-provider.ts","../src/runpod-image-model.ts","../src/runpod-error.ts","../src/runpod-speech-model.ts","../src/runpod-transcription-model.ts","../src/runpod-video-model.ts"],"sourcesContent":["import {\n Experimental_VideoModelV3,\n ImageModelV3,\n LanguageModelV3,\n SpeechModelV3,\n TranscriptionModelV3,\n} 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';\nimport { RunpodTranscriptionModel } from './runpod-transcription-model';\nimport { RunpodVideoModel } from './runpod-video-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 /**\nCreates a transcription model for audio transcription.\n*/\n transcriptionModel(modelId: string): TranscriptionModelV3;\n\n /**\nCreates a transcription model for audio transcription.\n*/\n transcription(modelId: string): TranscriptionModelV3;\n\n /**\nCreates a video model for video generation.\n*/\n videoModel(modelId: string): Experimental_VideoModelV3;\n\n /**\nCreates a video model for video generation.\n*/\n video(modelId: string): Experimental_VideoModelV3;\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 'qwen/qwen-image-edit-2511': 'https://api.runpod.ai/v2/qwen-image-edit-2511',\n 'qwen/qwen-image-edit-2511-lora':\n 'https://api.runpod.ai/v2/qwen-image-edit-2511-lora',\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 // Alibaba Wan 2.6 (t2i)\n 'alibaba/wan-2.6': 'https://api.runpod.ai/v2/wan-2-6-t2i',\n // Tongyi Z-Image Turbo (t2i)\n 'tongyi-mai/z-image-turbo': 'https://api.runpod.ai/v2/z-image-turbo',\n 'z-image-turbo': 'https://api.runpod.ai/v2/z-image-turbo', // alias, not advertised\n // Nano Banana (edit only)\n 'google/nano-banana-edit': 'https://api.runpod.ai/v2/nano-banana-edit',\n 'nano-banana-edit': 'https://api.runpod.ai/v2/nano-banana-edit', // backwards compatibility\n // Nano Banana 2 (edit only)\n 'google/nano-banana-2-edit':\n 'https://api.runpod.ai/v2/google-nano-banana-2-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 transcription model IDs to their serverless endpoint URLs\nconst TRANSCRIPTION_MODEL_ID_TO_ENDPOINT_URL: Record<string, string> = {\n 'pruna/whisper-v3-large': 'https://api.runpod.ai/v2/whisper-v3-large',\n};\n\n// Mapping of Runpod video model IDs to their serverless endpoint URLs\nconst VIDEO_MODEL_ID_TO_ENDPOINT_URL: Record<string, string> = {\n 'pruna/p-video': 'https://api.runpod.ai/v2/p-video',\n 'vidu/q3-t2v': 'https://api.runpod.ai/v2/vidu-q3-t2v',\n 'vidu/q3-i2v': 'https://api.runpod.ai/v2/vidu-q3-i2v',\n 'kwaivgi/kling-v2.6-std-motion-control':\n 'https://api.runpod.ai/v2/kling-v2-6-std-motion-control',\n 'kwaivgi/kling-video-o1-r2v': 'https://api.runpod.ai/v2/kling-video-o1-r2v',\n 'kwaivgi/kling-v2.1-i2v-pro': 'https://api.runpod.ai/v2/kling-v2-1-i2v-pro',\n 'alibaba/wan-2.6-t2v': 'https://api.runpod.ai/v2/wan-2-6-t2v',\n 'alibaba/wan-2.6-i2v': 'https://api.runpod.ai/v2/wan-2-6-i2v',\n 'alibaba/wan-2.5': 'https://api.runpod.ai/v2/wan-2-5',\n 'alibaba/wan-2.2-t2v-720-lora':\n 'https://api.runpod.ai/v2/wan-2-2-t2v-720-lora',\n 'alibaba/wan-2.2-i2v-720': 'https://api.runpod.ai/v2/wan-2-2-i2v-720',\n 'alibaba/wan-2.1-i2v-720': 'https://api.runpod.ai/v2/wan-2-1-i2v-720',\n 'bytedance/seedance-v1.5-pro-i2v':\n 'https://api.runpod.ai/v2/seedance-v1-5-pro-i2v',\n 'openai/sora-2-pro-i2v': 'https://api.runpod.ai/v2/sora-2-pro-i2v',\n 'openai/sora-2-i2v': 'https://api.runpod.ai/v2/sora-2-i2v',\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 const endpointIdFromConsole = parseRunpodConsoleEndpointId(modelId);\n const normalizedModelId = endpointIdFromConsole ?? modelId;\n\n // Prefer explicit mapping for known image model IDs.\n const mappedBaseURL = IMAGE_MODEL_ID_TO_ENDPOINT_URL[normalizedModelId];\n\n const baseURL =\n options.baseURL ??\n mappedBaseURL ??\n (normalizedModelId.startsWith('http')\n ? normalizedModelId\n : `https://api.runpod.ai/v2/${normalizedModelId}`);\n\n return new RunpodImageModel(normalizedModelId, {\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 createTranscriptionModel = (modelId: string) => {\n const endpointIdFromConsole = parseRunpodConsoleEndpointId(modelId);\n const normalizedModelId = endpointIdFromConsole ?? modelId;\n\n // Prefer explicit mapping for known transcription model IDs.\n const mappedBaseURL =\n TRANSCRIPTION_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 RunpodTranscriptionModel(normalizedModelId, {\n provider: 'runpod.transcription',\n baseURL,\n headers: getHeaders,\n fetch: runpodFetch,\n });\n };\n\n const createVideoModel = (modelId: string) => {\n const endpointIdFromConsole = parseRunpodConsoleEndpointId(modelId);\n const normalizedModelId = endpointIdFromConsole ?? modelId;\n\n // Prefer explicit mapping for known video model IDs.\n const mappedBaseURL = VIDEO_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 RunpodVideoModel(normalizedModelId, {\n provider: 'runpod.video',\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 provider.image = createImageModel;\n provider.speechModel = createSpeechModel;\n provider.speech = createSpeechModel;\n provider.transcriptionModel = createTranscriptionModel;\n provider.transcription = createTranscriptionModel;\n provider.videoModel = createVideoModel;\n provider.video = createVideoModel;\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 for most models)\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 '1280*1280', // wan-2.6 max\n '1536*1536',\n '2048*2048',\n '4096*4096',\n '512*768',\n '768*512',\n '1024*768',\n '768*1024',\n]);\n\n// Z-Image Turbo supported sizes (validated working sizes)\nconst Z_IMAGE_TURBO_SUPPORTED_SIZES = new Set([\n '1328*1328', // 1:1\n '1472*1140', // 4:3\n '1140*1472', // 3:4\n '512*512',\n '768*768',\n '1024*1024',\n '1280*1280',\n '1536*1536',\n '512*768',\n '768*512',\n '1024*768',\n '768*1024',\n '768*432',\n '1024*576',\n '1280*720',\n '1536*864',\n '432*768',\n '576*1024',\n '720*1280',\n '864*1536',\n]);\n\nconst Z_IMAGE_TURBO_ASPECT_RATIOS: Record<string, string> = {\n '1:1': '1328*1328',\n '4:3': '1472*1140',\n '3:4': '1140*1472',\n '3:2': '768*512',\n '2:3': '512*768',\n '16:9': '1280*720',\n '9:16': '720*1280',\n};\n\nconst MODEL_SUPPORTED_SIZES: Record<string, Set<string>> = {\n 'tongyi-mai/z-image-turbo': Z_IMAGE_TURBO_SUPPORTED_SIZES,\n 'z-image-turbo': Z_IMAGE_TURBO_SUPPORTED_SIZES, // alias, not advertised\n};\n\nconst MODEL_SUPPORTED_ASPECT_RATIOS: Record<string, Record<string, string>> = {\n 'tongyi-mai/z-image-turbo': Z_IMAGE_TURBO_ASPECT_RATIOS,\n 'z-image-turbo': Z_IMAGE_TURBO_ASPECT_RATIOS, // alias, not advertised\n};\n\n// WAN 2.6 specific aspect ratio to size mappings\n// Total pixels must be between 768*768 (589,824) and 1280*1280 (1,638,400)\n// Aspect ratio must be between 1:4 and 4:1\nconst WAN_ASPECT_RATIOS: Record<string, string> = {\n '1:1': '1280*1280', // 1,638,400 pixels\n '2:3': '800*1200', // 960,000 pixels\n '3:2': '1200*800', // 960,000 pixels\n '3:4': '960*1280', // 1,228,800 pixels\n '4:3': '1280*960', // 1,228,800 pixels\n '9:16': '720*1280', // 921,600 pixels\n '16:9': '1280*720', // 921,600 pixels\n '21:9': '1344*576', // 774,144 pixels\n '9:21': '576*1344', // 774,144 pixels\n};\n\n// WAN 2.6 pixel constraints\nconst WAN_MIN_PIXELS = 768 * 768; // 589,824\nconst WAN_MAX_PIXELS = 1280 * 1280; // 1,638,400\nconst WAN_MIN_ASPECT_RATIO = 1 / 4; // 1:4\nconst WAN_MAX_ASPECT_RATIO = 4 / 1; // 4:1\n\n/**\n * Validates a size string for WAN 2.6 constraints.\n * Returns true if valid, throws InvalidArgumentError if not.\n */\nfunction validateWanSize(size: string): boolean {\n const [widthStr, heightStr] = size.split('*');\n const width = parseInt(widthStr, 10);\n const height = parseInt(heightStr, 10);\n\n if (isNaN(width) || isNaN(height)) {\n throw new InvalidArgumentError({\n argument: 'size',\n message: `Invalid size format: ${size}. Expected format: WIDTHxHEIGHT or WIDTH*HEIGHT`,\n });\n }\n\n const totalPixels = width * height;\n const aspectRatio = width / height;\n\n if (totalPixels < WAN_MIN_PIXELS || totalPixels > WAN_MAX_PIXELS) {\n throw new InvalidArgumentError({\n argument: 'size',\n message: `Size ${size} has ${totalPixels} pixels, which is outside the valid range for WAN 2.6 (${WAN_MIN_PIXELS} to ${WAN_MAX_PIXELS} pixels). Try 1280x1280 or 1024x1024.`,\n });\n }\n\n if (\n aspectRatio < WAN_MIN_ASPECT_RATIO ||\n aspectRatio > WAN_MAX_ASPECT_RATIO\n ) {\n throw new InvalidArgumentError({\n argument: 'size',\n message: `Size ${size} has aspect ratio ${aspectRatio.toFixed(2)}, which is outside the valid range for WAN 2.6 (1:4 to 4:1).`,\n });\n }\n\n return true;\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 // Check if this is a Nano Banana 2 model (skip standard size/aspectRatio validation)\n const isNanoBanana2Model = this.modelId.includes('nano-banana-2');\n\n // Check if this is a WAN model (uses WAN-specific pixel/aspect ratio constraints)\n const isWanModel = this.modelId.includes('wan-2');\n\n // Determine the size to use\n let runpodSize: string;\n\n if (isPrunaModel || isNanoBananaProModel || isNanoBanana2Model) {\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 (isWanModel) {\n // WAN 2.6 has specific pixel and aspect ratio constraints\n // Total pixels: 768*768 (589,824) to 1280*1280 (1,638,400)\n // Aspect ratio: 1:4 to 4:1\n if (size) {\n const runpodSizeCandidate = size.replace('x', '*');\n validateWanSize(runpodSizeCandidate);\n runpodSize = runpodSizeCandidate;\n } else if (aspectRatio) {\n if (!WAN_ASPECT_RATIOS[aspectRatio]) {\n throw new InvalidArgumentError({\n argument: 'aspectRatio',\n message: `Aspect ratio ${aspectRatio} is not supported by WAN 2.6. Supported aspect ratios: ${Object.keys(WAN_ASPECT_RATIOS).join(', ')}`,\n });\n }\n runpodSize = WAN_ASPECT_RATIOS[aspectRatio];\n } else {\n // Default to 1280*1280 for WAN models\n runpodSize = '1280*1280';\n }\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 const supportedSizes =\n MODEL_SUPPORTED_SIZES[this.modelId] ?? SUPPORTED_SIZES;\n if (!supportedSizes.has(runpodSizeCandidate)) {\n throw new InvalidArgumentError({\n argument: 'size',\n message: `Size ${size} is not supported by Runpod. Supported sizes: ${Array.from(\n supportedSizes\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 const supportedAspectRatios =\n MODEL_SUPPORTED_ASPECT_RATIOS[this.modelId] ?? SUPPORTED_ASPECT_RATIOS;\n if (!supportedAspectRatios[aspectRatio]) {\n throw new InvalidArgumentError({\n argument: 'aspectRatio',\n message: `Aspect ratio ${aspectRatio} is not supported by Runpod. Supported aspect ratios: ${Object.keys(\n supportedAspectRatios\n ).join(', ')}`,\n });\n }\n\n // Use supported aspect ratio mapping\n runpodSize = supportedAspectRatios[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 // Determine the effective baseURL (may switch for LoRA models)\n let effectiveBaseURL = this.config.baseURL;\n const runpodOptions = providerOptions.runpod as\n | Record<string, unknown>\n | undefined;\n if (\n this.modelId.includes('qwen-image-edit-2511') &&\n !this.modelId.includes('lora') &&\n runpodOptions?.loras &&\n Array.isArray(runpodOptions.loras) &&\n runpodOptions.loras.length > 0\n ) {\n // Switch to LoRA endpoint when loras are provided\n effectiveBaseURL = this.config.baseURL.replace(\n 'qwen-image-edit-2511',\n 'qwen-image-edit-2511-lora'\n );\n }\n\n const { value: response, responseHeaders } = await postJsonToApi({\n url: `${effectiveBaseURL}/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 effectiveBaseURL\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 if (typedResponse.status === 'FAILED') {\n throw new Error(\n `Image generation failed: ${typedResponse.error || 'Unknown error'}`\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 effectiveBaseURL?: string\n ): Promise<string> {\n const maxAttempts = pollOptions?.maxAttempts ?? 60; // 5 minutes with 5-second intervals\n const pollInterval = pollOptions?.pollIntervalMillis ?? 5000; // 5 seconds\n const baseURL = effectiveBaseURL ?? this.config.baseURL;\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: `${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 2 model (google/nano-banana-2-edit)\n const isNanoBanana2Model = this.modelId.includes('nano-banana-2');\n if (isNanoBanana2Model) {\n // Nano Banana 2 image edit\n // Supported aspect_ratio: \"1:1\", \"3:2\", \"2:3\", \"3:4\", \"4:3\", \"4:5\", \"5:4\", \"9:16\", \"16:9\", \"21:9\", \"1:4\", \"4:1\", \"1:8\", \"8:1\"\n // Supported resolution: \"1k\", \"2k\", \"4k\"\n // Supported output_format: \"jpeg\", \"png\"\n const nanoBanana2Payload: 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_safety_checker:\n (runpodOptions?.enable_safety_checker as boolean) ?? true,\n };\n\n // Use standardized files if provided, otherwise use providerOptions.images\n if (standardizedImages && standardizedImages.length > 0) {\n nanoBanana2Payload.images = standardizedImages;\n } else if (runpodOptions?.images) {\n nanoBanana2Payload.images = runpodOptions.images;\n }\n\n return nanoBanana2Payload;\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: (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 // Check if this is a Nano Banana (non-pro) edit model\n const isNanaBananaEditModel =\n this.modelId.includes('nano-banana-edit') &&\n !this.modelId.includes('nano-banana-pro');\n if (isNanaBananaEditModel) {\n // Nano Banana edit uses simple format: prompt, images array, enable_safety_checker\n const nanoBananaEditPayload: Record<string, unknown> = {\n prompt,\n enable_safety_checker: runpodOptions?.enable_safety_checker ?? true,\n };\n\n // Always use images array format\n if (standardizedImages && standardizedImages.length > 0) {\n nanoBananaEditPayload.images = standardizedImages;\n } else if (runpodOptions?.images) {\n nanoBananaEditPayload.images = runpodOptions.images;\n }\n\n return nanoBananaEditPayload;\n }\n\n // Check if this is a Qwen Image Edit 2511 model (uses images array format)\n const isQwenImageEdit2511 = this.modelId.includes('qwen-image-edit-2511');\n if (isQwenImageEdit2511) {\n // Qwen Image Edit 2511 uses images array, output_format, and sync options\n const qwenEdit2511Payload: Record<string, unknown> = {\n prompt,\n size: runpodSize,\n seed: seed ?? -1,\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: (runpodOptions?.enable_sync_mode as boolean) ?? false,\n ...runpodOptions,\n };\n\n // Always use images array format for this model\n if (standardizedImages && standardizedImages.length > 0) {\n qwenEdit2511Payload.images = standardizedImages;\n } else if (runpodOptions?.images) {\n qwenEdit2511Payload.images = runpodOptions.images;\n }\n\n return qwenEdit2511Payload;\n }\n\n // Check if this is Tongyi Z-Image Turbo (t2i)\n const isZImageTurbo =\n this.modelId === 'tongyi-mai/z-image-turbo' ||\n this.modelId === 'z-image-turbo';\n if (isZImageTurbo) {\n const zImageTurboPayload: Record<string, unknown> = {\n prompt,\n size: runpodSize,\n seed: seed ?? -1,\n output_format: (runpodOptions?.output_format as string) ?? 'png',\n enable_safety_checker: runpodOptions?.enable_safety_checker ?? true,\n ...runpodOptions,\n };\n\n if (standardizedImages && standardizedImages.length > 0) {\n if (standardizedImages.length === 1) {\n zImageTurboPayload.image = standardizedImages[0];\n } else {\n zImageTurboPayload.images = standardizedImages;\n }\n }\n\n return zImageTurboPayload;\n }\n\n // Check if this is an Alibaba Wan model\n const isWanModel = this.modelId.includes('wan-2');\n if (isWanModel) {\n // Alibaba Wan 2.6 uses standard t2i format with negative prompt in prompt string\n return {\n prompt,\n size: runpodSize,\n seed: seed ?? -1,\n enable_safety_checker: runpodOptions?.enable_safety_checker ?? true,\n ...runpodOptions,\n };\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 error: z.string().optional(), // Error message if FAILED\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';\nimport { createJsonErrorResponseHandler } from '@ai-sdk/provider-utils';\n\n// Runpod image API error schema (supports both error formats)\nexport const runpodImageErrorSchema = z.object({\n error: z.string().optional(),\n message: z.string().optional(),\n});\n\nexport type RunpodImageErrorData = z.infer<typeof runpodImageErrorSchema>;\n\n// Helper function to extract error message from Runpod error data\nfunction extractErrorMessage(data: RunpodImageErrorData): string {\n // Prefer message if available (more descriptive)\n if (data.message) {\n return data.message;\n }\n\n // If error field exists, try to extract nested JSON message\n if (data.error) {\n // Runpod sometimes returns nested JSON in the error field like:\n // \"Error submitting task: 400, {\\\"code\\\":400,\\\"message\\\":\\\"...\\\"}\"\n // Try to extract the inner message for cleaner error messages\n // Find the last occurrence of { which likely starts the JSON object\n const lastBraceIndex = data.error.lastIndexOf('{');\n if (lastBraceIndex !== -1) {\n try {\n const jsonStr = data.error.substring(lastBraceIndex);\n const nestedError = JSON.parse(jsonStr);\n if (nestedError.message && typeof nestedError.message === 'string') {\n return nestedError.message;\n }\n } catch {\n // If parsing fails, fall back to the original error string\n }\n }\n return data.error;\n }\n\n return 'Unknown Runpod error';\n}\n\nexport const runpodImageFailedResponseHandler = createJsonErrorResponseHandler({\n errorSchema: runpodImageErrorSchema as any,\n errorToMessage: extractErrorMessage,\n});\n\nexport const runpodTranscriptionFailedResponseHandler =\n createJsonErrorResponseHandler({\n errorSchema: runpodImageErrorSchema as any,\n errorToMessage: extractErrorMessage,\n });\n\nexport const runpodVideoFailedResponseHandler = createJsonErrorResponseHandler({\n errorSchema: runpodImageErrorSchema as any,\n errorToMessage: extractErrorMessage,\n});\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 // Check for FAILED status and surface the actual error message\n if (parsed?.status === 'FAILED') {\n throw new Error(\n `Speech generation failed: ${parsed.error || 'Unknown error'}`\n );\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","import {\n JSONValue,\n TranscriptionModelV3,\n TranscriptionModelV3CallOptions,\n SharedV3Warning,\n} from '@ai-sdk/provider';\nimport {\n FetchFunction,\n withoutTrailingSlash,\n createJsonResponseHandler,\n getFromApi,\n postJsonToApi,\n} from '@ai-sdk/provider-utils';\nimport { z } from 'zod';\nimport { runpodTranscriptionFailedResponseHandler } from './runpod-error';\n\nexport interface RunpodTranscriptionModelConfig {\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\n// Schema for the job submission response\nconst runpodJobResponseSchema = z.object({\n id: z.string(),\n status: z.string().optional(),\n});\n\n// Schema for the status polling response\n// Note: RunPod Whisper may return 'result' or 'text' depending on the worker version\nconst runpodStatusResponseSchema = z.object({\n id: z.string().optional(),\n status: z.string(),\n output: z\n .object({\n text: z.string().optional(),\n result: z.string().optional(), // Some workers use 'result' instead of 'text'\n segments: z\n .array(\n z.object({\n text: z.string().optional(),\n start: z.number().optional(),\n end: z.number().optional(),\n })\n )\n .optional(),\n language: z.string().optional(),\n duration: z.number().optional(),\n cost: z.number().optional(),\n })\n .optional(),\n error: z.string().optional(),\n});\n\nexport class RunpodTranscriptionModel implements TranscriptionModelV3 {\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: RunpodTranscriptionModelConfig\n ) {}\n\n private getRunpodRunUrl(): 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 // Use /run for async jobs (Whisper can take time)\n return `${baseURL}/run`;\n }\n\n async doGenerate(\n options: TranscriptionModelV3CallOptions\n ): Promise<Awaited<ReturnType<TranscriptionModelV3['doGenerate']>>> {\n const currentDate = this.config._internal?.currentDate?.() ?? new Date();\n\n const warnings: SharedV3Warning[] = [];\n\n const { audio, providerOptions, abortSignal, headers } = options;\n\n // Extract Runpod-specific options\n const runpodOptions = this.extractRunpodOptions(providerOptions);\n\n // Build input - RunPod Whisper accepts either 'audio' (URL) or 'audio_base64' (base64 string)\n const input: Record<string, unknown> = {};\n\n // Check if user provided an audio URL directly via providerOptions\n if (runpodOptions.audio && typeof runpodOptions.audio === 'string') {\n input.audio = runpodOptions.audio;\n } else {\n // Convert the AI SDK audio input to base64 for RunPod\n const base64Audio = this.convertAudioToBase64(audio);\n input.audio_base64 = base64Audio;\n }\n\n // Add optional parameters\n if (runpodOptions.prompt || runpodOptions.initial_prompt) {\n input.initial_prompt = runpodOptions.prompt ?? runpodOptions.initial_prompt;\n }\n if (runpodOptions.language) {\n input.language = runpodOptions.language;\n }\n if (runpodOptions.word_timestamps !== undefined) {\n input.word_timestamps = runpodOptions.word_timestamps;\n }\n // Pass through other Whisper-specific options\n if (runpodOptions.model) {\n input.model = runpodOptions.model;\n }\n if (runpodOptions.transcription) {\n input.transcription = runpodOptions.transcription;\n }\n if (runpodOptions.translate !== undefined) {\n input.translate = runpodOptions.translate;\n }\n if (runpodOptions.enable_vad !== undefined) {\n input.enable_vad = runpodOptions.enable_vad;\n }\n\n const requestBody = { input };\n const url = this.getRunpodRunUrl();\n const effectiveBaseURL =\n withoutTrailingSlash(this.config.baseURL) ?? this.config.baseURL;\n\n // Submit the job\n const { value: response, responseHeaders } = await postJsonToApi({\n url,\n headers: {\n ...this.config.headers(),\n ...headers,\n },\n body: requestBody,\n failedResponseHandler: runpodTranscriptionFailedResponseHandler,\n successfulResponseHandler: createJsonResponseHandler(\n runpodJobResponseSchema as any\n ),\n abortSignal,\n fetch: this.config.fetch,\n });\n\n const typedResponse = response as z.infer<typeof runpodJobResponseSchema>;\n\n // Get job ID for polling\n const jobId = typedResponse.id;\n if (!jobId) {\n throw new Error(\n 'Runpod transcription response did not include a job id.'\n );\n }\n\n // Poll for completion\n const pollOptions = {\n maxAttempts: (runpodOptions.maxPollAttempts as number | undefined) ?? 120,\n pollIntervalMillis: (runpodOptions.pollIntervalMillis as number | undefined) ?? 2000,\n };\n\n const result = await this.pollForCompletion(\n jobId,\n abortSignal,\n pollOptions,\n effectiveBaseURL\n );\n\n // Parse the transcription output\n // Note: RunPod Whisper may return 'result' or 'text' depending on the worker version\n const output = result.output;\n const text = output?.text ?? output?.result ?? '';\n const segments = this.parseSegments(output);\n const language = output?.language;\n const durationInSeconds = output?.duration;\n\n const providerMetadata: Record<string, Record<string, JSONValue>> = {\n runpod: {\n jobId,\n },\n };\n\n return {\n text,\n segments,\n language,\n durationInSeconds,\n warnings,\n request: {\n body: JSON.stringify(requestBody),\n },\n response: {\n timestamp: currentDate,\n modelId: this.modelId,\n headers: responseHeaders,\n body: JSON.stringify(result),\n },\n providerMetadata,\n };\n }\n\n private convertAudioToBase64(\n audio: TranscriptionModelV3CallOptions['audio']\n ): string {\n if (typeof audio === 'string') {\n // Already base64 encoded\n return audio;\n }\n\n // Convert Uint8Array to base64\n return this.uint8ArrayToBase64(audio);\n }\n\n private uint8ArrayToBase64(data: Uint8Array): string {\n // Use Buffer in Node.js environment for efficiency\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(data).toString('base64');\n }\n // Fallback for browser environment\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 extractRunpodOptions(\n providerOptions: Record<string, unknown> | undefined\n ): Record<string, unknown> {\n if (!providerOptions) return {};\n const runpod = providerOptions.runpod;\n if (isRecord(runpod)) {\n return runpod;\n }\n return {};\n }\n\n private async pollForCompletion(\n jobId: string,\n abortSignal?: AbortSignal,\n pollOptions?: { maxAttempts?: number; pollIntervalMillis?: number },\n effectiveBaseURL?: string\n ): Promise<z.infer<typeof runpodStatusResponseSchema>> {\n const maxAttempts = pollOptions?.maxAttempts ?? 120;\n const pollInterval = pollOptions?.pollIntervalMillis ?? 2000;\n const baseURL = effectiveBaseURL ?? this.config.baseURL;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n if (abortSignal?.aborted) {\n throw new Error('Transcription was aborted');\n }\n\n const { value: statusResponse } = await getFromApi({\n url: `${baseURL}/status/${jobId}`,\n headers: this.config.headers(),\n successfulResponseHandler: createJsonResponseHandler(\n runpodStatusResponseSchema as any\n ),\n failedResponseHandler: runpodTranscriptionFailedResponseHandler,\n abortSignal,\n fetch: this.config.fetch,\n });\n\n const typedStatusResponse =\n statusResponse as z.infer<typeof runpodStatusResponseSchema>;\n\n if (typedStatusResponse.status === 'COMPLETED') {\n return typedStatusResponse;\n }\n\n if (typedStatusResponse.status === 'FAILED') {\n throw new Error(\n `Transcription 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 `Transcription timed out after ${maxAttempts} attempts (${(maxAttempts * pollInterval) / 1000}s)`\n );\n }\n\n private parseSegments(\n output: z.infer<typeof runpodStatusResponseSchema>['output']\n ): Array<{ text: string; startSecond: number; endSecond: number }> {\n if (!output?.segments || !Array.isArray(output.segments)) {\n return [];\n }\n\n return output.segments.map((segment) => ({\n text: segment.text ?? '',\n startSecond: segment.start ?? 0,\n endSecond: segment.end ?? 0,\n }));\n }\n}\n","import {\n JSONValue,\n Experimental_VideoModelV3 as VideoModelV3,\n Experimental_VideoModelV3CallOptions as VideoModelV3CallOptions,\n Experimental_VideoModelV3File as VideoModelV3File,\n SharedV3Warning,\n} from '@ai-sdk/provider';\nimport {\n FetchFunction,\n withoutTrailingSlash,\n createJsonResponseHandler,\n getFromApi,\n postJsonToApi,\n} from '@ai-sdk/provider-utils';\nimport { z } from 'zod';\nimport { runpodVideoFailedResponseHandler } from './runpod-error';\n\nexport interface RunpodVideoModelConfig {\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\n// Schema for the job submission response\nconst runpodVideoJobResponseSchema = z.object({\n id: z.string(),\n status: z.string().optional(),\n});\n\n// Schema for the status polling response\nconst runpodVideoStatusSchema = z.object({\n id: z.string().optional(),\n status: z.string(),\n output: z.unknown().optional(),\n error: z.string().optional(),\n});\n\nexport class RunpodVideoModel implements VideoModelV3 {\n readonly specificationVersion = 'v3';\n readonly maxVideosPerCall = 1;\n\n get provider(): string {\n return this.config.provider;\n }\n\n constructor(\n readonly modelId: string,\n private readonly config: RunpodVideoModelConfig\n ) {}\n\n private getRunpodRunUrl(): string {\n const baseURL =\n withoutTrailingSlash(this.config.baseURL) ?? this.config.baseURL;\n\n if (baseURL.endsWith('/run') || baseURL.endsWith('/runsync')) {\n return baseURL;\n }\n\n return `${baseURL}/run`;\n }\n\n async doGenerate(\n options: VideoModelV3CallOptions\n ): Promise<Awaited<ReturnType<VideoModelV3['doGenerate']>>> {\n const currentDate = this.config._internal?.currentDate?.() ?? new Date();\n\n const warnings: SharedV3Warning[] = [];\n\n if (options.n > 1) {\n warnings.push({\n type: 'unsupported',\n feature: 'n > 1',\n details:\n 'Runpod video models only support generating 1 video per call. Only 1 video will be generated.',\n });\n }\n\n const { providerOptions, abortSignal, headers } = options;\n\n const runpodOptions = this.extractRunpodOptions(providerOptions);\n\n const input = this.buildInputPayload(options, runpodOptions);\n\n const requestBody = { input };\n const url = this.getRunpodRunUrl();\n const effectiveBaseURL =\n withoutTrailingSlash(this.config.baseURL) ?? this.config.baseURL;\n\n // Submit the job\n const { value: response, responseHeaders } = await postJsonToApi({\n url,\n headers: {\n ...this.config.headers(),\n ...headers,\n },\n body: requestBody,\n failedResponseHandler: runpodVideoFailedResponseHandler,\n successfulResponseHandler: createJsonResponseHandler(\n runpodVideoJobResponseSchema as any\n ),\n abortSignal,\n fetch: this.config.fetch,\n });\n\n const typedResponse = response as z.infer<\n typeof runpodVideoJobResponseSchema\n >;\n\n const jobId = typedResponse.id;\n if (!jobId) {\n throw new Error('Runpod video response did not include a job id.');\n }\n\n // Poll for completion\n const pollOptions = {\n maxAttempts: (runpodOptions.maxPollAttempts as number | undefined) ?? 120,\n pollIntervalMillis:\n (runpodOptions.pollIntervalMillis as number | undefined) ?? 5000,\n };\n\n const result = await this.pollForCompletion(\n jobId,\n abortSignal,\n pollOptions,\n effectiveBaseURL\n );\n\n const videoUrl = this.extractVideoUrl(result.output);\n\n const providerMetadata: Record<string, Record<string, JSONValue>> = {\n runpod: {\n jobId,\n },\n };\n\n return {\n videos: [{ type: 'url', url: videoUrl, mediaType: 'video/mp4' }],\n warnings,\n response: {\n timestamp: currentDate,\n modelId: this.modelId,\n headers: responseHeaders,\n },\n providerMetadata,\n };\n }\n\n private buildInputPayload(\n options: VideoModelV3CallOptions,\n runpodOptions: Record<string, unknown>\n ): Record<string, unknown> {\n // Filter out polling options — they should not be sent to the API\n const apiOptions = Object.fromEntries(\n Object.entries(runpodOptions).filter(\n ([key]) => key !== 'maxPollAttempts' && key !== 'pollIntervalMillis'\n )\n );\n\n const input: Record<string, unknown> = {\n ...apiOptions,\n };\n\n if (options.prompt) {\n input.prompt = options.prompt;\n }\n\n if (options.duration !== undefined) {\n input.duration = options.duration;\n }\n\n if (options.fps !== undefined) {\n input.fps = options.fps;\n }\n\n if (options.seed !== undefined) {\n input.seed = options.seed;\n }\n\n // Convert resolution from WxH (e.g. \"1280x720\") to size with * (e.g. \"1280*720\")\n if (options.resolution) {\n input.size = options.resolution.replace('x', '*');\n } else if (options.aspectRatio) {\n input.aspect_ratio = options.aspectRatio;\n }\n\n if (options.image) {\n input.image = this.convertFileToRunpodFormat(options.image);\n }\n\n return input;\n }\n\n private convertFileToRunpodFormat(file: VideoModelV3File): string {\n if (file.type === 'url') {\n return file.url;\n }\n\n // file.type === 'file' — convert to base64 data URL\n const mediaType = file.mediaType;\n const data = file.data;\n\n if (typeof data === 'string') {\n // Already base64 — wrap in data URL\n return `data:${mediaType};base64,${data}`;\n }\n\n // Uint8Array — encode to base64 data URL\n const base64 = this.uint8ArrayToBase64(data);\n return `data:${mediaType};base64,${base64}`;\n }\n\n private uint8ArrayToBase64(data: Uint8Array): string {\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(data).toString('base64');\n }\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 extractRunpodOptions(\n providerOptions: Record<string, unknown> | undefined\n ): Record<string, unknown> {\n if (!providerOptions) return {};\n const runpod = providerOptions.runpod;\n if (isRecord(runpod)) {\n return runpod;\n }\n return {};\n }\n\n private extractVideoUrl(output: unknown): string {\n if (isRecord(output)) {\n // Check common output field names\n if (typeof output.video_url === 'string') return output.video_url;\n if (typeof output.result === 'string') return output.result;\n if (typeof output.url === 'string') return output.url;\n }\n\n // If output is a string URL directly\n if (typeof output === 'string') {\n return output;\n }\n\n throw new Error(\n `Runpod video generation completed but no video URL was found in the output: ${JSON.stringify(output)}`\n );\n }\n\n private async pollForCompletion(\n jobId: string,\n abortSignal?: AbortSignal,\n pollOptions?: { maxAttempts?: number; pollIntervalMillis?: number },\n effectiveBaseURL?: string\n ): Promise<z.infer<typeof runpodVideoStatusSchema>> {\n const maxAttempts = pollOptions?.maxAttempts ?? 120;\n const pollInterval = pollOptions?.pollIntervalMillis ?? 5000;\n const baseURL = effectiveBaseURL ?? this.config.baseURL;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n if (abortSignal?.aborted) {\n throw new Error('Video generation was aborted');\n }\n\n const { value: statusResponse } = await getFromApi({\n url: `${baseURL}/status/${jobId}`,\n headers: this.config.headers(),\n successfulResponseHandler: createJsonResponseHandler(\n runpodVideoStatusSchema as any\n ),\n failedResponseHandler: runpodVideoFailedResponseHandler,\n abortSignal,\n fetch: this.config.fetch,\n });\n\n const typedStatusResponse = statusResponse as z.infer<\n typeof runpodVideoStatusSchema\n >;\n\n if (typedStatusResponse.status === 'COMPLETED') {\n return typedStatusResponse;\n }\n\n if (typedStatusResponse.status === 'FAILED') {\n throw new Error(\n `Video 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 `Video generation timed out after ${maxAttempts} attempts (${(maxAttempts * pollInterval) / 1000}s)`\n );\n }\n}\n"],"mappings":"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","names":["withoutTrailingSlash","z","z","withoutTrailingSlash","createJsonResponseHandler","getFromApi","postJsonToApi","z","isRecord","z","withoutTrailingSlash","postJsonToApi","createJsonResponseHandler","runpod","getFromApi","withoutTrailingSlash","createJsonResponseHandler","getFromApi","postJsonToApi","z","isRecord","z","withoutTrailingSlash","postJsonToApi","createJsonResponseHandler","runpod","getFromApi","withoutTrailingSlash"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@runpod/ai-sdk-provider",
3
- "version": "1.2.0",
3
+ "version": "1.4.0",
4
4
  "license": "Apache-2.0",
5
5
  "sideEffects": false,
6
6
  "main": "./dist/index.js",
@@ -19,20 +19,20 @@
19
19
  }
20
20
  },
21
21
  "dependencies": {
22
- "@ai-sdk/openai-compatible": "^2.0.0",
23
- "@ai-sdk/provider": "^3.0.0",
24
- "@ai-sdk/provider-utils": "^4.0.0"
22
+ "@ai-sdk/openai-compatible": "^2.0.30",
23
+ "@ai-sdk/provider": "^3.0.8",
24
+ "@ai-sdk/provider-utils": "^4.0.15"
25
25
  },
26
26
  "devDependencies": {
27
- "@changesets/cli": "^2.29.6",
27
+ "@changesets/cli": "^2.29.8",
28
28
  "@edge-runtime/vm": "^5.0.0",
29
29
  "@types/node": "^20.0.0",
30
- "@typescript-eslint/eslint-plugin": "^8.39.1",
31
- "@typescript-eslint/parser": "^8.39.1",
30
+ "@typescript-eslint/eslint-plugin": "^8.56.1",
31
+ "@typescript-eslint/parser": "^8.56.1",
32
32
  "eslint": "^9.33.0",
33
- "prettier": "^3.6.2",
34
- "tsup": "^8.0.0",
35
- "typescript": "^5.0.0",
33
+ "prettier": "^3.8.1",
34
+ "tsup": "^8.5.1",
35
+ "typescript": "^5.9.3",
36
36
  "vitest": "^2.0.0",
37
37
  "zod": "^3.25.76"
38
38
  },