Add NVIDIA NIM provider

This commit is contained in:
Mario Zechner
2026-06-02 15:09:36 +02:00
parent 13898f048f
commit 6014801229
20 changed files with 700 additions and 66 deletions

View File

@@ -32,12 +32,17 @@ interface ModelsDevModel {
};
modalities?: {
input?: string[];
output?: string[];
};
provider?: {
npm?: string;
};
}
interface NvidiaNimModelListItem {
id: string;
}
interface AiGatewayModel {
id: string;
name?: string;
@@ -117,6 +122,39 @@ const TOGETHER_TOGGLE_REASONING_LEVEL_MAP = {
const AI_GATEWAY_MODELS_URL = "https://ai-gateway.vercel.sh/v1";
const AI_GATEWAY_BASE_URL = "https://ai-gateway.vercel.sh";
const NVIDIA_BASE_URL = "https://integrate.api.nvidia.com/v1";
const NVIDIA_HEADERS = {
"NVCF-POLL-SECONDS": "3600",
} as const;
const NVIDIA_OPENAI_COMPAT: OpenAICompletionsCompat = {
supportsStore: false,
supportsDeveloperRole: false,
supportsReasoningEffort: false,
maxTokensField: "max_tokens",
supportsStrictMode: false,
supportsLongCacheRetention: false,
};
const NVIDIA_NIM_UNSUPPORTED_MODELS = new Set([
"abacusai/dracarys-llama-3.1-70b-instruct",
"bytedance/seed-oss-36b-instruct",
"deepseek-ai/deepseek-v4-flash",
"deepseek-ai/deepseek-v4-pro",
"google/gemma-2-2b-it",
"google/gemma-3n-e2b-it",
"google/gemma-3n-e4b-it",
"google/gemma-4-31b-it",
"meta/llama-3.2-1b-instruct",
"meta/llama-4-maverick-17b-128e-instruct",
"microsoft/phi-4-mini-instruct",
"minimaxai/minimax-m2.7",
"mistralai/mistral-nemotron",
"nvidia/nemotron-mini-4b-instruct",
"qwen/qwen3-next-80b-a3b-instruct",
"qwen/qwen3.5-122b-a10b",
"qwen/qwen3.5-397b-a17b",
"sarvamai/sarvam-m",
"upstage/solar-10.7b-instruct",
]);
const ZAI_TOOL_STREAM_UNSUPPORTED_MODELS = new Set(["glm-4.5", "glm-4.5-air", "glm-4.5-flash", "glm-4.5v"]);
const EAGER_TOOL_INPUT_STREAMING_UNSUPPORTED_ANTHROPIC_MODELS = new Set([
"github-copilot:claude-haiku-4.5",
@@ -312,6 +350,30 @@ function getBedrockBaseUrl(modelId: string): string {
: "https://bedrock-runtime.us-east-1.amazonaws.com";
}
function normalizeNvidiaModelId(modelId: string): string {
return modelId.toLowerCase().replaceAll("_", ".");
}
async function fetchNvidiaNimModelIds(): Promise<Map<string, string>> {
try {
console.log("Fetching models from NVIDIA NIM API...");
const response = await fetch(`${NVIDIA_BASE_URL}/models`);
const data = (await response.json()) as { data?: NvidiaNimModelListItem[] };
const modelIds = new Map<string, string>();
for (const model of data.data ?? []) {
modelIds.set(model.id, model.id);
modelIds.set(normalizeNvidiaModelId(model.id), model.id);
}
console.log(`Fetched ${data.data?.length ?? 0} model IDs from NVIDIA NIM`);
return modelIds;
} catch (error) {
console.error("Failed to fetch NVIDIA NIM models:", error);
return new Map();
}
}
async function fetchOpenRouterModels(): Promise<Model<any>[]> {
try {
console.log("Fetching models from OpenRouter API...");
@@ -435,6 +497,7 @@ async function loadModelsDevData(): Promise<Model<any>[]> {
const data = await response.json();
const models: Model<any>[] = [];
const nvidiaNimModelIds = data.nvidia?.models ? await fetchNvidiaNimModelIds() : new Map<string, string>();
// Process Amazon Bedrock models
if (data["amazon-bedrock"]?.models) {
@@ -836,6 +899,40 @@ async function loadModelsDevData(): Promise<Model<any>[]> {
}
}
// Process NVIDIA NIM models
if (data.nvidia?.models) {
for (const [modelId, model] of Object.entries(data.nvidia.models)) {
const m = model as ModelsDevModel;
if (m.tool_call !== true) continue;
if (!m.modalities?.input?.includes("text")) continue;
if (!m.modalities?.output?.includes("text")) continue;
const liveModelId = nvidiaNimModelIds.get(modelId) ?? nvidiaNimModelIds.get(normalizeNvidiaModelId(modelId));
if (!liveModelId) continue;
if (NVIDIA_NIM_UNSUPPORTED_MODELS.has(liveModelId)) continue;
models.push({
id: liveModelId,
name: m.name || liveModelId,
api: "openai-completions",
provider: "nvidia",
baseUrl: NVIDIA_BASE_URL,
headers: { ...NVIDIA_HEADERS },
reasoning: m.reasoning === true,
input: m.modalities.input.includes("image") ? ["text", "image"] : ["text"],
cost: {
input: m.cost?.input || 0,
output: m.cost?.output || 0,
cacheRead: m.cost?.cache_read || 0,
cacheWrite: m.cost?.cache_write || 0,
},
compat: NVIDIA_OPENAI_COMPAT,
contextWindow: m.limit?.context || 4096,
maxTokens: m.limit?.output || 4096,
});
}
}
// Process Together AI models
const togetherProvider = data.together ?? data.togetherai ?? data["together-ai"];
if (togetherProvider?.models) {