Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
4ec45d4
feat(ai-gateway): add NVIDIA direct BYOK support
lambertjosh Jul 27, 2026
44d5234
fix(ai-gateway): strip gateway-only fields NVIDIA rejects
lambertjosh Jul 27, 2026
cbff1c9
refactor(ai-gateway): address NVIDIA BYOK review feedback
lambertjosh Jul 28, 2026
126a7b2
fix(ai-gateway): keep stripping include_reasoning for NVIDIA
lambertjosh Jul 28, 2026
df1c045
refactor(ai-gateway): keep NVIDIA handling out of shared model settings
lambertjosh Jul 28, 2026
b0efb8b
fix(ai-gateway): preserve NVIDIA model capabilities
lambertjosh Jul 28, 2026
e4a2cd7
refactor(ai-gateway): simplify NVIDIA BYOK metadata
lambertjosh Jul 28, 2026
9464aae
fix(ai-gateway): preserve NVIDIA catalog on empty sync
lambertjosh Jul 29, 2026
8b84db1
refactor(ai-gateway): source NVIDIA models from models.dev
lambertjosh Jul 29, 2026
29561fc
refactor(ai-gateway): derive NVIDIA reasoning from models.dev
lambertjosh Jul 29, 2026
99938e9
Merge origin/main into research-nvidia-byok-support
chrarnoldus Jul 29, 2026
1381bc1
Merge remote-tracking branch 'origin/main' into research-nvidia-byok-…
chrarnoldus Jul 30, 2026
56ae955
refactor(ai-gateway): simplify NVIDIA BYOK filtering
chrarnoldus Jul 30, 2026
91a6571
fix(ai-gateway): strip NVIDIA include reasoning field
chrarnoldus Jul 30, 2026
6d30087
refactor(ai-gateway): minimize NVIDIA model sync
chrarnoldus Jul 30, 2026
fd5fd32
Merge branch 'main' into research-nvidia-byok-support
chrarnoldus Jul 30, 2026
9783e7c
Rename
chrarnoldus Jul 30, 2026
739723d
Simplify
chrarnoldus Jul 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import kimiCoding from './kimi-coding';
import martian from './martian';
import morph from './morph';
import neuralwatt from './neurowatt';
import nvidiaByok from './nvidia-byok';
import ollamaCloud from './ollama-cloud';
import openCodeGo from './opencode-go';
import orcarouter from './orcarouter';
Expand All @@ -26,6 +27,7 @@ export default [
martian,
morph,
neuralwatt,
nvidiaByok,
ollamaCloud,
openCodeGo,
orcarouter,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const DIRECT_BYOK_PROVIDERS_META = {
martian: 'Martian',
'morph-byok': 'Morph BYOK',
neuralwatt: 'Neuralwatt',
'nvidia-byok': 'NVIDIA BYOK',
'ollama-cloud': 'Ollama Cloud',
'opencode-go': 'OpenCode Go',
orcarouter: 'OrcaRouter',
Expand Down
35 changes: 35 additions & 0 deletions apps/web/src/lib/ai-gateway/providers/direct-byok/nvidia-byok.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { cachedEnhancedDirectByokModelList } from '@/lib/ai-gateway/providers/direct-byok/model-list';
import type { DirectByokProvider } from '@/lib/ai-gateway/providers/direct-byok/types';

export default {
id: 'nvidia-byok',
base_url: 'https://integrate.api.nvidia.com/v1',
supported_chat_apis: ['chat_completions'],
default_ai_sdk_provider: 'openai-compatible',
transformRequest(context) {
const { request } = context;
if (request.kind !== 'chat_completions') {
return;
}

request.body.reasoning_effort ??= request.body.reasoning?.effort ?? undefined;

delete request.body.provider;
Comment thread
chrarnoldus marked this conversation as resolved.
delete request.body.transforms;
delete request.body.reasoning;
delete request.body.safety_identifier;
delete request.body.prompt_cache_key;
Comment thread
chrarnoldus marked this conversation as resolved.
},
models: cachedEnhancedDirectByokModelList({
providerId: 'nvidia-byok',
recommendedModels: [
{
id: 'nvidia/nemotron-3-super-120b-a12b',
name: 'Nemotron 3 Super 120B A12B',
flags: ['reasoning'],
context_length: 262144,
max_completion_tokens: 262144,
},
],
}),
} satisfies DirectByokProvider;
Original file line number Diff line number Diff line change
Expand Up @@ -227,4 +227,60 @@ describe('parseModelsDevProviderModels', () => {
expect(models.map(model => model.id)).toEqual(['available']);
expect(models[0].context_length).toBe(128_000);
});

test('excludes explicit capability mismatches while accepting missing metadata', () => {
const model = (id: string, overrides: Record<string, unknown> = {}) => ({
id,
name: id,
tool_call: true,
modalities: { input: ['text'], output: ['text'] },
...overrides,
});
const models = parseModelsDevProviderModels(
{
models: {
chat: model('nvidia/chat', {
reasoning: true,
reasoning_options: [{ type: 'effort', values: ['none', 'high', 'max'] }],
limit: { context: 128000 },
}),
vision: model('nvidia/vision', {
modalities: { input: ['text', 'image'], output: ['text'] },
}),
unknownCapabilities: { id: 'nvidia/unknown' },
unavailable: model('nvidia/unavailable'),
noTools: model('nvidia/no-tools', { tool_call: false }),
noTextInput: model('nvidia/no-text-input', {
modalities: { input: ['image'], output: ['text'] },
}),
},
},
'nvidia-byok',
new Set([
'nvidia/chat',
'nvidia/vision',
'nvidia/unknown',
'nvidia/no-tools',
'nvidia/no-text-input',
])
);

expect(models).toEqual([
expect.objectContaining({
id: 'nvidia/chat',
context_length: 128000,
flags: ['reasoning'],
variants: {
none: { reasoning: { enabled: false, effort: 'none' } },
high: { reasoning: { enabled: true, effort: 'high' } },
max: { reasoning: { enabled: true, effort: 'max' } },
},
}),
expect.objectContaining({
id: 'nvidia/vision',
input_modalities: ['text', 'image'],
}),
expect.objectContaining({ id: 'nvidia/unknown' }),
]);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ const ModelsDevModelSchema = z.object({
output: z.array(ModalitySchema).optional(),
})
.optional(),
tool_call: z.boolean().optional(),
});

const ModelsDevProviderSchema = z.object({
Expand Down Expand Up @@ -186,7 +187,9 @@ export function parseModelsDevProviderModels(
model =>
model.status !== 'deprecated' &&
(!model.modalities?.output || model.modalities.output.includes('text')) &&
(!availableModelIds || availableModelIds.has(model.id))
(!availableModelIds || availableModelIds.has(model.id)) &&
model.tool_call !== false &&
(!model.modalities?.input || model.modalities.input.includes('text'))
)
.map(model => {
const modelId = `${providerId}/${model.id}`.toLowerCase();
Expand Down Expand Up @@ -254,6 +257,7 @@ const FETCHERS: ReadonlyArray<ProviderFetcher> = [
label: 'Neuralwatt',
url: 'https://api.neuralwatt.com/v1/models',
}),
modelsDevFetcher('nvidia-byok', 'nvidia', 'https://integrate.api.nvidia.com/v1/models'),
openAICompatibleFetcher({
providerId: 'chutes-byok',
label: 'Chutes',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ export const DirectUserByokInferenceProviderIdSchema = z.enum([
'martian',
'morph-byok',
'neuralwatt',
'nvidia-byok',
'ollama-cloud',
'opencode-go',
'orcarouter',
Expand Down Expand Up @@ -156,6 +157,8 @@ export const UserByokTestModels = {
[DirectUserByokInferenceProviderIdSchema.enum.martian]: 'google/gemini-3.5-flash',
[DirectUserByokInferenceProviderIdSchema.enum['morph-byok']]: 'morph-qwen35-397b',
[DirectUserByokInferenceProviderIdSchema.enum.neuralwatt]: 'Qwen/Qwen3.5-35B-A3B',
[DirectUserByokInferenceProviderIdSchema.enum['nvidia-byok']]:
'nvidia/nemotron-3-super-120b-a12b',
[DirectUserByokInferenceProviderIdSchema.enum['orcarouter']]: 'google/gemini-3.6-flash',
[DirectUserByokInferenceProviderIdSchema.enum['crofai']]: 'deepseek-v4-flash',
[DirectUserByokInferenceProviderIdSchema.enum['synthetic']]: 'hf:zai-org/GLM-5.1',
Expand Down