-
Notifications
You must be signed in to change notification settings - Fork 6
feat(ai-gateway): add NVIDIA direct BYOK support #4803
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 13 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 44d5234
fix(ai-gateway): strip gateway-only fields NVIDIA rejects
lambertjosh cbff1c9
refactor(ai-gateway): address NVIDIA BYOK review feedback
lambertjosh 126a7b2
fix(ai-gateway): keep stripping include_reasoning for NVIDIA
lambertjosh df1c045
refactor(ai-gateway): keep NVIDIA handling out of shared model settings
lambertjosh b0efb8b
fix(ai-gateway): preserve NVIDIA model capabilities
lambertjosh e4a2cd7
refactor(ai-gateway): simplify NVIDIA BYOK metadata
lambertjosh 9464aae
fix(ai-gateway): preserve NVIDIA catalog on empty sync
lambertjosh 8b84db1
refactor(ai-gateway): source NVIDIA models from models.dev
lambertjosh 29561fc
refactor(ai-gateway): derive NVIDIA reasoning from models.dev
lambertjosh 99938e9
Merge origin/main into research-nvidia-byok-support
chrarnoldus 1381bc1
Merge remote-tracking branch 'origin/main' into research-nvidia-byok-…
chrarnoldus 56ae955
refactor(ai-gateway): simplify NVIDIA BYOK filtering
chrarnoldus 91a6571
fix(ai-gateway): strip NVIDIA include reasoning field
chrarnoldus 6d30087
refactor(ai-gateway): minimize NVIDIA model sync
chrarnoldus fd5fd32
Merge branch 'main' into research-nvidia-byok-support
chrarnoldus 9783e7c
Rename
chrarnoldus 739723d
Simplify
chrarnoldus File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
102 changes: 102 additions & 0 deletions
102
apps/web/src/lib/ai-gateway/providers/direct-byok/nvidia-byok.test.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| import type { TransformRequestContext } from '@/lib/ai-gateway/providers/types'; | ||
| import type { DirectByokModel } from './types'; | ||
| import nvidiaByok from './nvidia-byok'; | ||
|
|
||
| const SUPER_MODEL_ID = 'nvidia/nemotron-3-super-120b-a12b'; | ||
| const SUPER_MODEL: DirectByokModel = { | ||
| id: SUPER_MODEL_ID, | ||
| name: 'Nemotron 3 Super', | ||
| flags: ['reasoning'], | ||
| context_length: 262144, | ||
| max_completion_tokens: 262144, | ||
| variants: { | ||
| none: { reasoning: { enabled: false, effort: 'none' } }, | ||
| high: { reasoning: { enabled: true, effort: 'high' } }, | ||
| }, | ||
| }; | ||
|
|
||
| function transform(body: Record<string, unknown>, model: DirectByokModel = SUPER_MODEL) { | ||
| const request = { | ||
| kind: 'chat_completions', | ||
| body: { | ||
| messages: [{ role: 'user', content: 'Hello' }], | ||
| ...body, | ||
| }, | ||
| } as TransformRequestContext['request']; | ||
|
|
||
| nvidiaByok.transformRequest({ request } as TransformRequestContext, model); | ||
| return request.body; | ||
| } | ||
|
|
||
| describe('NVIDIA direct BYOK', () => { | ||
| test('removes gateway-only request fields', () => { | ||
| const body = transform({ | ||
| model: SUPER_MODEL_ID, | ||
| provider: { order: ['nvidia'] }, | ||
| providerOptions: { gateway: {} }, | ||
| transforms: ['middle-out'], | ||
| reasoning: { effort: 'low' }, | ||
| safety_identifier: 'user-hash', | ||
| prompt_cache_key: 'task-hash', | ||
| temperature: 0.5, | ||
| }); | ||
|
|
||
| expect(body).toMatchObject({ | ||
| model: SUPER_MODEL_ID, | ||
| temperature: 0.5, | ||
| }); | ||
| expect(body).not.toHaveProperty('provider'); | ||
| expect(body).not.toHaveProperty('providerOptions'); | ||
| expect(body).not.toHaveProperty('transforms'); | ||
| expect(body).not.toHaveProperty('reasoning'); | ||
| expect(body).not.toHaveProperty('reasoning_effort'); | ||
| expect(body).not.toHaveProperty('safety_identifier'); | ||
| expect(body).not.toHaveProperty('prompt_cache_key'); | ||
| }); | ||
|
|
||
| test('translates an explicit reasoning disable to the documented none effort', () => { | ||
| expect(transform({ model: SUPER_MODEL_ID, reasoning: { enabled: false } })).toHaveProperty( | ||
| 'reasoning_effort', | ||
| 'none' | ||
| ); | ||
| }); | ||
|
|
||
| test('preserves an explicit reasoning effort', () => { | ||
| expect( | ||
| transform({ | ||
| model: SUPER_MODEL_ID, | ||
| reasoning_effort: 'high', | ||
| reasoning: { effort: 'low' }, | ||
| }) | ||
| ).toHaveProperty('reasoning_effort', 'high'); | ||
| expect( | ||
| transform({ model: SUPER_MODEL_ID, reasoning_effort: 'unsupported' }) | ||
| ).not.toHaveProperty('reasoning_effort'); | ||
| }); | ||
|
|
||
| test('strips efforts not supported by the selected model', () => { | ||
| const gptOssModel: DirectByokModel = { | ||
| id: 'openai/gpt-oss-120b', | ||
| name: 'GPT-OSS-120B', | ||
| flags: ['reasoning'], | ||
| context_length: 128000, | ||
| max_completion_tokens: 8192, | ||
| variants: { | ||
| low: { reasoning: { enabled: true, effort: 'low' } }, | ||
| medium: { reasoning: { enabled: true, effort: 'medium' } }, | ||
| high: { reasoning: { enabled: true, effort: 'high' } }, | ||
| }, | ||
| }; | ||
|
|
||
| expect(transform({ reasoning_effort: 'medium' }, gptOssModel)).toHaveProperty( | ||
| 'reasoning_effort', | ||
| 'medium' | ||
| ); | ||
| expect(transform({ reasoning_effort: 'max' }, gptOssModel)).not.toHaveProperty( | ||
| 'reasoning_effort' | ||
| ); | ||
| expect(transform({ reasoning: { enabled: false } }, gptOssModel)).not.toHaveProperty( | ||
| 'reasoning_effort' | ||
| ); | ||
| }); | ||
| }); |
55 changes: 55 additions & 0 deletions
55
apps/web/src/lib/ai-gateway/providers/direct-byok/nvidia-byok.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| import { cachedEnhancedDirectByokModelList } from '@/lib/ai-gateway/providers/direct-byok/model-list'; | ||
| import type { DirectByokProvider } from '@/lib/ai-gateway/providers/direct-byok/types'; | ||
| import { ReasoningEffortSchema } from '@kilocode/db/schema-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, model) { | ||
| const { request } = context; | ||
| if (request.kind !== 'chat_completions') { | ||
| return; | ||
| } | ||
|
|
||
| const reasoningEffort = | ||
| request.body.reasoning?.enabled === false | ||
| ? 'none' | ||
| : (request.body.reasoning_effort ?? request.body.reasoning?.effort); | ||
| const parsedReasoningEffort = ReasoningEffortSchema.safeParse(reasoningEffort); | ||
| const supportedReasoningEfforts = new Set( | ||
| Object.values(model.variants ?? {}).flatMap(variant => | ||
| variant.reasoning?.effort ? [variant.reasoning.effort] : [] | ||
| ) | ||
| ); | ||
| if ( | ||
| parsedReasoningEffort.success && | ||
| supportedReasoningEfforts.has(parsedReasoningEffort.data) | ||
| ) { | ||
| request.body.reasoning_effort = parsedReasoningEffort.data; | ||
| } else { | ||
| delete request.body.reasoning_effort; | ||
| } | ||
|
|
||
| // NVIDIA rejects these with `Validation: Unsupported parameter(s)`. | ||
| delete request.body.provider; | ||
|
chrarnoldus marked this conversation as resolved.
|
||
| delete request.body.providerOptions; | ||
| delete request.body.transforms; | ||
| delete request.body.reasoning; | ||
| delete request.body.safety_identifier; | ||
| delete request.body.prompt_cache_key; | ||
|
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; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.