From 6df311565a8256d7a9566b47e15821837157805d Mon Sep 17 00:00:00 2001 From: kiranchilledout Date: Fri, 30 Jan 2026 15:13:23 +0530 Subject: [PATCH 1/2] Adding support for Nebius Token Factory --- docs/concepts/model-providers.md | 24 ++++ docs/docs.json | 8 ++ docs/providers/index.md | 1 + docs/providers/nebius.md | 41 ++++++ src/agents/model-auth.ts | 1 + src/agents/models-config.providers.ts | 118 ++++++++++++++++++ src/cli/program/register.onboard.ts | 4 +- src/commands/auth-choice-options.test.ts | 10 ++ src/commands/auth-choice-options.ts | 14 +++ .../auth-choice.apply.api-providers.ts | 53 ++++++++ .../auth-choice.preferred-provider.ts | 1 + src/commands/onboard-auth.config-core.ts | 69 ++++++++++ src/commands/onboard-auth.credentials.ts | 12 ++ src/commands/onboard-auth.models.ts | 23 ++++ src/commands/onboard-auth.ts | 7 ++ .../local/auth-choice.ts | 21 ++++ src/commands/onboard-types.ts | 2 + 17 files changed, 408 insertions(+), 1 deletion(-) create mode 100644 docs/providers/nebius.md diff --git a/docs/concepts/model-providers.md b/docs/concepts/model-providers.md index 38ce0b0ea..cd8832722 100644 --- a/docs/concepts/model-providers.md +++ b/docs/concepts/model-providers.md @@ -186,6 +186,30 @@ Kimi Code uses a dedicated endpoint and key (separate from Moonshot): } ``` +### Nebius + +- Provider: `nebius` +- Auth: `NEBIUS_API_KEY` +- Example model: `nebius/zai-org/GLM-4.7-FP8` + +```json5 +{ + agents: { + defaults: { model: { primary: "nebius/zai-org/GLM-4.7-FP8" } } + }, + models: { + mode: "merge", + providers: { + nebius: { + baseUrl: "https://api.tokenfactory.nebius.com/v1", + apiKey: "${NEBIUS_API_KEY}", + api: "openai-completions" + } + } + } +} +``` + ### Qwen OAuth (free tier) Qwen provides OAuth access to Qwen Coder + Vision via a device-code flow. diff --git a/docs/docs.json b/docs/docs.json index a676004f6..297289380 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -101,6 +101,14 @@ "source": "/moonshot/", "destination": "/providers/moonshot" }, + { + "source": "/nebius", + "destination": "/providers/nebius" + }, + { + "source": "/nebius/", + "destination": "/providers/nebius" + }, { "source": "/openrouter", "destination": "/providers/openrouter" diff --git a/docs/providers/index.md b/docs/providers/index.md index b2793ee22..a81856cbb 100644 --- a/docs/providers/index.md +++ b/docs/providers/index.md @@ -39,6 +39,7 @@ See [Venice AI](/providers/venice). - [OpenRouter](/providers/openrouter) - [Vercel AI Gateway](/providers/vercel-ai-gateway) - [Moonshot AI (Kimi + Kimi Code)](/providers/moonshot) +- [Nebius](/providers/nebius) - [OpenCode Zen](/providers/opencode) - [Amazon Bedrock](/bedrock) - [Z.AI](/providers/zai) diff --git a/docs/providers/nebius.md b/docs/providers/nebius.md new file mode 100644 index 000000000..583a18153 --- /dev/null +++ b/docs/providers/nebius.md @@ -0,0 +1,41 @@ +# Nebius + +Nebius offers OpenAI-compatible endpoints. OpenClaw can auto-discover available models from the Nebius `/v1/models` endpoint when you provide an API key. + +## Quick start + +```bash +export NEBIUS_API_KEY="sk-..." +openclaw onboard --auth-choice nebius-api-key --nebius-api-key "$NEBIUS_API_KEY" +``` + +This writes the key to your OpenClaw auth profiles and sets the default model to `nebius/zai-org/GLM-4.7-FP8`. + +## Configuration snippet + +```json5 +{ + agents: { + defaults: { model: { primary: "nebius/zai-org/GLM-4.7-FP8" } } + }, + models: { + mode: "merge", + providers: { + nebius: { + baseUrl: "https://api.tokenfactory.nebius.com/v1", + apiKey: "${NEBIUS_API_KEY}", + api: "openai-completions", + // models auto-discovered from /v1/models; optional static fallback: + models: [{ id: "zai-org/GLM-4.7-FP8", name: "Nebius GLM 4.7" }] + } + } + } +} +``` + +## Notes + +- Endpoint: `https://api.tokenfactory.nebius.com/v1` +- Auth: `NEBIUS_API_KEY` (Bearer) +- API: OpenAI chat completions + `/v1/models` for discovery +- Vision support is inferred from the provider’s `capabilities.vision` flag on each model. diff --git a/src/agents/model-auth.ts b/src/agents/model-auth.ts index 1445b53f7..e39424e9d 100644 --- a/src/agents/model-auth.ts +++ b/src/agents/model-auth.ts @@ -284,6 +284,7 @@ export function resolveEnvApiKey(provider: string): EnvApiKeyResult | null { xiaomi: "XIAOMI_API_KEY", synthetic: "SYNTHETIC_API_KEY", venice: "VENICE_API_KEY", + nebius: "NEBIUS_API_KEY", mistral: "MISTRAL_API_KEY", opencode: "OPENCODE_API_KEY", }; diff --git a/src/agents/models-config.providers.ts b/src/agents/models-config.providers.ts index 0cd034c82..0884cd293 100644 --- a/src/agents/models-config.providers.ts +++ b/src/agents/models-config.providers.ts @@ -41,6 +41,17 @@ const XIAOMI_DEFAULT_COST = { cacheWrite: 0, }; +const NEBIUS_BASE_URL = "https://api.tokenfactory.nebius.com/v1"; +const NEBIUS_DEFAULT_MODEL_ID = "zai-org/GLM-4.7-FP8"; +const NEBIUS_DEFAULT_CONTEXT_WINDOW = 128000; +const NEBIUS_DEFAULT_MAX_TOKENS = 8192; +const NEBIUS_DEFAULT_COST = { + input: 0, + output: 0, + cacheRead: 0, + cacheWrite: 0, +}; + const MOONSHOT_BASE_URL = "https://api.moonshot.ai/v1"; const MOONSHOT_DEFAULT_MODEL_ID = "kimi-k2.5"; const MOONSHOT_DEFAULT_CONTEXT_WINDOW = 256000; @@ -101,6 +112,8 @@ interface OllamaTagsResponse { models: OllamaModel[]; } +type OpenAiModelsResponse = { data?: unknown; models?: unknown }; + async function discoverOllamaModels(): Promise { // Skip Ollama discovery in test environments if (process.env.VITEST || process.env.NODE_ENV === "test") { @@ -139,6 +152,81 @@ async function discoverOllamaModels(): Promise { } } +function coerceModelEntries(payload: OpenAiModelsResponse): Array> { + if (!payload) return []; + if (Array.isArray(payload.data)) { + return payload.data.filter((entry) => entry && typeof entry === "object") as Array< + Record + >; + } + if (Array.isArray(payload.models)) { + return payload.models.filter((entry) => entry && typeof entry === "object") as Array< + Record + >; + } + return []; +} + +function buildNebiusModelDefinition(entry: Record): ModelDefinitionConfig | null { + const rawId = typeof entry.id === "string" ? entry.id.trim() : ""; + if (!rawId) return null; + const name = + typeof entry.name === "string" + ? entry.name.trim() + : typeof entry.display_name === "string" + ? entry.display_name.trim() + : rawId; + const contextWindow = + typeof entry.context_length === "number" && entry.context_length > 0 + ? entry.context_length + : NEBIUS_DEFAULT_CONTEXT_WINDOW; + const capabilities = + entry.capabilities && typeof entry.capabilities === "object" ? entry.capabilities : undefined; + const supportsVision = + typeof (capabilities as { vision?: unknown })?.vision === "boolean" + ? Boolean((capabilities as { vision?: unknown }).vision) + : false; + const reasoning = + typeof (capabilities as { reasoning?: unknown })?.reasoning === "boolean" + ? Boolean((capabilities as { reasoning?: unknown }).reasoning) + : false; + + return { + id: rawId, + name: name || rawId, + reasoning, + input: supportsVision ? ["text", "image"] : ["text"], + cost: NEBIUS_DEFAULT_COST, + contextWindow, + maxTokens: NEBIUS_DEFAULT_MAX_TOKENS, + }; +} + +async function discoverNebiusModels(apiKey?: string): Promise { + if (process.env.VITEST || process.env.NODE_ENV === "test" || !apiKey?.trim()) { + return []; + } + try { + const response = await fetch(`${NEBIUS_BASE_URL}/models`, { + headers: { Authorization: `Bearer ${apiKey.trim()}` }, + signal: AbortSignal.timeout(5000), + }); + if (!response.ok) { + console.warn(`Failed to discover Nebius models: ${response.status}`); + return []; + } + const payload = (await response.json()) as OpenAiModelsResponse; + const entries = coerceModelEntries(payload); + const models = entries + .map((entry) => buildNebiusModelDefinition(entry)) + .filter((model): model is ModelDefinitionConfig => Boolean(model)); + return models; + } catch (error) { + console.warn(`Failed to discover Nebius models: ${String(error)}`); + return []; + } +} + function normalizeApiKeyConfig(value: string): string { const trimmed = value.trim(); const match = /^\$\{([A-Z0-9_]+)\}$/.exec(trimmed); @@ -252,6 +340,28 @@ export function normalizeProviders(params: { return mutated ? next : providers; } +function buildNebiusDefaultModel(): ModelDefinitionConfig { + return { + id: NEBIUS_DEFAULT_MODEL_ID, + name: "Nebius GLM 4.7", + reasoning: false, + input: ["text"], + cost: NEBIUS_DEFAULT_COST, + contextWindow: NEBIUS_DEFAULT_CONTEXT_WINDOW, + maxTokens: NEBIUS_DEFAULT_MAX_TOKENS, + }; +} + +function buildNebiusProvider(models?: ModelDefinitionConfig[]): ProviderConfig { + const resolvedModels = + Array.isArray(models) && models.length > 0 ? models : [buildNebiusDefaultModel()]; + return { + baseUrl: NEBIUS_BASE_URL, + api: "openai-completions", + models: resolvedModels, + }; +} + function buildMinimaxProvider(): ProviderConfig { return { baseUrl: MINIMAX_API_BASE_URL, @@ -431,6 +541,14 @@ export async function resolveImplicitProviders(params: { providers.venice = { ...(await buildVeniceProvider()), apiKey: veniceKey }; } + const nebiusKey = + resolveEnvApiKeyVarName("nebius") ?? + resolveApiKeyFromProfiles({ provider: "nebius", store: authStore }); + if (nebiusKey) { + const nebiusModels = await discoverNebiusModels(nebiusKey); + providers.nebius = { ...buildNebiusProvider(nebiusModels), apiKey: nebiusKey }; + } + const qwenProfiles = listProfilesForProvider(authStore, "qwen-portal"); if (qwenProfiles.length > 0) { providers["qwen-portal"] = { diff --git a/src/cli/program/register.onboard.ts b/src/cli/program/register.onboard.ts index 3f81a5ee8..25c2428a6 100644 --- a/src/cli/program/register.onboard.ts +++ b/src/cli/program/register.onboard.ts @@ -52,7 +52,7 @@ export function registerOnboardCommand(program: Command) { .option("--mode ", "Wizard mode: local|remote") .option( "--auth-choice ", - "Auth: setup-token|token|chutes|openai-codex|openai-api-key|openrouter-api-key|ai-gateway-api-key|moonshot-api-key|kimi-code-api-key|synthetic-api-key|venice-api-key|gemini-api-key|zai-api-key|xiaomi-api-key|apiKey|minimax-api|minimax-api-lightning|opencode-zen|skip", + "Auth: setup-token|token|chutes|openai-codex|openai-api-key|openrouter-api-key|ai-gateway-api-key|moonshot-api-key|kimi-code-api-key|nebius-api-key|synthetic-api-key|venice-api-key|gemini-api-key|zai-api-key|xiaomi-api-key|apiKey|minimax-api|minimax-api-lightning|opencode-zen|skip", ) .option( "--token-provider ", @@ -70,6 +70,7 @@ export function registerOnboardCommand(program: Command) { .option("--ai-gateway-api-key ", "Vercel AI Gateway API key") .option("--moonshot-api-key ", "Moonshot API key") .option("--kimi-code-api-key ", "Kimi Code API key") + .option("--nebius-api-key ", "Nebius API key") .option("--gemini-api-key ", "Gemini API key") .option("--zai-api-key ", "Z.AI API key") .option("--xiaomi-api-key ", "Xiaomi API key") @@ -121,6 +122,7 @@ export function registerOnboardCommand(program: Command) { aiGatewayApiKey: opts.aiGatewayApiKey as string | undefined, moonshotApiKey: opts.moonshotApiKey as string | undefined, kimiCodeApiKey: opts.kimiCodeApiKey as string | undefined, + nebiusApiKey: opts.nebiusApiKey as string | undefined, geminiApiKey: opts.geminiApiKey as string | undefined, zaiApiKey: opts.zaiApiKey as string | undefined, xiaomiApiKey: opts.xiaomiApiKey as string | undefined, diff --git a/src/commands/auth-choice-options.test.ts b/src/commands/auth-choice-options.test.ts index c85cc0b4d..802807b9f 100644 --- a/src/commands/auth-choice-options.test.ts +++ b/src/commands/auth-choice-options.test.ts @@ -65,6 +65,16 @@ describe("buildAuthChoiceOptions", () => { expect(options.some((opt) => opt.value === "kimi-code-api-key")).toBe(true); }); + it("includes Nebius auth choice", () => { + const store: AuthProfileStore = { version: 1, profiles: {} }; + const options = buildAuthChoiceOptions({ + store, + includeSkip: false, + }); + + expect(options.some((opt) => opt.value === "nebius-api-key")).toBe(true); + }); + it("includes Vercel AI Gateway auth choice", () => { const store: AuthProfileStore = { version: 1, profiles: {} }; const options = buildAuthChoiceOptions({ diff --git a/src/commands/auth-choice-options.ts b/src/commands/auth-choice-options.ts index 5acddf4e3..3339079a1 100644 --- a/src/commands/auth-choice-options.ts +++ b/src/commands/auth-choice-options.ts @@ -15,6 +15,7 @@ export type AuthChoiceGroupId = | "openrouter" | "ai-gateway" | "moonshot" + | "nebius" | "zai" | "xiaomi" | "opencode-zen" @@ -102,6 +103,18 @@ const AUTH_CHOICE_GROUP_DEFS: { hint: "Kimi K2 + Kimi Code", choices: ["moonshot-api-key", "kimi-code-api-key"], }, + { + value: "nebius", + label: "Nebius", + hint: "OpenAI-compatible", + choices: ["nebius-api-key"], + }, + { + value: "nebius", + label: "Nebius", + hint: "OpenAI-compatible", + choices: ["nebius-api-key"], + }, { value: "zai", label: "Z.AI (GLM 4.7)", @@ -148,6 +161,7 @@ export function buildAuthChoiceOptions(params: { }); options.push({ value: "moonshot-api-key", label: "Moonshot AI API key" }); options.push({ value: "kimi-code-api-key", label: "Kimi Code API key" }); + options.push({ value: "nebius-api-key", label: "Nebius API key" }); options.push({ value: "synthetic-api-key", label: "Synthetic API key" }); options.push({ value: "venice-api-key", diff --git a/src/commands/auth-choice.apply.api-providers.ts b/src/commands/auth-choice.apply.api-providers.ts index fa4fc77e7..04da7cb84 100644 --- a/src/commands/auth-choice.apply.api-providers.ts +++ b/src/commands/auth-choice.apply.api-providers.ts @@ -17,6 +17,8 @@ import { applyKimiCodeProviderConfig, applyMoonshotConfig, applyMoonshotProviderConfig, + applyNebiusConfig, + applyNebiusProviderConfig, applyOpencodeZenConfig, applyOpencodeZenProviderConfig, applyOpenrouterConfig, @@ -32,6 +34,7 @@ import { applyZaiConfig, KIMI_CODE_MODEL_REF, MOONSHOT_DEFAULT_MODEL_REF, + NEBIUS_DEFAULT_MODEL_REF, OPENROUTER_DEFAULT_MODEL_REF, SYNTHETIC_DEFAULT_MODEL_REF, VENICE_DEFAULT_MODEL_REF, @@ -40,6 +43,7 @@ import { setGeminiApiKey, setKimiCodeApiKey, setMoonshotApiKey, + setNebiusApiKey, setOpencodeZenApiKey, setOpenrouterApiKey, setSyntheticApiKey, @@ -79,6 +83,8 @@ export async function applyAuthChoiceApiProviders( authChoice = "moonshot-api-key"; } else if (params.opts.tokenProvider === "kimi-code") { authChoice = "kimi-code-api-key"; + } else if (params.opts.tokenProvider === "nebius") { + authChoice = "nebius-api-key"; } else if (params.opts.tokenProvider === "google") { authChoice = "gemini-api-key"; } else if (params.opts.tokenProvider === "zai") { @@ -271,6 +277,53 @@ export async function applyAuthChoiceApiProviders( return { config: nextConfig, agentModelOverride }; } + if (authChoice === "nebius-api-key") { + let hasCredential = false; + + if (!hasCredential && params.opts?.token && params.opts?.tokenProvider === "nebius") { + await setNebiusApiKey(normalizeApiKeyInput(params.opts.token), params.agentDir); + hasCredential = true; + } + + const envKey = resolveEnvApiKey("nebius"); + if (envKey) { + const useExisting = await params.prompter.confirm({ + message: `Use existing NEBIUS_API_KEY (${envKey.source}, ${formatApiKeyPreview(envKey.apiKey)})?`, + initialValue: true, + }); + if (useExisting) { + await setNebiusApiKey(envKey.apiKey, params.agentDir); + hasCredential = true; + } + } + if (!hasCredential) { + const key = await params.prompter.text({ + message: "Enter Nebius API key", + validate: validateApiKeyInput, + }); + await setNebiusApiKey(normalizeApiKeyInput(String(key)), params.agentDir); + } + nextConfig = applyAuthProfileConfig(nextConfig, { + profileId: "nebius:default", + provider: "nebius", + mode: "api_key", + }); + { + const applied = await applyDefaultModelChoice({ + config: nextConfig, + setDefaultModel: params.setDefaultModel, + defaultModel: NEBIUS_DEFAULT_MODEL_REF, + applyDefaultConfig: applyNebiusConfig, + applyProviderConfig: applyNebiusProviderConfig, + noteAgentModel, + prompter: params.prompter, + }); + nextConfig = applied.config; + agentModelOverride = applied.agentModelOverride ?? agentModelOverride; + } + return { config: nextConfig, agentModelOverride }; + } + if (authChoice === "kimi-code-api-key") { let hasCredential = false; if (!hasCredential && params.opts?.token && params.opts?.tokenProvider === "kimi-code") { diff --git a/src/commands/auth-choice.preferred-provider.ts b/src/commands/auth-choice.preferred-provider.ts index a4d831c92..96495a0e9 100644 --- a/src/commands/auth-choice.preferred-provider.ts +++ b/src/commands/auth-choice.preferred-provider.ts @@ -14,6 +14,7 @@ const PREFERRED_PROVIDER_BY_AUTH_CHOICE: Partial> = { "ai-gateway-api-key": "vercel-ai-gateway", "moonshot-api-key": "moonshot", "kimi-code-api-key": "kimi-code", + "nebius-api-key": "nebius", "gemini-api-key": "google", "google-antigravity": "google-antigravity", "google-gemini-cli": "google-gemini-cli", diff --git a/src/commands/onboard-auth.config-core.ts b/src/commands/onboard-auth.config-core.ts index c94eeb51b..36c72c969 100644 --- a/src/commands/onboard-auth.config-core.ts +++ b/src/commands/onboard-auth.config-core.ts @@ -21,12 +21,16 @@ import { import { buildKimiCodeModelDefinition, buildMoonshotModelDefinition, + buildNebiusModelDefinition, KIMI_CODE_BASE_URL, KIMI_CODE_MODEL_ID, KIMI_CODE_MODEL_REF, MOONSHOT_BASE_URL, MOONSHOT_DEFAULT_MODEL_ID, MOONSHOT_DEFAULT_MODEL_REF, + NEBIUS_BASE_URL, + NEBIUS_DEFAULT_MODEL_ID, + NEBIUS_DEFAULT_MODEL_REF, } from "./onboard-auth.models.js"; export function applyZaiConfig(cfg: OpenClawConfig): OpenClawConfig { @@ -204,6 +208,71 @@ export function applyMoonshotConfig(cfg: OpenClawConfig): OpenClawConfig { }; } +export function applyNebiusProviderConfig(cfg: OpenClawConfig): OpenClawConfig { + const models = { ...cfg.agents?.defaults?.models }; + models[NEBIUS_DEFAULT_MODEL_REF] = { + ...models[NEBIUS_DEFAULT_MODEL_REF], + alias: models[NEBIUS_DEFAULT_MODEL_REF]?.alias ?? "Nebius GLM 4.7", + }; + + const providers = { ...cfg.models?.providers }; + const existingProvider = providers.nebius; + const existingModels = Array.isArray(existingProvider?.models) ? existingProvider.models : []; + const defaultModel = buildNebiusModelDefinition(); + const hasDefaultModel = existingModels.some((model) => model.id === NEBIUS_DEFAULT_MODEL_ID); + const mergedModels = hasDefaultModel ? existingModels : [...existingModels, defaultModel]; + const { apiKey: existingApiKey, ...existingProviderRest } = (existingProvider ?? {}) as Record< + string, + unknown + > as { apiKey?: string }; + const resolvedApiKey = typeof existingApiKey === "string" ? existingApiKey : undefined; + const normalizedApiKey = resolvedApiKey?.trim(); + providers.nebius = { + ...existingProviderRest, + baseUrl: NEBIUS_BASE_URL, + api: "openai-completions", + ...(normalizedApiKey ? { apiKey: normalizedApiKey } : {}), + models: mergedModels.length > 0 ? mergedModels : [defaultModel], + }; + + return { + ...cfg, + agents: { + ...cfg.agents, + defaults: { + ...cfg.agents?.defaults, + models, + }, + }, + models: { + mode: cfg.models?.mode ?? "merge", + providers, + }, + }; +} + +export function applyNebiusConfig(cfg: OpenClawConfig): OpenClawConfig { + const next = applyNebiusProviderConfig(cfg); + const existingModel = next.agents?.defaults?.model; + return { + ...next, + agents: { + ...next.agents, + defaults: { + ...next.agents?.defaults, + model: { + ...(existingModel && "fallbacks" in (existingModel as Record) + ? { + fallbacks: (existingModel as { fallbacks?: string[] }).fallbacks, + } + : undefined), + primary: NEBIUS_DEFAULT_MODEL_REF, + }, + }, + }, + }; +} + export function applyKimiCodeProviderConfig(cfg: OpenClawConfig): OpenClawConfig { const models = { ...cfg.agents?.defaults?.models }; models[KIMI_CODE_MODEL_REF] = { diff --git a/src/commands/onboard-auth.credentials.ts b/src/commands/onboard-auth.credentials.ts index fbf6dbfb9..c1271c098 100644 --- a/src/commands/onboard-auth.credentials.ts +++ b/src/commands/onboard-auth.credentials.ts @@ -177,3 +177,15 @@ export async function setOpencodeZenApiKey(key: string, agentDir?: string) { agentDir: resolveAuthAgentDir(agentDir), }); } + +export async function setNebiusApiKey(key: string, agentDir?: string) { + upsertAuthProfile({ + profileId: "nebius:default", + credential: { + type: "api_key", + provider: "nebius", + key, + }, + agentDir: resolveAuthAgentDir(agentDir), + }); +} diff --git a/src/commands/onboard-auth.models.ts b/src/commands/onboard-auth.models.ts index de5a4edaa..c3cdbf130 100644 --- a/src/commands/onboard-auth.models.ts +++ b/src/commands/onboard-auth.models.ts @@ -12,6 +12,11 @@ export const MOONSHOT_DEFAULT_MODEL_ID = "kimi-k2-0905-preview"; export const MOONSHOT_DEFAULT_MODEL_REF = `moonshot/${MOONSHOT_DEFAULT_MODEL_ID}`; export const MOONSHOT_DEFAULT_CONTEXT_WINDOW = 256000; export const MOONSHOT_DEFAULT_MAX_TOKENS = 8192; +export const NEBIUS_BASE_URL = "https://api.tokenfactory.nebius.com/v1"; +export const NEBIUS_DEFAULT_MODEL_ID = "zai-org/GLM-4.7-FP8"; +export const NEBIUS_DEFAULT_MODEL_REF = `nebius/${NEBIUS_DEFAULT_MODEL_ID}`; +export const NEBIUS_DEFAULT_CONTEXT_WINDOW = 128000; +export const NEBIUS_DEFAULT_MAX_TOKENS = 8192; export const KIMI_CODE_BASE_URL = "https://api.kimi.com/coding/v1"; export const KIMI_CODE_MODEL_ID = "kimi-for-coding"; export const KIMI_CODE_MODEL_REF = `kimi-code/${KIMI_CODE_MODEL_ID}`; @@ -45,6 +50,12 @@ export const MOONSHOT_DEFAULT_COST = { cacheRead: 0, cacheWrite: 0, }; +export const NEBIUS_DEFAULT_COST = { + input: 0, + output: 0, + cacheRead: 0, + cacheWrite: 0, +}; export const KIMI_CODE_DEFAULT_COST = { input: 0, output: 0, @@ -103,6 +114,18 @@ export function buildMoonshotModelDefinition(): ModelDefinitionConfig { }; } +export function buildNebiusModelDefinition(): ModelDefinitionConfig { + return { + id: NEBIUS_DEFAULT_MODEL_ID, + name: "Nebius GLM 4.7", + reasoning: false, + input: ["text"], + cost: NEBIUS_DEFAULT_COST, + contextWindow: NEBIUS_DEFAULT_CONTEXT_WINDOW, + maxTokens: NEBIUS_DEFAULT_MAX_TOKENS, + }; +} + export function buildKimiCodeModelDefinition(): ModelDefinitionConfig { return { id: KIMI_CODE_MODEL_ID, diff --git a/src/commands/onboard-auth.ts b/src/commands/onboard-auth.ts index 612b24865..9c2266c54 100644 --- a/src/commands/onboard-auth.ts +++ b/src/commands/onboard-auth.ts @@ -9,6 +9,8 @@ export { applyKimiCodeProviderConfig, applyMoonshotConfig, applyMoonshotProviderConfig, + applyNebiusConfig, + applyNebiusProviderConfig, applyOpenrouterConfig, applyOpenrouterProviderConfig, applySyntheticConfig, @@ -41,6 +43,7 @@ export { setKimiCodeApiKey, setMinimaxApiKey, setMoonshotApiKey, + setNebiusApiKey, setOpencodeZenApiKey, setOpenrouterApiKey, setSyntheticApiKey, @@ -58,6 +61,7 @@ export { buildMinimaxApiModelDefinition, buildMinimaxModelDefinition, buildMoonshotModelDefinition, + buildNebiusModelDefinition, DEFAULT_MINIMAX_BASE_URL, KIMI_CODE_BASE_URL, KIMI_CODE_MODEL_ID, @@ -68,4 +72,7 @@ export { MOONSHOT_BASE_URL, MOONSHOT_DEFAULT_MODEL_ID, MOONSHOT_DEFAULT_MODEL_REF, + NEBIUS_BASE_URL, + NEBIUS_DEFAULT_MODEL_ID, + NEBIUS_DEFAULT_MODEL_REF, } from "./onboard-auth.models.js"; diff --git a/src/commands/onboard-non-interactive/local/auth-choice.ts b/src/commands/onboard-non-interactive/local/auth-choice.ts index 8719a1f1a..fff7b6ec6 100644 --- a/src/commands/onboard-non-interactive/local/auth-choice.ts +++ b/src/commands/onboard-non-interactive/local/auth-choice.ts @@ -12,6 +12,7 @@ import { applyMinimaxApiConfig, applyMinimaxConfig, applyMoonshotConfig, + applyNebiusConfig, applyOpencodeZenConfig, applyOpenrouterConfig, applySyntheticConfig, @@ -24,6 +25,7 @@ import { setKimiCodeApiKey, setMinimaxApiKey, setMoonshotApiKey, + setNebiusApiKey, setOpencodeZenApiKey, setOpenrouterApiKey, setSyntheticApiKey, @@ -273,6 +275,25 @@ export async function applyNonInteractiveAuthChoice(params: { return applyMoonshotConfig(nextConfig); } + if (authChoice === "nebius-api-key") { + const resolved = await resolveNonInteractiveApiKey({ + provider: "nebius", + cfg: baseConfig, + flagValue: opts.nebiusApiKey, + flagName: "--nebius-api-key", + envVar: "NEBIUS_API_KEY", + runtime, + }); + if (!resolved) return null; + if (resolved.source !== "profile") await setNebiusApiKey(resolved.key); + nextConfig = applyAuthProfileConfig(nextConfig, { + profileId: "nebius:default", + provider: "nebius", + mode: "api_key", + }); + return applyNebiusConfig(nextConfig); + } + if (authChoice === "kimi-code-api-key") { const resolved = await resolveNonInteractiveApiKey({ provider: "kimi-code", diff --git a/src/commands/onboard-types.ts b/src/commands/onboard-types.ts index f4154bc6d..baae2f350 100644 --- a/src/commands/onboard-types.ts +++ b/src/commands/onboard-types.ts @@ -15,6 +15,7 @@ export type AuthChoice = | "ai-gateway-api-key" | "moonshot-api-key" | "kimi-code-api-key" + | "nebius-api-key" | "synthetic-api-key" | "venice-api-key" | "codex-cli" @@ -66,6 +67,7 @@ export type OnboardOptions = { aiGatewayApiKey?: string; moonshotApiKey?: string; kimiCodeApiKey?: string; + nebiusApiKey?: string; geminiApiKey?: string; zaiApiKey?: string; xiaomiApiKey?: string; From b9653f8d66b2baa81d8446c121e82d25cda973cc Mon Sep 17 00:00:00 2001 From: kiranchilledout Date: Fri, 30 Jan 2026 15:41:43 +0530 Subject: [PATCH 2/2] chore: trigger ci for Nebius provider