#!/usr/bin/env node const fs = require("node:fs"); const path = require("node:path"); const repoRoot = path.resolve(__dirname, "..", ".."); const registryPath = path.join( repoRoot, "packages/core/src/registries/model-provider-registry.generated.ts", ); const modelsPath = path.join( repoRoot, "packages/core/src/registries/model-provider-types.generated.ts", ); const docsRoot = path.join(repoRoot, "website/models-docs"); const providersDir = path.join(docsRoot, "providers"); const readFile = (filePath) => fs.readFileSync(filePath, "utf8"); const parseRegistry = (source) => { const marker = "MODEL_PROVIDER_REGISTRY"; const start = source.indexOf(marker); if (start === -1) { throw new Error("MODEL_PROVIDER_REGISTRY not found."); } const braceStart = source.indexOf("{", start); const braceEnd = source.lastIndexOf("};"); if (braceStart === -1 || braceEnd === -1) { throw new Error("Unable to parse provider registry object."); } const objectLiteral = source.slice(braceStart, braceEnd + 1); return new Function(`return ${objectLiteral};`)(); }; const parseProviderModels = (source) => { const providerRegex = /readonly\s+'([^']+)':\s+readonly\s+\[\n([\s\S]*?)\n\s*\];/g; const modelRegex = /'([^']+)'/g; const map = {}; for (const match of source.matchAll(providerRegex)) { const providerId = match[1]; const block = match[2]; const models = []; for (const modelMatch of block.matchAll(modelRegex)) { models.push(modelMatch[1]); } map[providerId] = models; } return map; }; const formatEnvList = (env) => { if (!env || env.length === 0) { return "None listed."; } return env.map((name) => `- \`${name}\``).join("\n"); }; const formatTableEnv = (env) => { if (!env || env.length === 0) { return "-"; } return env.map((name) => `\`${name}\``).join("
"); }; const formatModelList = (models) => { if (!models || models.length === 0) { return "No models listed in the registry snapshot."; } const lines = models.map((model) => `- ${model}`).join("\n"); return [ "
", ` Show models (${models.length})`, "", lines, "", "
", ].join("\n"); }; const autoGeneratedNotice = ""; const buildOverview = (providerCount, modelCount) => `--- title: Models slug: / sidebar_position: 1 description: Explore ${providerCount}+ providers and ${modelCount}+ models supported by VoltAgent's model registry. --- ${autoGeneratedNotice} import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; # Models Explore ${providerCount}+ providers and ${modelCount}+ models using VoltAgent's built-in model registry. Use \`provider/model\` strings for fast routing, or pass an ai-sdk \`LanguageModel\` when you need provider-specific control. The registry is generated from [models.dev](https://models.dev) and bundled with VoltAgent. At runtime, VoltAgent checks required environment variables and reports the exact one that's missing. ## Highlights - **Zero-import model strings** - Use \`provider/model\` IDs without adding provider packages. - **Registry-backed env mapping** - VoltAgent knows which env vars each provider expects. - **Type-aware model IDs** - \`ModelRouterModelId\` adds autocomplete and validation. - **Runtime routing** - Pick models dynamically per request or tenant. - **Bring your own LanguageModel** - Drop in ai-sdk providers for advanced options. ## Quick start (model strings) \`\`\`ts import { Agent } from "@voltagent/core"; const agent = new Agent({ name: "openai-summary", instructions: "Summarize the update in 2 bullets.", model: "openai/gpt-4.1-mini", }); \`\`\` \`\`\`ts import { Agent } from "@voltagent/core"; const agent = new Agent({ name: "claude-notes", instructions: "Turn notes into action items.", model: "anthropic/claude-3-5-haiku", }); \`\`\` \`\`\`ts import { Agent } from "@voltagent/core"; const agent = new Agent({ name: "gemini-translator", instructions: "Translate to Turkish and keep tone friendly.", model: "google/gemini-2.0-flash", }); \`\`\` \`\`\`ts import { Agent } from "@voltagent/core"; const agent = new Agent({ name: "grok-ideas", instructions: "Brainstorm five product names.", model: "xai/grok-3-mini", }); \`\`\` \`\`\`ts import { Agent } from "@voltagent/core"; const agent = new Agent({ name: "openrouter-agent", instructions: "Answer in short paragraphs.", model: "openrouter/anthropic/claude-3.5-haiku", }); \`\`\` ## Provider directory Browse provider pages in the left navigation or visit the [Providers directory](/models-docs/providers/overview) for the full list. For full model inventories per provider, see each provider page or explore [models.dev](https://models.dev). ## Type-safe model IDs Use \`ModelRouterModelId\` to get IDE autocomplete for model strings: \`\`\`ts import type { ModelRouterModelId } from "@voltagent/core"; const modelId: ModelRouterModelId = "openai/gpt-4.1-mini"; \`\`\` ## Split workloads across models Assign cheaper models to throughput-heavy steps and stronger models to critical analysis: \`\`\`ts import { Agent } from "@voltagent/core"; const ingestAgent = new Agent({ name: "ingest-agent", instructions: "Extract entities and key facts from raw notes.", model: "google/gemini-2.0-flash", }); const reviewAgent = new Agent({ name: "review-agent", instructions: "Review the summary and flag risks or gaps.", model: "anthropic/claude-3-5-sonnet", }); \`\`\` ## Runtime model selection Pick a model based on request context: \`\`\`ts const agent = new Agent({ name: "runtime-router", model: ({ context }) => { const tier = (context.get("tier") as string) || "fast"; return tier === "fast" ? "openai/gpt-4.1-mini" : "anthropic/claude-3-5-sonnet"; }, }); \`\`\` ## Provider options Pass provider-specific options per request when you need them: \`\`\`ts const analyst = new Agent({ name: "analyst", instructions: "Explain tradeoffs clearly and concisely.", model: "openai/o3-mini", }); const response = await analyst.generateText("Compare JWTs vs cookies for auth.", { providerOptions: { openai: { reasoningEffort: "high" }, }, }); \`\`\` ## Custom headers If you need custom headers, pass an ai-sdk \`LanguageModel\` directly: \`\`\`ts import { Agent } from "@voltagent/core"; import { createOpenAICompatible } from "@ai-sdk/openai-compatible"; const customProvider = createOpenAICompatible({ name: "openai", baseURL: "https://api.openai.com/v1", apiKey: process.env.OPENAI_API_KEY, headers: { "X-Client-Source": "voltagent-docs", }, }); const agent = new Agent({ name: "custom-agent", model: customProvider("gpt-4o-mini"), }); \`\`\` :::note VoltAgent does not include fallback chains yet. Implement retries or failover in your app if needed. ::: ## Use ai-sdk directly You can use ai-sdk provider modules anywhere VoltAgent expects a \`LanguageModel\`: \`\`\`ts import { mistral } from "@ai-sdk/mistral"; import { Agent } from "@voltagent/core"; const agent = new Agent({ name: "mistral-agent", model: mistral("mistral-small-latest"), }); \`\`\` `; const buildProvidersOverview = (providerIds, registry, _providerModels) => { const rows = providerIds .map((providerId) => { const entry = registry[providerId]; const name = entry?.name ?? providerId; const env = formatTableEnv(entry?.env); const doc = entry?.doc ? `[Docs](${entry.doc})` : "-"; return `| ${name} | \`${providerId}\` | ${env} | ${doc} |`; }) .join("\n"); return `--- title: Providers description: Browse all providers supported by VoltAgent's model router. sidebar_label: Overview sidebar_position: 1 --- ${autoGeneratedNotice} # Providers Each provider page includes: - A usage example with \`provider/model\` - Required environment variables - Links to provider documentation - Model list from the registry snapshot ## Provider directory | Provider | Model prefix | Environment variables | Docs | | --- | --- | --- | --- | ${rows} `; }; const preferredModelByProvider = { anthropic: "claude-3-5-sonnet", evroc: "Qwen/Qwen3.8-27B", google: "gemini-2.0-flash", "google-vertex": "gemini-3.5-flash", nearai: "Qwen/Qwen3.8-27B", openai: "gpt-4o-mini", openrouter: "anthropic/claude-haiku-4-5", xai: "grok-4", }; const buildProviderDoc = (providerId, entry, models) => { const name = entry?.name ?? providerId; const docLink = entry?.doc ? `- ${entry.doc}` : "- Not available."; const envBlock = formatEnvList(entry?.env); const baseUrlEnv = `${providerId.toUpperCase().replace(/-/g, "_")}_BASE_URL`; const baseUrl = entry?.api && entry.api.trim().length > 0 ? `\`${entry.api}\`` : "Not listed."; const usesOpenAICompatible = entry?.npm === "@ai-sdk/openai-compatible"; const providerPackage = entry?.npm ? `\`${entry.npm}\`` : "Not listed."; const fallbackModel = models?.[0]; const preferredModel = preferredModelByProvider[providerId]; const exampleModel = preferredModel && models?.includes(preferredModel) ? preferredModel : fallbackModel || "model-id"; const exampleModelId = `${providerId}/${exampleModel}`; return `--- title: ${name} --- ${autoGeneratedNotice} # ${name} Use \`${providerId}/\` with VoltAgent's model router. ## Quick start \`\`\`ts import { Agent } from "@voltagent/core"; const agent = new Agent({ name: "${providerId}-agent", instructions: "You are a helpful assistant", model: "${exampleModelId}", }); \`\`\` ## Environment variables ${envBlock} ## Provider package ${providerPackage} ${usesOpenAICompatible ? "This provider uses the OpenAI-compatible adapter." : ""} ## Default base URL ${baseUrl} You can override the base URL by setting \`${baseUrlEnv}\`. ## Provider docs ${docLink} ## Models ${formatModelList(models)} `; }; const main = () => { const registrySource = readFile(registryPath); const modelsSource = readFile(modelsPath); const registry = parseRegistry(registrySource); const providerModels = parseProviderModels(modelsSource); const providerIds = Object.keys(registry).sort((a, b) => a.localeCompare(b)); const providerCount = providerIds.length; const modelCount = providerIds.reduce( (total, providerId) => total + (providerModels[providerId]?.length ?? 0), 0, ); fs.mkdirSync(providersDir, { recursive: true }); fs.writeFileSync( path.join(docsRoot, "overview.md"), buildOverview(providerCount, modelCount), "utf8", ); fs.writeFileSync( path.join(providersDir, "overview.md"), buildProvidersOverview(providerIds, registry, providerModels), "utf8", ); for (const providerId of providerIds) { const entry = registry[providerId]; const models = providerModels[providerId] ?? []; const content = buildProviderDoc(providerId, entry, models); fs.writeFileSync(path.join(providersDir, `${providerId}.md`), content, "utf8"); } // eslint-disable-next-line no-console console.log(`Generated Models docs for ${providerCount} providers (${modelCount} models).`); }; main();