@mastra/core
Version:
1 lines • 17.1 kB
Source Map (JSON)
{"version":3,"sources":["../src/llm/model/registry-generator.ts"],"names":["fs","shouldEnableGateway","getGatewayId","path"],"mappings":"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","file":"registry-generator-KDBM5ARQ.cjs","sourcesContent":["/**\n * Shared provider registry generation logic\n * Used by both the CLI generation script and runtime refresh\n */\n\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\nimport type {\n AttachmentCapabilities,\n MastraModelGatewayInterface,\n ProviderConfig,\n TemperatureCapabilities,\n} from './gateways/base.js';\nimport { getGatewayId, shouldEnableGateway } from './gateways/index.js';\n\ninterface GatewayWithAttachmentCapabilities {\n getAttachmentCapabilities(): AttachmentCapabilities;\n}\n\ninterface GatewayWithTemperatureCapabilities {\n getTemperatureCapabilities(): TemperatureCapabilities;\n}\n\nfunction hasAttachmentCapabilities(\n gateway: MastraModelGatewayInterface,\n): gateway is MastraModelGatewayInterface & GatewayWithAttachmentCapabilities {\n return (\n 'getAttachmentCapabilities' in gateway &&\n typeof (gateway as { getAttachmentCapabilities?: unknown }).getAttachmentCapabilities === 'function'\n );\n}\n\nfunction hasTemperatureCapabilities(\n gateway: MastraModelGatewayInterface,\n): gateway is MastraModelGatewayInterface & GatewayWithTemperatureCapabilities {\n return (\n 'getTemperatureCapabilities' in gateway &&\n typeof (gateway as { getTemperatureCapabilities?: unknown }).getTemperatureCapabilities === 'function'\n );\n}\n\n/**\n * Write a file atomically using the write-to-temp-then-rename pattern.\n * This prevents file corruption when multiple processes write to the same file concurrently.\n *\n * The rename operation is atomic on POSIX systems when source and destination\n * are on the same filesystem.\n *\n * @param filePath - The target file path\n * @param content - The content to write\n * @param encoding - The encoding to use (default: 'utf-8')\n */\nexport async function atomicWriteFile(\n filePath: string,\n content: string,\n encoding: BufferEncoding = 'utf-8',\n): Promise<void> {\n // Create a unique temp file name using PID, timestamp, and random suffix to avoid collisions\n const randomSuffix = Math.random().toString(36).substring(2, 15);\n const tempPath = `${filePath}.${process.pid}.${Date.now()}.${randomSuffix}.tmp`;\n\n try {\n // Write to temp file first\n await fs.writeFile(tempPath, content, encoding);\n\n // Atomically rename temp file to target path\n // This is atomic on POSIX when both paths are on the same filesystem\n await fs.rename(tempPath, filePath);\n } catch (error) {\n // Clean up temp file if it exists\n try {\n await fs.unlink(tempPath);\n } catch {\n // Ignore cleanup errors\n }\n throw error;\n }\n}\n\n/**\n * Fetch providers from all enabled gateways with silent retry logic.\n * Retries up to 3 times per gateway with exponential backoff. If all\n * retries are exhausted the gateway is silently skipped (no error logging)\n * since the bundled registry already contains all model data.\n * @param gateways - Array of gateway instances to fetch from\n * @returns Object containing providers and models records\n */\nexport async function fetchProvidersFromGateways(gateways: MastraModelGatewayInterface[]): Promise<{\n providers: Record<string, ProviderConfig>;\n models: Record<string, string[]>;\n attachmentCapabilities: AttachmentCapabilities;\n temperatureCapabilities: TemperatureCapabilities;\n failedGateways: string[];\n}> {\n const enabledGateways: MastraModelGatewayInterface[] = [];\n\n for (const gateway of gateways) {\n if (shouldEnableGateway(gateway)) {\n enabledGateways.push(gateway);\n }\n }\n\n const allProviders: Record<string, ProviderConfig> = {};\n const allModels: Record<string, string[]> = {};\n const allAttachmentCapabilities: AttachmentCapabilities = {};\n const allTemperatureCapabilities: TemperatureCapabilities = {};\n const failedGateways: string[] = [];\n\n const maxRetries = 3;\n\n for (const gateway of enabledGateways) {\n let providers: Record<string, ProviderConfig> | null = null;\n\n for (let attempt = 1; attempt <= maxRetries; attempt++) {\n try {\n providers = await gateway.fetchProviders();\n break;\n } catch {\n if (attempt < maxRetries) {\n const delayMs = Math.min(1000 * Math.pow(2, attempt - 1), 5000);\n await new Promise(resolve => setTimeout(resolve, delayMs));\n }\n }\n }\n\n if (!providers) {\n failedGateways.push(getGatewayId(gateway));\n continue;\n }\n\n const gatewayId = getGatewayId(gateway);\n // models.dev is a provider registry, not a true gateway - don't prefix its providers\n const isProviderRegistry = gatewayId === 'models.dev';\n\n // Collect capabilities if the gateway exposes them\n const gatewayAttachmentCaps = hasAttachmentCapabilities(gateway) ? gateway.getAttachmentCapabilities() : undefined;\n const gatewayTemperatureCaps = hasTemperatureCapabilities(gateway)\n ? gateway.getTemperatureCapabilities()\n : undefined;\n\n for (const [providerId, config] of Object.entries(providers)) {\n // For true gateways, use gateway id as prefix (e.g., \"netlify/anthropic\")\n // Special case: if providerId matches gateway id, it's a unified gateway (e.g., azure-openai returning {azure-openai: {...}})\n // In this case, use just the gateway ID to avoid duplication (azure-openai, not azure-openai/azure-openai)\n const typeProviderId = isProviderRegistry\n ? providerId\n : providerId === gatewayId\n ? gatewayId\n : `${gatewayId}/${providerId}`;\n\n allProviders[typeProviderId] = config;\n // Sort models alphabetically for consistent ordering\n allModels[typeProviderId] = config.models.sort();\n\n // Merge capabilities for this provider if available\n if (gatewayAttachmentCaps?.[providerId]) {\n allAttachmentCapabilities[typeProviderId] = gatewayAttachmentCaps[providerId];\n }\n if (gatewayTemperatureCaps?.[providerId]) {\n allTemperatureCapabilities[typeProviderId] = gatewayTemperatureCaps[providerId];\n }\n }\n }\n\n return {\n providers: allProviders,\n models: allModels,\n attachmentCapabilities: allAttachmentCapabilities,\n temperatureCapabilities: allTemperatureCapabilities,\n failedGateways,\n };\n}\n\n/**\n * Generate TypeScript type definitions content\n * @param models - Record of provider IDs to model arrays\n * @returns Generated TypeScript type definitions as a string\n */\nexport function generateTypesContent(models: Record<string, string[]>): string {\n const providerModelsEntries = Object.entries(models)\n .map(([provider, modelList]) => {\n const modelsList = modelList.map(m => `'${m}'`);\n\n // Quote provider key if it's not a valid JavaScript identifier\n // Valid identifiers must start with a letter, underscore, or dollar sign\n const needsQuotes = !/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(provider);\n const providerKey = needsQuotes ? `'${provider}'` : provider;\n\n // Format array based on length (prettier printWidth: 120)\n const singleLine = ` readonly ${providerKey}: readonly [${modelsList.join(', ')}];`;\n\n // If single line exceeds 120 chars, format as multi-line\n if (singleLine.length > 120) {\n const formattedModels = modelList.map(m => ` '${m}',`).join('\\n');\n return ` readonly ${providerKey}: readonly [\\n${formattedModels}\\n ];`;\n }\n\n return singleLine;\n })\n .join('\\n');\n\n return `/**\n * THIS FILE IS AUTO-GENERATED - DO NOT EDIT\n * Generated from model gateway providers\n */\n\n/**\n * Provider models mapping type\n * This is derived from the JSON data and provides type-safe access\n */\nexport type ProviderModelsMap = {\n${providerModelsEntries}\n};\n\n/**\n * Union type of all registered provider IDs\n */\nexport type Provider = keyof ProviderModelsMap;\n\n/**\n * Provider models mapping interface\n */\nexport interface ProviderModels {\n [key: string]: string[];\n}\n\n/**\n * OpenAI-compatible model ID type\n * Dynamically derived from ProviderModelsMap\n * Full provider/model paths (e.g., \"openai/gpt-4o\", \"anthropic/claude-3-5-sonnet-20241022\")\n */\nexport type ModelRouterModelId =\n | {\n [P in Provider]: \\`\\${P}/\\${ProviderModelsMap[P][number]}\\`;\n }[Provider]\n | \\`mastra/\\${ProviderModelsMap['openrouter'][number]}\\`\n | (string & {});\n\n/**\n * Extract the model part from a ModelRouterModelId for a specific provider\n * Dynamically derived from ProviderModelsMap\n * Example: ModelForProvider<'openai'> = 'gpt-4o' | 'gpt-4-turbo' | ...\n */\nexport type ModelForProvider<P extends Provider> = ProviderModelsMap[P][number];\n`;\n}\n\n/**\n * Write registry files to disk (JSON and .d.ts)\n * @param jsonPath - Path to write the JSON file\n * @param typesPath - Path to write the .d.ts file\n * @param providers - Provider configurations\n * @param models - Model lists by provider\n */\nexport async function writeRegistryFiles(\n jsonPath: string,\n typesPath: string,\n providers: Record<string, ProviderConfig>,\n models: Record<string, string[]>,\n attachmentCapabilities?: AttachmentCapabilities,\n temperatureCapabilities?: TemperatureCapabilities,\n): Promise<void> {\n // 0. Ensure directories exist\n const jsonDir = path.dirname(jsonPath);\n const typesDir = path.dirname(typesPath);\n await fs.mkdir(jsonDir, { recursive: true });\n await fs.mkdir(typesDir, { recursive: true });\n\n // 1. Write JSON file atomically to prevent corruption from concurrent writes\n const registryData = {\n providers,\n models,\n version: '1.0.0',\n };\n\n await atomicWriteFile(jsonPath, JSON.stringify(registryData, null, 2), 'utf-8');\n\n // 2. Generate .d.ts file with type-only declarations (also atomic)\n const typeContent = generateTypesContent(models);\n await atomicWriteFile(typesPath, typeContent, 'utf-8');\n\n // 3. Write per-provider capability files into a capabilities/ directory\n const hasCapabilities =\n (attachmentCapabilities && Object.keys(attachmentCapabilities).length > 0) ||\n (temperatureCapabilities && Object.keys(temperatureCapabilities).length > 0);\n if (hasCapabilities) {\n const capDir = path.join(jsonDir, 'capabilities');\n await fs.mkdir(capDir, { recursive: true });\n\n // Clean out stale provider files from previous runs\n try {\n const existing = await fs.readdir(capDir);\n for (const file of existing) {\n if (file.endsWith('.json')) {\n await fs.unlink(path.join(capDir, file));\n }\n }\n } catch {\n // Directory may not exist yet — ignore\n }\n\n // Build a merged capability object per provider\n const allProviderIds = new Set([\n ...(attachmentCapabilities ? Object.keys(attachmentCapabilities) : []),\n ...(temperatureCapabilities ? Object.keys(temperatureCapabilities) : []),\n ]);\n\n for (const provider of allProviderIds) {\n const capData: Record<string, string[]> = {};\n if (attachmentCapabilities?.[provider]) capData.attachment = attachmentCapabilities[provider];\n if (temperatureCapabilities?.[provider]) capData.temperature = temperatureCapabilities[provider];\n\n const providerFile = path.join(capDir, `${provider}.json`);\n await atomicWriteFile(providerFile, JSON.stringify(capData, null, 2), 'utf-8');\n }\n }\n}\n"]}