Skip to content

Commit b4c38df

Browse files
authored
feat(providers): add Nebius Token Factory (#8759)
* feat(providers): add Nebius Token Factory * fix(nebius): normalize unsupported forced tools
1 parent 14e6c0a commit b4c38df

17 files changed

Lines changed: 716 additions & 1 deletion

File tree

‎apps/sim/app/workspace/[workspaceId]/settings/components/byok/byok.tsx‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import {
4646
ZaiIcon,
4747
ZeroBounceIcon,
4848
} from '@/components/icons'
49+
import { NebiusIcon } from '@/components/icons/nebius'
4950
import { canMutateWorkspaceSettingsSection } from '@/components/settings/navigation'
5051
import { type BYOKProviderId, MAX_BYOK_KEYS_PER_PROVIDER } from '@/lib/api/contracts/byok-keys'
5152
import { useDeploymentShape } from '@/lib/core/config/deployment-shape'
@@ -160,6 +161,13 @@ const PROVIDERS: (BYOKManagerProvider & { id: BYOKProviderId })[] = [
160161
description: 'LLM calls',
161162
placeholder: 'Enter your Baseten API key',
162163
},
164+
{
165+
id: 'nebius',
166+
name: 'Nebius',
167+
icon: NebiusIcon,
168+
description: 'LLM calls',
169+
placeholder: 'Enter your Nebius Token Factory API key',
170+
},
163171
{
164172
id: 'ollama-cloud',
165173
name: 'Ollama Cloud',
@@ -372,6 +380,7 @@ const PROVIDER_SECTIONS: BYOKProviderSection[] = [
372380
'fireworks',
373381
'together',
374382
'baseten',
383+
'nebius',
375384
'ollama-cloud',
376385
'kie',
377386
'falai',
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import type { SVGProps } from 'react'
2+
3+
interface NebiusIconProps extends SVGProps<SVGSVGElement> {}
4+
5+
export function NebiusIcon(props: NebiusIconProps) {
6+
return (
7+
<svg {...props} viewBox='0 0 32 32' fill='none' xmlns='http://www.w3.org/2000/svg'>
8+
<rect width='32' height='32' fill='#052B42' rx='8' />
9+
<path
10+
fill='#E0FF4F'
11+
d='M18.468 14a.468.468 0 0 1-.468-.468v-2.877a.655.655 0 0 0-.655-.655h-2.878A.468.468 0 0 1 14 9.532V6.655A.655.655 0 0 0 13.345 6h-2.69a.655.655 0 0 0-.655.655v2.69c0 .362.293.655.655.655h2.877c.258 0 .468.21.468.468v2.877c0 .362.293.655.655.655h2.878c.258 0 .467.21.467.468v3.064a.468.468 0 0 1-.467.468h-2.878a.655.655 0 0 0-.655.655v2.877c0 .258-.21.468-.468.468h-2.877a.655.655 0 0 0-.655.655v2.69c0 .362.293.655.655.655h2.69a.655.655 0 0 0 .655-.655v-2.877c0-.258.209-.467.467-.468h2.878a.655.655 0 0 0 .655-.655v-2.877c0-.258.21-.468.468-.468h2.877a.655.655 0 0 0 .655-.655v-2.69a.655.655 0 0 0-.655-.655h-2.877Z'
12+
/>
13+
</svg>
14+
)
15+
}

‎apps/sim/ee/organization-usage/components/usage-consumers.tsx‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import {
3030
xAIIcon,
3131
ZaiIcon,
3232
} from '@/components/icons'
33+
import { NebiusIcon } from '@/components/icons/nebius'
3334
import type {
3435
OrganizationUsageBreakdown,
3536
OrganizationUsageBreakdownRow,
@@ -70,6 +71,7 @@ const PROVIDER_ICONS: Readonly<Record<string, ComponentType<{ className?: string
7071
litellm: LitellmIcon,
7172
meta: MetaIcon,
7273
mistral: MistralIcon,
74+
nebius: NebiusIcon,
7375
nvidia: NvidiaIcon,
7476
ollama: OllamaIcon,
7577
'ollama-cloud': OllamaIcon,

‎apps/sim/lib/api-key/byok.test.ts‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,3 +412,41 @@ describe('getApiKeyWithBYOK for Fireworks', () => {
412412
expect(result).toEqual({ apiKey: 'platform-fireworks-key', isBYOK: false })
413413
})
414414
})
415+
416+
describe('getApiKeyWithBYOK for Nebius', () => {
417+
beforeEach(() => {
418+
resetDbChainMock()
419+
mockDecryptSecret.mockImplementation(async (encrypted: string) => ({
420+
decrypted: encrypted.replace('encrypted-', 'decrypted-'),
421+
}))
422+
})
423+
424+
it('uses the configured workspace key instead of a caller key', async () => {
425+
dbChainMockFns.orderBy.mockResolvedValueOnce([storedKey('nebius-workspace')])
426+
await expect(
427+
getApiKeyWithBYOK(
428+
'nebius',
429+
'nebius/Qwen/Qwen3-30B-A3B-Instruct-2507',
430+
uniqueWorkspaceId(),
431+
'caller-key'
432+
)
433+
).resolves.toEqual({
434+
apiKey: 'decrypted-nebius-workspace',
435+
isBYOK: true,
436+
scope: 'workspace',
437+
})
438+
})
439+
440+
it('fails closed when a configured Nebius key cannot be decrypted', async () => {
441+
dbChainMockFns.orderBy.mockResolvedValueOnce([storedKey('nebius-corrupt')])
442+
mockDecryptSecret.mockRejectedValueOnce(new Error('cannot decrypt'))
443+
await expect(
444+
getApiKeyWithBYOK(
445+
'nebius',
446+
'nebius/Qwen/Qwen3-30B-A3B-Instruct-2507',
447+
uniqueWorkspaceId(),
448+
'caller-key'
449+
)
450+
).rejects.toThrow('Configured BYOK credentials are unavailable')
451+
})
452+
})

‎apps/sim/lib/api-key/byok.ts‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,13 @@ export async function getApiKeyWithBYOK(
298298
throw new Error(`API key is required for Baseten ${model}`)
299299
}
300300

301+
if (provider === 'nebius') {
302+
const byokResult = await getBYOKKey(workspaceId, 'nebius', { failClosed: true })
303+
if (byokResult) return byokResult
304+
if (userProvidedKey) return { apiKey: userProvidedKey, isBYOK: false }
305+
throw new Error(`API key is required for Nebius ${model}`)
306+
}
307+
301308
if (provider === 'ollama-cloud') {
302309
if (workspaceId) {
303310
const byokResult = await getBYOKKey(workspaceId, 'ollama-cloud')

‎apps/sim/lib/api/contracts/byok-keys.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export const byokProviderIdSchema = z.enum([
1414
'fireworks',
1515
'together',
1616
'baseten',
17+
'nebius',
1718
'ollama-cloud',
1819
'kie',
1920
'falai',

‎apps/sim/providers/attachments.ts‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export type AttachmentProvider =
3535
| 'fireworks'
3636
| 'together'
3737
| 'baseten'
38+
| 'nebius'
3839
| 'ollama'
3940
| 'vllm'
4041
| 'litellm'
@@ -173,6 +174,7 @@ const PROVIDER_SUPPORTED_LABELS: Record<AttachmentProvider, string> = {
173174
fireworks: 'images through image_url message parts on vision models',
174175
together: 'images through image_url message parts on vision models',
175176
baseten: 'images through image_url message parts on vision models',
177+
nebius: 'images through image_url message parts on vision models',
176178
ollama: 'images through image_url message parts on vision models',
177179
vllm: 'images through image_url message parts on multimodal models',
178180
litellm: 'images through image_url message parts on multimodal models',
@@ -197,6 +199,7 @@ export function getAttachmentProvider(providerId: ProviderId | string): Attachme
197199
if (providerId === 'fireworks') return 'fireworks'
198200
if (providerId === 'together') return 'together'
199201
if (providerId === 'baseten') return 'baseten'
202+
if (providerId === 'nebius') return 'nebius'
200203
if (providerId === 'ollama' || providerId === 'ollama-cloud') return 'ollama'
201204
if (providerId === 'vllm') return 'vllm'
202205
if (providerId === 'litellm') return 'litellm'
@@ -411,6 +414,7 @@ function isMimeTypeSupportedByProvider(
411414
case 'fireworks':
412415
case 'together':
413416
case 'baseten':
417+
case 'nebius':
414418
case 'ollama':
415419
case 'vllm':
416420
case 'litellm':

‎apps/sim/providers/history-adapters.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ export const providerHistoryProtocols: Record<
115115
fireworks: 'chat-completions',
116116
together: 'chat-completions',
117117
baseten: 'chat-completions',
118+
nebius: 'chat-completions',
118119
vllm: 'chat-completions',
119120
litellm: 'chat-completions',
120121
}

‎apps/sim/providers/models.ts‎

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import {
3535
xAIIcon,
3636
ZaiIcon,
3737
} from '@/components/icons'
38+
import { NebiusIcon } from '@/components/icons/nebius'
3839
import { LARGE_VALUE_THRESHOLD_BYTES } from '@/lib/execution/payloads/large-value-ref'
3940
import type { ModelPricing, ProviderId } from '@/providers/types'
4041

@@ -261,6 +262,166 @@ export const PROVIDER_DEFINITIONS: Record<string, ProviderDefinition> = {
261262
},
262263
],
263264
},
265+
nebius: {
266+
id: 'nebius',
267+
name: 'Nebius',
268+
description: 'Open models via Nebius Token Factory',
269+
defaultModel: 'nebius/Qwen/Qwen3.5-397B-A17B',
270+
modelPatterns: [/^nebius\//],
271+
icon: NebiusIcon,
272+
color: '#052B42',
273+
isReseller: true,
274+
capabilities: {
275+
temperature: { min: 0, max: 2 },
276+
toolUsageControl: true,
277+
},
278+
models: [
279+
{
280+
id: 'nebius/deepseek-ai/DeepSeek-V4.1-Flash',
281+
pricing: { input: 0.3, output: 1.2, updatedAt: '2026-10-07' },
282+
capabilities: { toolUsageControl: false, nativeStructuredOutputs: false },
283+
contextWindow: 1048000,
284+
},
285+
{
286+
id: 'nebius/deepseek-ai/DeepSeek-V4-Flash-0731',
287+
pricing: { input: 0.14, output: 0.28, updatedAt: '2026-10-07' },
288+
capabilities: { toolUsageControl: true, nativeStructuredOutputs: true },
289+
contextWindow: 1024000,
290+
},
291+
{
292+
id: 'nebius/deepseek-ai/DeepSeek-V4-Pro',
293+
pricing: { input: 1.75, output: 3.5, updatedAt: '2026-10-07' },
294+
capabilities: { toolUsageControl: true, nativeStructuredOutputs: true },
295+
contextWindow: 1048576,
296+
},
297+
{
298+
id: 'nebius/deepseek-ai/DeepSeek-V4-Pro-0813',
299+
pricing: { input: 1.32, output: 3.96, updatedAt: '2026-10-07' },
300+
capabilities: { toolUsageControl: true, nativeStructuredOutputs: false },
301+
contextWindow: 979000,
302+
},
303+
{
304+
id: 'nebius/google/gemma-3-27b-it',
305+
pricing: { input: 0.1, output: 0.3, updatedAt: '2026-10-07' },
306+
capabilities: { toolUsageControl: true, nativeStructuredOutputs: false },
307+
contextWindow: 110000,
308+
},
309+
{
310+
id: 'nebius/MiniMaxAI/MiniMax-M3',
311+
pricing: { input: 0.3, output: 1.2, updatedAt: '2026-10-07' },
312+
capabilities: { toolUsageControl: true, nativeStructuredOutputs: false },
313+
contextWindow: 1048576,
314+
},
315+
{
316+
id: 'nebius/moonshotai/Kimi-K2.6',
317+
pricing: { input: 0.95, output: 4, updatedAt: '2026-10-07' },
318+
capabilities: { toolUsageControl: true, nativeStructuredOutputs: false },
319+
contextWindow: 262144,
320+
},
321+
{
322+
id: 'nebius/moonshotai/Kimi-K2.7-Code',
323+
pricing: { input: 0.95, output: 4, updatedAt: '2026-10-07' },
324+
capabilities: { toolUsageControl: true, nativeStructuredOutputs: false },
325+
contextWindow: 262144,
326+
},
327+
{
328+
id: 'nebius/moonshotai/Kimi-K3',
329+
pricing: { input: 3, output: 15, updatedAt: '2026-10-07' },
330+
capabilities: { toolUsageControl: true, nativeStructuredOutputs: false },
331+
contextWindow: 1024000,
332+
},
333+
{
334+
id: 'nebius/NousResearch/Hermes-4-405B',
335+
pricing: { input: 1, output: 3, updatedAt: '2026-10-07' },
336+
capabilities: { toolUsageControl: true, nativeStructuredOutputs: true },
337+
contextWindow: 131072,
338+
},
339+
{
340+
id: 'nebius/nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B',
341+
pricing: { input: 0.06, output: 0.24, updatedAt: '2026-10-07' },
342+
capabilities: { toolUsageControl: true, nativeStructuredOutputs: false },
343+
contextWindow: 262144,
344+
},
345+
{
346+
id: 'nebius/nvidia/nemotron-3-super-120b-a12b',
347+
pricing: { input: 0.3, output: 0.9, updatedAt: '2026-10-07' },
348+
capabilities: { toolUsageControl: true, nativeStructuredOutputs: false },
349+
contextWindow: 262144,
350+
},
351+
{
352+
id: 'nebius/nvidia/Nemotron-3-Ultra-550b-a55b',
353+
pricing: { input: 1, output: 3, updatedAt: '2026-10-07' },
354+
capabilities: { toolUsageControl: true, nativeStructuredOutputs: false },
355+
contextWindow: 1048576,
356+
},
357+
{
358+
id: 'nebius/nvidia/Nemotron-3_5-Lightning',
359+
pricing: { input: 0.06, output: 0.24, updatedAt: '2026-10-07' },
360+
capabilities: { toolUsageControl: true, nativeStructuredOutputs: false },
361+
contextWindow: 1048576,
362+
},
363+
{
364+
id: 'nebius/openai/gpt-oss-120b',
365+
pricing: { input: 0.15, output: 0.6, updatedAt: '2026-10-07' },
366+
capabilities: { toolUsageControl: true, nativeStructuredOutputs: true },
367+
contextWindow: 131072,
368+
},
369+
{
370+
id: 'nebius/openbmb/MiniCPM-V-4_5',
371+
pricing: { input: 0.658, output: 1.11, updatedAt: '2026-10-07' },
372+
capabilities: { toolUsageControl: false, nativeStructuredOutputs: true },
373+
contextWindow: 32000,
374+
},
375+
{
376+
id: 'nebius/Qwen/Qwen3-235B-A22B-Instruct-2507',
377+
pricing: { input: 0.2, output: 0.6, updatedAt: '2026-10-07' },
378+
capabilities: { toolUsageControl: true, nativeStructuredOutputs: true },
379+
contextWindow: 262144,
380+
},
381+
{
382+
id: 'nebius/Qwen/Qwen3-30B-A3B-Instruct-2507',
383+
pricing: { input: 0.1, output: 0.3, updatedAt: '2026-10-07' },
384+
capabilities: { toolUsageControl: true, nativeStructuredOutputs: true },
385+
contextWindow: 262144,
386+
},
387+
{
388+
id: 'nebius/Qwen/Qwen3.5-397B-A17B',
389+
pricing: { input: 0.6, output: 3.6, updatedAt: '2026-10-07' },
390+
capabilities: { toolUsageControl: true, nativeStructuredOutputs: false },
391+
contextWindow: 262144,
392+
},
393+
{
394+
id: 'nebius/Qwen/Qwen3.8-27B',
395+
pricing: { input: 0.45, output: 3, updatedAt: '2026-10-07' },
396+
capabilities: { toolUsageControl: true, nativeStructuredOutputs: false },
397+
contextWindow: 262144,
398+
},
399+
{
400+
id: 'nebius/zai-org/GLM-5.1',
401+
pricing: { input: 1.4, output: 4.4, updatedAt: '2026-10-07' },
402+
capabilities: { toolUsageControl: true, nativeStructuredOutputs: true },
403+
contextWindow: 202752,
404+
},
405+
{
406+
id: 'nebius/zai-org/GLM-5.2',
407+
pricing: { input: 1.4, output: 4.4, updatedAt: '2026-10-07' },
408+
capabilities: { toolUsageControl: true, nativeStructuredOutputs: false },
409+
contextWindow: 1048576,
410+
},
411+
{
412+
id: 'nebius/zai-org/GLM-5.3',
413+
pricing: { input: 1.4, output: 4.4, updatedAt: '2026-10-07' },
414+
capabilities: { toolUsageControl: true, nativeStructuredOutputs: false },
415+
contextWindow: 1024000,
416+
},
417+
{
418+
id: 'nebius/zai-org/GLM-5.3-Flash',
419+
pricing: { input: 0.15, output: 0.5, updatedAt: '2026-10-07' },
420+
capabilities: { toolUsageControl: true, nativeStructuredOutputs: false },
421+
contextWindow: 1024000,
422+
},
423+
],
424+
},
264425
together: {
265426
id: 'together',
266427
fileAttachment: { maxBytes: 50 * 1024 * 1024, strategy: 'remote-url' },

0 commit comments

Comments
 (0)