From 209714a88be1dde01f8652a98cc5f66369b43fc1 Mon Sep 17 00:00:00 2001 From: amrrs <1littlecoder@gmail.com> Date: Wed, 20 May 2026 20:22:10 +0530 Subject: [PATCH] feat: add Nebius Token Factory provider --- backend/app/model/model_platform.py | 1 + .../app/controller/test_model_controller.py | 9 ++++++ backend/tests/app/model/test_chat.py | 10 +++++++ .../tests/app/model/test_model_platform.py | 1 + docs/core/models/byok.md | 29 +++++++++--------- docs/get_started/quick_start.md | 2 +- src/lib/llm.ts | 11 +++++++ src/pages/Agents/Models.tsx | 3 +- src/pages/Agents/localModels.ts | 1 + test/unit/lib/llm.test.ts | 30 +++++++++++++++++++ 10 files changed, 81 insertions(+), 16 deletions(-) create mode 100644 test/unit/lib/llm.test.ts diff --git a/backend/app/model/model_platform.py b/backend/app/model/model_platform.py index 53658a73..a4194e4d 100644 --- a/backend/app/model/model_platform.py +++ b/backend/app/model/model_platform.py @@ -22,6 +22,7 @@ PLATFORM_ALIAS_MAPPING: Final[dict[str, str]] = { "grok": "openai-compatible-model", "ernie": "qianfan", "llama.cpp": "openai-compatible-model", + "nebius": "openai-compatible-model", "orcarouter": "openai-compatible-model", } diff --git a/backend/tests/app/controller/test_model_controller.py b/backend/tests/app/controller/test_model_controller.py index 61c89831..0f40687d 100644 --- a/backend/tests/app/controller/test_model_controller.py +++ b/backend/tests/app/controller/test_model_controller.py @@ -43,6 +43,15 @@ class TestModelControllerEnhanced: ) assert request_data.model_platform == "openai-compatible-model" + def test_validate_model_request_maps_nebius_alias(self): + """Test request model maps Nebius alias to openai-compatible-model.""" + request_data = ValidateModelRequest( + model_platform="nebius", + model_type="meta-llama/Llama-3.3-70B-Instruct", + api_key="test_key", + ) + assert request_data.model_platform == "openai-compatible-model" + def test_validate_model_request_keeps_supported_platforms_unchanged(self): """Test request model keeps native camel-ai platforms unchanged.""" request_data = ValidateModelRequest( diff --git a/backend/tests/app/model/test_chat.py b/backend/tests/app/model/test_chat.py index d9932797..b42690e1 100644 --- a/backend/tests/app/model/test_chat.py +++ b/backend/tests/app/model/test_chat.py @@ -140,6 +140,11 @@ class TestModelPlatformMapping: chat = self._create_chat("grok") assert chat.model_platform == "openai-compatible-model" + def test_chat_maps_nebius_to_openai_compatible_model(self): + """Test Chat maps Nebius platform alias correctly.""" + chat = self._create_chat("nebius") + assert chat.model_platform == "openai-compatible-model" + def test_chat_keeps_supported_platforms_unchanged(self): """Test Chat keeps native camel-ai platforms unchanged.""" chat = self._create_chat("mistral") @@ -152,6 +157,11 @@ class TestModelPlatformMapping: config = AgentModelConfig(model_platform="grok") assert config.model_platform == "openai-compatible-model" + def test_agent_model_config_maps_nebius_alias(self): + """Test AgentModelConfig also maps Nebius alias.""" + config = AgentModelConfig(model_platform="nebius") + assert config.model_platform == "openai-compatible-model" + def test_agent_model_config_keeps_supported_platforms_unchanged(self): """Test AgentModelConfig keeps native camel-ai platforms unchanged.""" config = AgentModelConfig(model_platform="mistral") diff --git a/backend/tests/app/model/test_model_platform.py b/backend/tests/app/model/test_model_platform.py index c0fc2876..e9b08ada 100644 --- a/backend/tests/app/model/test_model_platform.py +++ b/backend/tests/app/model/test_model_platform.py @@ -28,6 +28,7 @@ def test_normalize_model_platform_maps_known_aliases(): assert normalize_model_platform("ModelArk") == "openai-compatible-model" assert normalize_model_platform("ernie") == "qianfan" assert normalize_model_platform("llama.cpp") == "openai-compatible-model" + assert normalize_model_platform("nebius") == "openai-compatible-model" def test_normalize_model_platform_keeps_non_alias_unchanged(): diff --git a/docs/core/models/byok.md b/docs/core/models/byok.md index 5adf6731..8153da5a 100644 --- a/docs/core/models/byok.md +++ b/docs/core/models/byok.md @@ -68,20 +68,21 @@ When saving your configuration, Eigent validates your API key and model. Here ar Eigent supports the following BYOK providers: -| Provider | Default API Host | Official Documentation | -| --------------------- | ---------------------------------------------------------- | --------------------------------------------------------------------------------------------- | -| **OpenAI** | `https://api.openai.com/v1` | [OpenAI API Docs](https://platform.openai.com/docs/api-reference) | -| **Anthropic** | `https://api.anthropic.com/` | [Anthropic API Docs](https://docs.anthropic.com/en/api/getting-started) | -| **Google Gemini** | `https://generativelanguage.googleapis.com/v1beta/openai/` | [Gemini API Docs](https://ai.google.dev/gemini-api/docs) | -| **OpenRouter** | `https://openrouter.ai/api/v1` | [OpenRouter Docs](https://openrouter.ai/docs) | -| **OrcaRouter** | `https://api.orcarouter.ai/v1` | [OrcaRouter Docs](https://docs.orcarouter.ai/) | -| **Qwen (Alibaba)** | `https://dashscope.aliyuncs.com/compatible-mode/v1` | [Qwen API Docs](https://help.aliyun.com/zh/dashscope/developer-reference/api-details) | -| **DeepSeek** | `https://api.deepseek.com` | [DeepSeek API Docs](https://platform.deepseek.com/api-docs) | -| **Minimax** | `https://api.minimax.io/v1` | [Minimax API Docs](https://platform.minimaxi.com/document/Announcement) | -| **Z.ai** | `https://api.z.ai/api/coding/paas/v4/` | [Z.ai Platform](https://z.ai) | -| **Azure OpenAI** | _(user-provided)_ | [Azure OpenAI Docs](https://learn.microsoft.com/en-us/azure/ai-services/openai/reference) | -| **AWS Bedrock** | _(user-provided)_ | [AWS Bedrock Docs](https://docs.aws.amazon.com/bedrock/latest/userguide/what-is-bedrock.html) | -| **OpenAI Compatible** | _(user-provided)_ | For custom endpoints (e.g., xAI, local servers) | +| Provider | Default API Host | Official Documentation | +| -------------------------- | ---------------------------------------------------------- | --------------------------------------------------------------------------------------------- | +| **OpenAI** | `https://api.openai.com/v1` | [OpenAI API Docs](https://platform.openai.com/docs/api-reference) | +| **Anthropic** | `https://api.anthropic.com/` | [Anthropic API Docs](https://docs.anthropic.com/en/api/getting-started) | +| **Google Gemini** | `https://generativelanguage.googleapis.com/v1beta/openai/` | [Gemini API Docs](https://ai.google.dev/gemini-api/docs) | +| **OpenRouter** | `https://openrouter.ai/api/v1` | [OpenRouter Docs](https://openrouter.ai/docs) | +| **OrcaRouter** | `https://api.orcarouter.ai/v1` | [OrcaRouter Docs](https://docs.orcarouter.ai/) | +| **Nebius Token Factory** | `https://api.tokenfactory.nebius.com/v1` | [Nebius Token Factory Docs](https://docs.tokenfactory.nebius.com/quickstart) | +| **Qwen (Alibaba)** | `https://dashscope.aliyuncs.com/compatible-mode/v1` | [Qwen API Docs](https://help.aliyun.com/zh/dashscope/developer-reference/api-details) | +| **DeepSeek** | `https://api.deepseek.com` | [DeepSeek API Docs](https://platform.deepseek.com/api-docs) | +| **Minimax** | `https://api.minimax.io/v1` | [Minimax API Docs](https://platform.minimaxi.com/document/Announcement) | +| **Z.ai** | `https://api.z.ai/api/coding/paas/v4/` | [Z.ai Platform](https://z.ai) | +| **Azure OpenAI** | _(user-provided)_ | [Azure OpenAI Docs](https://learn.microsoft.com/en-us/azure/ai-services/openai/reference) | +| **AWS Bedrock** | _(user-provided)_ | [AWS Bedrock Docs](https://docs.aws.amazon.com/bedrock/latest/userguide/what-is-bedrock.html) | +| **OpenAI Compatible** | _(user-provided)_ | For custom endpoints (e.g., xAI, local servers) | ## Tips diff --git a/docs/get_started/quick_start.md b/docs/get_started/quick_start.md index 6252c5d9..2889d38c 100644 --- a/docs/get_started/quick_start.md +++ b/docs/get_started/quick_start.md @@ -166,7 +166,7 @@ Eigent can run in two modes. Your choice here affects how you are billed and wha - **Cloud Version:** We provide pre-configured, state-of-the-art models, including GPT-4.1, GPT-4.1 mini and Gemini 2.5 Pro. Using these models is the easiest way to get started and will be billed to your account based on usage (credits). - **Self-hosted Version:** You can connect your own models. - - **Cloud Models:** Connect your personal accounts from providers like OpenAI, Anthropic, Qwen, Deepseek and Azure by entering your own API key. + - **Cloud Models:** Connect your personal accounts from providers like OpenAI, Anthropic, Qwen, Deepseek, Nebius Token Factory and Azure by entering your own API key. - **Local Models:** For advanced users, you can run models locally using Ollama, vLLM, SGLang, LM Studio, or LLaMA.cpp server. ### **MCP Servers** diff --git a/src/lib/llm.ts b/src/lib/llm.ts index 4d785f4b..da0296d7 100644 --- a/src/lib/llm.ts +++ b/src/lib/llm.ts @@ -53,6 +53,17 @@ export const INIT_PROVODERS: Provider[] = [ modelsEndpoint: '/models', websiteUrl: 'https://www.orcarouter.ai', }, + { + id: 'nebius', + name: 'Nebius Token Factory', + apiKey: '', + apiHost: 'https://api.tokenfactory.nebius.com/v1', + description: 'Nebius Token Factory model configuration.', + is_valid: false, + model_type: '', + modelsEndpoint: '/models', + websiteUrl: 'https://docs.tokenfactory.nebius.com/quickstart', + }, { id: 'openrouter', name: 'OpenRouter', diff --git a/src/pages/Agents/Models.tsx b/src/pages/Agents/Models.tsx index 40d67d80..2e6bac79 100644 --- a/src/pages/Agents/Models.tsx +++ b/src/pages/Agents/Models.tsx @@ -222,7 +222,7 @@ export default function SettingModels() { // Per-cloud-provider model list state: { groups, loading, error } keyed by // provider id. Populated for providers whose `INIT_PROVODERS` entry declares - // a `modelsEndpoint` (today: only OrcaRouter). + // a `modelsEndpoint`. const [cloudModelsState, setCloudModelsState] = useState< Record< string, @@ -1216,6 +1216,7 @@ export default function SettingModels() { openai: openaiImage, anthropic: anthropicImage, gemini: geminiImage, + nebius: PROVIDER_AVATAR_URLS.nebius, openrouter: openrouterImage, orcarouter: orcarouterImage, 'tongyi-qianwen': qwenImage, diff --git a/src/pages/Agents/localModels.ts b/src/pages/Agents/localModels.ts index 6f4c98fc..15e3cec2 100644 --- a/src/pages/Agents/localModels.ts +++ b/src/pages/Agents/localModels.ts @@ -101,6 +101,7 @@ export const DARK_FILL_MODELS = new Set([ ]); export const PROVIDER_AVATAR_URLS: Record = { + nebius: 'https://github.com/nebius.png', 'samba-nova': 'https://github.com/sambanova.png', mistral: 'https://github.com/mistralai.png', grok: 'https://github.com/xai-org.png', diff --git a/test/unit/lib/llm.test.ts b/test/unit/lib/llm.test.ts new file mode 100644 index 00000000..2ba52c53 --- /dev/null +++ b/test/unit/lib/llm.test.ts @@ -0,0 +1,30 @@ +// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. ========= +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. ========= + +import { describe, expect, it } from 'vitest'; + +import { INIT_PROVODERS } from '@/lib/llm'; + +describe('INIT_PROVODERS', () => { + it('includes Nebius Token Factory as an OpenAI-compatible BYOK provider', () => { + const provider = INIT_PROVODERS.find((item) => item.id === 'nebius'); + + expect(provider).toMatchObject({ + name: 'Nebius Token Factory', + apiHost: 'https://api.tokenfactory.nebius.com/v1', + modelsEndpoint: '/models', + websiteUrl: 'https://docs.tokenfactory.nebius.com/quickstart', + }); + }); +});