From e9335828c0959e1d64fd68b441e113539064a433 Mon Sep 17 00:00:00 2001 From: PR Bot Date: Thu, 26 Mar 2026 19:10:49 +0800 Subject: [PATCH 1/5] feat: add MiniMax as LLM provider for Python and TypeScript Add MiniMax as a first-class LLM provider in both Python and TypeScript implementations. MiniMax provides an OpenAI-compatible API, making integration straightforward through existing LiteLLM (Python) and Vercel AI SDK (TypeScript) infrastructure. Python: - Add MiniMaxChatModel extending LiteLLMChatModel with OpenAI-compat routing - Register "minimax" provider in BackendProviders with proper ProviderName/ProviderHumanName - Support MINIMAX_API_KEY, MINIMAX_CHAT_MODEL, MINIMAX_API_BASE env vars - Default model: MiniMax-M2.7, default base URL: https://api.minimax.io/v1 - 15 unit tests (all passing) + 3 integration tests (all passing) - Provider example following existing deepseek/qwen pattern TypeScript: - Add MiniMaxChatModel extending VercelChatModel via @ai-sdk/openai - Add MiniMaxClient extending BackendClient with OpenAI provider - Register "MiniMax" in BackendProviders with "minimax" alias - Support MINIMAX_API_KEY, MINIMAX_CHAT_MODEL, MINIMAX_API_BASE env vars - 9 unit tests + provider example following existing xai pattern Documentation: - Add MiniMax to supported providers table in docs/modules/backend.mdx Available models: MiniMax-M2.7, MiniMax-M2.7-highspeed, MiniMax-M2.5, MiniMax-M2.5-highspeed Signed-off-by: octo-patch --- docs-old/modules/backend.mdx | 1 + .../adapters/minimax/__init__.py | 6 + .../adapters/minimax/backend/__init__.py | 2 + .../adapters/minimax/backend/chat.py | 70 ++++++++++ python/beeai_framework/backend/constants.py | 3 + python/examples/backend/providers/minimax.py | 101 ++++++++++++++ python/tests/adapters/minimax/__init__.py | 2 + .../adapters/minimax/test_minimax_chat.py | 111 +++++++++++++++ .../minimax/test_minimax_integration.py | 59 ++++++++ .../examples/backend/providers/minimax.ts | 130 ++++++++++++++++++ .../src/adapters/minimax/backend/chat.ts | 29 ++++ .../src/adapters/minimax/backend/client.ts | 28 ++++ typescript/src/backend/constants.ts | 5 + typescript/tests/e2e/adapters/minimax.test.ts | 96 +++++++++++++ 14 files changed, 643 insertions(+) create mode 100644 python/beeai_framework/adapters/minimax/__init__.py create mode 100644 python/beeai_framework/adapters/minimax/backend/__init__.py create mode 100644 python/beeai_framework/adapters/minimax/backend/chat.py create mode 100644 python/examples/backend/providers/minimax.py create mode 100644 python/tests/adapters/minimax/__init__.py create mode 100644 python/tests/adapters/minimax/test_minimax_chat.py create mode 100644 python/tests/adapters/minimax/test_minimax_integration.py create mode 100644 typescript/examples/backend/providers/minimax.ts create mode 100644 typescript/src/adapters/minimax/backend/chat.ts create mode 100644 typescript/src/adapters/minimax/backend/client.ts create mode 100644 typescript/tests/e2e/adapters/minimax.test.ts diff --git a/docs-old/modules/backend.mdx b/docs-old/modules/backend.mdx index da3e6dfbb..abceac2c9 100644 --- a/docs-old/modules/backend.mdx +++ b/docs-old/modules/backend.mdx @@ -39,6 +39,7 @@ The following table depicts supported providers. Each provider requires specific | Google Gemini | ✅ | ✅ | GEMINI_CHAT_MODEL
**GEMINI_API_KEY**
GEMINI_API_HEADERS | | MistralAI | ✅ | ✅ | MISTRALAI_CHAT_MODEL
MISTRALAI_EMBEDDING_MODEL
**MISTRALAI_API_KEY**
MISTRALAI_API_BASE | | Transformers | ✅ | ✅ | TRANSFORMERS_CHAT_MODEL
HF_TOKEN| +| MiniMax | ✅ | ❌ | MINIMAX_CHAT_MODEL
**MINIMAX_API_KEY**
MINIMAX_API_BASE
MINIMAX_API_HEADERS | If you don't see your provider raise an issue [here](https://github.com/i-am-bee/beeai-framework/issues). diff --git a/python/beeai_framework/adapters/minimax/__init__.py b/python/beeai_framework/adapters/minimax/__init__.py new file mode 100644 index 000000000..128f60bff --- /dev/null +++ b/python/beeai_framework/adapters/minimax/__init__.py @@ -0,0 +1,6 @@ +# Copyright 2025 © BeeAI a Series of LF Projects, LLC +# SPDX-License-Identifier: Apache-2.0 + +from beeai_framework.adapters.minimax.backend.chat import MiniMaxChatModel + +__all__ = ["MiniMaxChatModel"] diff --git a/python/beeai_framework/adapters/minimax/backend/__init__.py b/python/beeai_framework/adapters/minimax/backend/__init__.py new file mode 100644 index 000000000..ef775222d --- /dev/null +++ b/python/beeai_framework/adapters/minimax/backend/__init__.py @@ -0,0 +1,2 @@ +# Copyright 2025 © BeeAI a Series of LF Projects, LLC +# SPDX-License-Identifier: Apache-2.0 diff --git a/python/beeai_framework/adapters/minimax/backend/chat.py b/python/beeai_framework/adapters/minimax/backend/chat.py new file mode 100644 index 000000000..91b561c8a --- /dev/null +++ b/python/beeai_framework/adapters/minimax/backend/chat.py @@ -0,0 +1,70 @@ +# Copyright 2025 © BeeAI a Series of LF Projects, LLC +# SPDX-License-Identifier: Apache-2.0 + +import os +from typing_extensions import Unpack + +from beeai_framework.adapters.litellm import LiteLLMChatModel, utils +from beeai_framework.backend.chat import ChatModelKwargs +from beeai_framework.backend.constants import ProviderName +from beeai_framework.logger import Logger + +logger = Logger(__name__) + +MINIMAX_API_BASE = "https://api.minimax.io/v1" + + +class MiniMaxChatModel(LiteLLMChatModel): + """ + A chat model implementation for the MiniMax provider, leveraging LiteLLM. + + MiniMax provides an OpenAI-compatible API. This adapter routes requests + through LiteLLM's OpenAI provider with the MiniMax base URL. + + Available models include MiniMax-M2.7, MiniMax-M2.7-highspeed, + MiniMax-M2.5, and MiniMax-M2.5-highspeed. + """ + + @property + def provider_id(self) -> ProviderName: + """The provider ID for MiniMax.""" + return "minimax" + + def __init__( + self, + model_id: str | None = None, + *, + api_key: str | None = None, + base_url: str | None = None, + **kwargs: Unpack[ChatModelKwargs], + ) -> None: + """ + Initializes the MinimaxChatModel. + + Args: + model_id: The ID of the MiniMax model to use. If not provided, + it falls back to the MINIMAX_CHAT_MODEL environment variable, + and then defaults to 'MiniMax-M2.7'. + api_key: The MiniMax API key. Falls back to MINIMAX_API_KEY env var. + base_url: The MiniMax API base URL. Falls back to MINIMAX_API_BASE + env var, then defaults to 'https://api.minimax.io/v1'. + **kwargs: Additional settings to configure the provider. + """ + super().__init__( + model_id if model_id else os.getenv("MINIMAX_CHAT_MODEL", "MiniMax-M2.7"), + provider_id="openai", + **kwargs, + ) + + self._assert_setting_value("api_key", api_key, envs=["MINIMAX_API_KEY"]) + self._assert_setting_value( + "base_url", + base_url, + envs=["MINIMAX_API_BASE"], + aliases=["api_base"], + allow_empty=True, + fallback=MINIMAX_API_BASE, + ) + self._settings["extra_headers"] = utils.parse_extra_headers( + self._settings.get("extra_headers"), os.getenv("MINIMAX_API_HEADERS") + ) diff --git a/python/beeai_framework/backend/constants.py b/python/beeai_framework/backend/constants.py index d2569ab7f..8f4e70e1e 100644 --- a/python/beeai_framework/backend/constants.py +++ b/python/beeai_framework/backend/constants.py @@ -24,6 +24,7 @@ "transformers", "deepseek", "qwen", + "minimax", ] ProviderHumanName = Literal[ "AgentStack", @@ -44,6 +45,7 @@ "Transformers", "Deepseek", "Qwen", + "MiniMax", ] ModelTypes = Literal["embedding", "chat"] @@ -95,4 +97,5 @@ class ProviderModuleDef(BaseModel): "Transformers": ProviderDef(name="Transformers", module="transformers", aliases=["Transformers", "transformers"]), "Deepseek": ProviderDef(name="Deepseek", module="deepseek", aliases=["deepseek"]), "Qwen": ProviderDef(name="Qwen", module="qwen", aliases=["qwen", "dashscope"]), + "MiniMax": ProviderDef(name="MiniMax", module="minimax", aliases=["minimax"]), } diff --git a/python/examples/backend/providers/minimax.py b/python/examples/backend/providers/minimax.py new file mode 100644 index 000000000..3de712045 --- /dev/null +++ b/python/examples/backend/providers/minimax.py @@ -0,0 +1,101 @@ +# Copyright 2025 © BeeAI a Series of LF Projects, LLC +# SPDX-License-Identifier: Apache-2.0 + +import asyncio + +from dotenv import load_dotenv +from pydantic import BaseModel, Field + +from beeai_framework.adapters.minimax import MiniMaxChatModel +from beeai_framework.backend import ChatModel, ChatModelNewTokenEvent, UserMessage +from beeai_framework.emitter import EventMeta +from beeai_framework.errors import AbortError +from beeai_framework.parsers.field import ParserField +from beeai_framework.parsers.line_prefix import LinePrefixParser, LinePrefixParserNode +from beeai_framework.utils import AbortSignal + + +async def minimax_from_name() -> None: + llm = ChatModel.from_name("minimax:MiniMax-M2.7") + user_message = UserMessage("what states are part of New England?") + response = await llm.run([user_message]) + print(response.get_text_content()) + + +async def minimax_sync() -> None: + llm = MiniMaxChatModel("MiniMax-M2.7") + user_message = UserMessage("what is the capital of Massachusetts?") + response = await llm.run([user_message]) + print(response.get_text_content()) + + +async def minimax_stream() -> None: + llm = MiniMaxChatModel("MiniMax-M2.7") + user_message = UserMessage("How many islands make up the country of Cape Verde?") + response = await llm.run([user_message], stream=True) + print(response.get_text_content()) + + +async def minimax_stream_abort() -> None: + llm = MiniMaxChatModel("MiniMax-M2.7") + user_message = UserMessage("What is the smallest of the Cape Verde islands?") + + try: + response = await llm.run([user_message], stream=True, signal=AbortSignal.timeout(0.5)) + + if response is not None: + print(response.get_text_content()) + else: + print("No response returned.") + except AbortError as err: + print(f"Aborted: {err}") + + +async def minimax_structure() -> None: + class TestSchema(BaseModel): + answer: str = Field(description="your final answer") + + llm = MiniMaxChatModel("MiniMax-M2.7") + user_message = UserMessage("How many islands make up the country of Cape Verde?") + response = await llm.run([user_message], response_format=TestSchema) + print(response.output_structured) + + +async def minimax_stream_parser() -> None: + llm = MiniMaxChatModel("MiniMax-M2.7") + + parser = LinePrefixParser( + nodes={ + "test": LinePrefixParserNode( + prefix="Prefix: ", field=ParserField.from_type(str), is_start=True, is_end=True + ) + } + ) + + async def on_new_token(data: ChatModelNewTokenEvent, event: EventMeta) -> None: + await parser.add(chunk=data.value.get_text_content()) + + user_message = UserMessage("Produce 3 lines each starting with 'Prefix: ' followed by a sentence and a new line.") + await llm.run([user_message], stream=True).observe(lambda emitter: emitter.on("new_token", on_new_token)) + result = await parser.end() + print(result) + + +async def main() -> None: + print("*" * 10, "minimax_from_name") + await minimax_from_name() + print("*" * 10, "minimax_sync") + await minimax_sync() + print("*" * 10, "minimax_stream") + await minimax_stream() + print("*" * 10, "minimax_stream_abort") + await minimax_stream_abort() + print("*" * 10, "minimax_structure") + await minimax_structure() + print("*" * 10, "minimax_stream_parser") + await minimax_stream_parser() + + +if __name__ == "__main__": + load_dotenv() + asyncio.run(main()) diff --git a/python/tests/adapters/minimax/__init__.py b/python/tests/adapters/minimax/__init__.py new file mode 100644 index 000000000..ef775222d --- /dev/null +++ b/python/tests/adapters/minimax/__init__.py @@ -0,0 +1,2 @@ +# Copyright 2025 © BeeAI a Series of LF Projects, LLC +# SPDX-License-Identifier: Apache-2.0 diff --git a/python/tests/adapters/minimax/test_minimax_chat.py b/python/tests/adapters/minimax/test_minimax_chat.py new file mode 100644 index 000000000..12c7c5e55 --- /dev/null +++ b/python/tests/adapters/minimax/test_minimax_chat.py @@ -0,0 +1,111 @@ +# Copyright 2025 © BeeAI a Series of LF Projects, LLC +# SPDX-License-Identifier: Apache-2.0 + +import os +from unittest.mock import patch + +import pytest + +from beeai_framework.adapters.minimax.backend.chat import MINIMAX_API_BASE, MiniMaxChatModel +from beeai_framework.backend.chat import ChatModel +from beeai_framework.backend.constants import BackendProviders + + +class TestMiniMaxProviderRegistration: + """Test that MiniMax is properly registered as a provider.""" + + def test_minimax_in_backend_providers(self) -> None: + assert "MiniMax" in BackendProviders + provider = BackendProviders["MiniMax"] + assert provider.name == "MiniMax" + assert provider.module == "minimax" + assert "minimax" in provider.aliases + + def test_provider_def_has_correct_structure(self) -> None: + provider = BackendProviders["MiniMax"] + assert hasattr(provider, "name") + assert hasattr(provider, "module") + assert hasattr(provider, "aliases") + + +class TestMiniMaxChatModelInit: + """Test MiniMaxChatModel initialization.""" + + @patch.dict(os.environ, {"MINIMAX_API_KEY": "test-key-123"}) + def test_default_model_id(self) -> None: + model = MiniMaxChatModel() + assert model.model_id == "MiniMax-M2.7" + + @patch.dict(os.environ, {"MINIMAX_API_KEY": "test-key-123"}) + def test_custom_model_id(self) -> None: + model = MiniMaxChatModel("MiniMax-M2.5") + assert model.model_id == "MiniMax-M2.5" + + @patch.dict(os.environ, {"MINIMAX_API_KEY": "test-key-123"}) + def test_highspeed_model_id(self) -> None: + model = MiniMaxChatModel("MiniMax-M2.7-highspeed") + assert model.model_id == "MiniMax-M2.7-highspeed" + + @patch.dict( + os.environ, + {"MINIMAX_API_KEY": "test-key-123", "MINIMAX_CHAT_MODEL": "MiniMax-M2.5-highspeed"}, + ) + def test_model_from_env(self) -> None: + model = MiniMaxChatModel() + assert model.model_id == "MiniMax-M2.5-highspeed" + + @patch.dict(os.environ, {"MINIMAX_API_KEY": "test-key-123"}) + def test_provider_id(self) -> None: + model = MiniMaxChatModel() + assert model.provider_id == "minimax" + + @patch.dict(os.environ, {"MINIMAX_API_KEY": "test-key-123"}) + def test_default_base_url(self) -> None: + model = MiniMaxChatModel() + assert model._settings.get("base_url") == MINIMAX_API_BASE + + @patch.dict( + os.environ, + {"MINIMAX_API_KEY": "test-key-123", "MINIMAX_API_BASE": "https://custom.minimax.io/v1"}, + ) + def test_custom_base_url_from_env(self) -> None: + model = MiniMaxChatModel() + assert model._settings.get("base_url") == "https://custom.minimax.io/v1" + + @patch.dict(os.environ, {"MINIMAX_API_KEY": "test-key-123"}) + def test_custom_base_url_param(self) -> None: + model = MiniMaxChatModel(base_url="https://proxy.example.com/v1") + assert model._settings.get("base_url") == "https://proxy.example.com/v1" + + @patch.dict(os.environ, {"MINIMAX_API_KEY": "test-key-123"}) + def test_api_key_stored(self) -> None: + model = MiniMaxChatModel() + assert model._settings.get("api_key") == "test-key-123" + + def test_missing_api_key_raises(self) -> None: + with patch.dict(os.environ, {}, clear=True): + # Remove any existing MINIMAX_API_KEY + os.environ.pop("MINIMAX_API_KEY", None) + with pytest.raises(ValueError, match="api_key.*required"): + MiniMaxChatModel() + + @patch.dict(os.environ, {"MINIMAX_API_KEY": "test-key-123"}) + def test_explicit_api_key(self) -> None: + model = MiniMaxChatModel(api_key="explicit-key") + assert model._settings.get("api_key") == "explicit-key" + + +class TestMiniMaxModelLoading: + """Test that MiniMax models can be loaded via the factory method.""" + + @patch.dict(os.environ, {"MINIMAX_API_KEY": "test-key-123"}) + def test_load_from_name(self) -> None: + model = ChatModel.from_name("minimax:MiniMax-M2.7") + assert isinstance(model, MiniMaxChatModel) + assert model.model_id == "MiniMax-M2.7" + + @patch.dict(os.environ, {"MINIMAX_API_KEY": "test-key-123"}) + def test_load_from_alias(self) -> None: + model = ChatModel.from_name("minimax:MiniMax-M2.5") + assert isinstance(model, MiniMaxChatModel) + assert model.model_id == "MiniMax-M2.5" diff --git a/python/tests/adapters/minimax/test_minimax_integration.py b/python/tests/adapters/minimax/test_minimax_integration.py new file mode 100644 index 000000000..34d9544c0 --- /dev/null +++ b/python/tests/adapters/minimax/test_minimax_integration.py @@ -0,0 +1,59 @@ +# Copyright 2025 © BeeAI a Series of LF Projects, LLC +# SPDX-License-Identifier: Apache-2.0 + +"""Integration tests for MiniMax chat model. + +These tests require a valid MINIMAX_API_KEY environment variable. +Run with: pytest tests/adapters/minimax/test_minimax_integration.py -v +""" + +import os + +import pytest + +from beeai_framework.adapters.minimax.backend.chat import MiniMaxChatModel +from beeai_framework.backend.message import UserMessage + +pytestmark = pytest.mark.skipif( + not os.getenv("MINIMAX_API_KEY"), + reason="MINIMAX_API_KEY not set", +) + + +@pytest.fixture +def chat_model() -> MiniMaxChatModel: + return MiniMaxChatModel("MiniMax-M2.7") + + +@pytest.fixture +def highspeed_model() -> MiniMaxChatModel: + return MiniMaxChatModel("MiniMax-M2.7-highspeed") + + +class TestMiniMaxIntegration: + """Integration tests that call the real MiniMax API.""" + + @pytest.mark.asyncio + async def test_simple_chat(self, chat_model: MiniMaxChatModel) -> None: + output = await chat_model.run( + [UserMessage("What is 2 + 2? Reply with just the number.")], + ) + text = output.get_text_content() + assert "4" in text + + @pytest.mark.asyncio + async def test_highspeed_model(self, highspeed_model: MiniMaxChatModel) -> None: + output = await highspeed_model.run( + [UserMessage("Say hello in one word.")], + ) + text = output.get_text_content() + assert len(text) > 0 + + @pytest.mark.asyncio + async def test_streaming(self, chat_model: MiniMaxChatModel) -> None: + output = await chat_model.run( + [UserMessage("Count from 1 to 3.")], + stream=True, + ) + text = output.get_text_content() + assert "1" in text diff --git a/typescript/examples/backend/providers/minimax.ts b/typescript/examples/backend/providers/minimax.ts new file mode 100644 index 000000000..6c84d8f4b --- /dev/null +++ b/typescript/examples/backend/providers/minimax.ts @@ -0,0 +1,130 @@ +import "dotenv/config"; +import { MiniMaxChatModel } from "beeai-framework/adapters/minimax/backend/chat"; +import "dotenv/config.js"; +import { ToolMessage, UserMessage } from "beeai-framework/backend/message"; +import { ChatModel } from "beeai-framework/backend/chat"; +import { AbortError } from "beeai-framework/errors"; +import { z } from "zod"; +import { OpenMeteoTool } from "beeai-framework/tools/weather/openMeteo"; + +const llm = new MiniMaxChatModel( + "MiniMax-M2.7", + // {}, + // { + // apiKey: "MINIMAX_API_KEY", + // baseURL: "https://api.minimax.io/v1", + // }, +); + +llm.config({ + parameters: { + temperature: 0.7, + maxTokens: 1024, + topP: 1, + }, +}); + +async function minimaxFromName() { + const minimaxLLM = await ChatModel.fromName("minimax:MiniMax-M2.7"); + const response = await minimaxLLM.create({ + messages: [new UserMessage("what states are part of New England?")], + }); + console.info(response.getTextContent()); +} + +async function minimaxSync() { + const response = await llm.create({ + messages: [new UserMessage("what is the capital of Massachusetts?")], + }); + console.info(response.getTextContent()); +} + +async function minimaxStream() { + const response = await llm.create({ + messages: [new UserMessage("How many islands make up the country of Cape Verde?")], + stream: true, + }); + console.info(response.getTextContent()); +} + +async function minimaxAbort() { + try { + const response = await llm.create({ + messages: [new UserMessage("What is the smallest of the Cape Verde islands?")], + stream: true, + abortSignal: AbortSignal.timeout(5 * 1000), + }); + console.info(response.getTextContent()); + } catch (err) { + if (err instanceof AbortError) { + console.log("Aborted", { err }); + } + } +} + +async function minimaxStructure() { + const response = await llm.createStructure({ + schema: z.object({ + answer: z.string({ description: "your final answer" }), + }), + messages: [new UserMessage("How many islands make up the country of Cape Verde?")], + }); + console.info(response.object); +} + +async function minimaxToolCalling() { + const userMessage = new UserMessage( + `What is the current weather in Boston? Current date is ${new Date().toISOString().split("T")[0]}.`, + ); + const weatherTool = new OpenMeteoTool({ retryOptions: { maxRetries: 3 } }); + const response = await llm.create({ + messages: [userMessage], + tools: [weatherTool], + }); + const toolCallMsg = response.getToolCalls()[0]; + console.debug(JSON.stringify(toolCallMsg)); + const toolResponse = await weatherTool.run(toolCallMsg.input as any); + const toolResponseMsg = new ToolMessage({ + type: "tool-result", + output: { type: "text", value: toolResponse.getTextContent() }, + toolName: toolCallMsg.toolName, + toolCallId: toolCallMsg.toolCallId, + }); + console.info(toolResponseMsg.toPlain()); + const finalResponse = await llm.create({ + messages: [userMessage, ...response.messages, toolResponseMsg], + tools: [], + }); + console.info(finalResponse.getTextContent()); +} + +async function minimaxDebug() { + // Log every request + llm.emitter.match("*", (value, event) => + console.debug( + `Time: ${event.createdAt.toISOString()}`, + `Event: ${event.name}`, + `Data: ${JSON.stringify(value)}`, + ), + ); + + const response = await llm.create({ + messages: [new UserMessage("Hello world!")], + }); + console.info(response.messages[0].toPlain()); +} + +console.info("minimaxFromName".padStart(25, "*")); +await minimaxFromName(); +console.info("minimaxSync".padStart(25, "*")); +await minimaxSync(); +console.info("minimaxStream".padStart(25, "*")); +await minimaxStream(); +console.info("minimaxAbort".padStart(25, "*")); +await minimaxAbort(); +console.info("minimaxStructure".padStart(25, "*")); +await minimaxStructure(); +console.info("minimaxToolCalling".padStart(25, "*")); +await minimaxToolCalling(); +console.info("minimaxDebug".padStart(25, "*")); +await minimaxDebug(); diff --git a/typescript/src/adapters/minimax/backend/chat.ts b/typescript/src/adapters/minimax/backend/chat.ts new file mode 100644 index 000000000..0c0d992f3 --- /dev/null +++ b/typescript/src/adapters/minimax/backend/chat.ts @@ -0,0 +1,29 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { OpenAIProvider } from "@ai-sdk/openai"; +import { MiniMaxClient, MiniMaxClientSettings } from "@/adapters/minimax/backend/client.js"; +import { VercelChatModel } from "@/adapters/vercel/backend/chat.js"; +import { getEnv } from "@/internals/env.js"; +import { ChatModelParameters } from "@/backend/chat.js"; + +type MiniMaxParameters = Parameters; +export type MiniMaxChatModelId = NonNullable; + +export class MiniMaxChatModel extends VercelChatModel { + constructor( + modelId: MiniMaxChatModelId = getEnv("MINIMAX_CHAT_MODEL", "MiniMax-M2.7"), + parameters: ChatModelParameters = {}, + client?: MiniMaxClient | MiniMaxClientSettings, + ) { + const model = MiniMaxClient.ensure(client).instance.chat(modelId); + super(model); + Object.assign(this.parameters, parameters ?? {}); + } + + static { + this.register(); + } +} diff --git a/typescript/src/adapters/minimax/backend/client.ts b/typescript/src/adapters/minimax/backend/client.ts new file mode 100644 index 000000000..b058b7a76 --- /dev/null +++ b/typescript/src/adapters/minimax/backend/client.ts @@ -0,0 +1,28 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { createOpenAI, OpenAIProvider, OpenAIProviderSettings } from "@ai-sdk/openai"; +import { getEnv } from "@/internals/env.js"; +import { BackendClient } from "@/backend/client.js"; +import { parseHeadersFromEnv, vercelFetcher } from "@/adapters/vercel/backend/utils.js"; + +const MINIMAX_API_BASE = "https://api.minimax.io/v1"; + +export type MiniMaxClientSettings = OpenAIProviderSettings; + +export class MiniMaxClient extends BackendClient { + protected create(): OpenAIProvider { + return createOpenAI({ + ...this.settings, + apiKey: this.settings?.apiKey || getEnv("MINIMAX_API_KEY"), + baseURL: this.settings?.baseURL || getEnv("MINIMAX_API_BASE", MINIMAX_API_BASE), + headers: { + ...parseHeadersFromEnv("MINIMAX_API_HEADERS"), + ...this.settings?.headers, + }, + fetch: vercelFetcher(this.settings?.fetch), + }); + } +} diff --git a/typescript/src/backend/constants.ts b/typescript/src/backend/constants.ts index eab8f0a43..3954d1401 100644 --- a/typescript/src/backend/constants.ts +++ b/typescript/src/backend/constants.ts @@ -34,6 +34,11 @@ export const BackendProviders = { module: "anthropic", aliases: [] as string[], }, + MiniMax: { + name: "MiniMax", + module: "minimax", + aliases: ["minimax"] as string[], + }, } as const; export type ProviderName = (typeof BackendProviders)[keyof typeof BackendProviders]["module"]; diff --git a/typescript/tests/e2e/adapters/minimax.test.ts b/typescript/tests/e2e/adapters/minimax.test.ts new file mode 100644 index 000000000..8035210db --- /dev/null +++ b/typescript/tests/e2e/adapters/minimax.test.ts @@ -0,0 +1,96 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import { BackendProviders } from "@/backend/constants.js"; +import { MiniMaxChatModel } from "@/adapters/minimax/backend/chat.js"; +import { MiniMaxClient } from "@/adapters/minimax/backend/client.js"; + +describe("MiniMax Provider Registration", () => { + it("should be registered in BackendProviders", () => { + expect(BackendProviders.MiniMax).toBeDefined(); + expect(BackendProviders.MiniMax.name).toBe("MiniMax"); + expect(BackendProviders.MiniMax.module).toBe("minimax"); + expect(BackendProviders.MiniMax.aliases).toContain("minimax"); + }); +}); + +describe("MiniMaxClient", () => { + const originalEnv = process.env; + + beforeEach(() => { + process.env = { ...originalEnv }; + }); + + afterEach(() => { + process.env = originalEnv; + }); + + it("should create client with explicit settings", () => { + const client = new MiniMaxClient({ + apiKey: "test-key", + baseURL: "https://api.minimax.io/v1", + }); + expect(client).toBeDefined(); + expect(client.instance).toBeDefined(); + }); + + it("should create client from env vars", () => { + process.env.MINIMAX_API_KEY = "test-key-from-env"; + const client = new MiniMaxClient({}); + expect(client).toBeDefined(); + expect(client.instance).toBeDefined(); + }); +}); + +describe("MiniMaxChatModel", () => { + const originalEnv = process.env; + + beforeEach(() => { + process.env = { ...originalEnv }; + process.env.MINIMAX_API_KEY = "test-api-key"; + }); + + afterEach(() => { + process.env = originalEnv; + }); + + it("should instantiate with default model", () => { + const model = new MiniMaxChatModel(); + expect(model).toBeInstanceOf(MiniMaxChatModel); + expect(model.modelId).toBe("MiniMax-M2.7"); + }); + + it("should instantiate with custom model id", () => { + const model = new MiniMaxChatModel("MiniMax-M2.5"); + expect(model).toBeInstanceOf(MiniMaxChatModel); + expect(model.modelId).toBe("MiniMax-M2.5"); + }); + + it("should accept highspeed model", () => { + const model = new MiniMaxChatModel("MiniMax-M2.7-highspeed"); + expect(model).toBeInstanceOf(MiniMaxChatModel); + expect(model.modelId).toBe("MiniMax-M2.7-highspeed"); + }); + + it("should use env var for model id", () => { + process.env.MINIMAX_CHAT_MODEL = "MiniMax-M2.5-highspeed"; + const model = new MiniMaxChatModel(); + expect(model.modelId).toBe("MiniMax-M2.5-highspeed"); + }); + + it("should accept custom parameters", () => { + const model = new MiniMaxChatModel("MiniMax-M2.7", { temperature: 0.5 }); + expect(model).toBeInstanceOf(MiniMaxChatModel); + }); + + it("should accept custom client settings", () => { + const model = new MiniMaxChatModel("MiniMax-M2.7", {}, { + apiKey: "custom-key", + baseURL: "https://proxy.example.com/v1", + }); + expect(model).toBeInstanceOf(MiniMaxChatModel); + }); +}); From e6a9f11f29212f9b7e64ddfb5519340ab3728db5 Mon Sep 17 00:00:00 2001 From: Octopus Date: Mon, 6 Apr 2026 18:00:06 +0800 Subject: [PATCH 2/5] fix: skip minimax example tests when MINIMAX_API_KEY is not set Add conditional exclusion for minimax provider examples in both Python and TypeScript test suites, consistent with how other providers handle missing credentials. Signed-off-by: octo-patch --- python/tests/examples/test_examples.py | 1 + typescript/tests/examples/examples.test.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/python/tests/examples/test_examples.py b/python/tests/examples/test_examples.py index d307576be..abb72f383 100644 --- a/python/tests/examples/test_examples.py +++ b/python/tests/examples/test_examples.py @@ -35,6 +35,7 @@ "backend/providers/langchain_compatible.py", "backend/providers/qwen.py" if os.getenv("DASHSCOPE_API_KEY") is None else None, "backend/providers/deepseek.py" if os.getenv("DEEPSEEK_CHAT_MODEL") is None else None, + "backend/providers/minimax.py" if os.getenv("MINIMAX_API_KEY") is None else None, "tools/mcp_agent.py" if os.getenv("SLACK_BOT_TOKEN") is None else None, "tools/mcp_tool_creation.py" if os.getenv("SLACK_BOT_TOKEN") is None else None, "tools/mcp_slack_agent.py" if os.getenv("SLACK_BOT_TOKEN") is None else None, diff --git a/typescript/tests/examples/examples.test.ts b/typescript/tests/examples/examples.test.ts index 47997f01c..e9b997f24 100644 --- a/typescript/tests/examples/examples.test.ts +++ b/typescript/tests/examples/examples.test.ts @@ -58,6 +58,7 @@ const exclude: string[] = [ !getEnv("GOOGLE_APPLICATION_CREDENTIALS") && ["examples/backend/providers/vertexai.ts"], !getEnv("ANTHROPIC_API_KEY") && ["examples/backend/providers/anthropic.ts"], !getEnv("XAI_API_KEY") && ["examples/backend/providers/xai.ts"], + !getEnv("MINIMAX_API_KEY") && ["examples/backend/providers/minimax.ts"], "examples/tools/custom/extending.ts", // DDG problems ] .filter(isTruthy) From 857ddeaa43bb5f4d74a26a55a98e06b063cea9fb Mon Sep 17 00:00:00 2001 From: octo-patch Date: Sun, 7 Jun 2026 14:52:21 +0800 Subject: [PATCH 3/5] feat: upgrade MiniMax default model to M3 - Set MiniMax-M3 as the default model for Python and TypeScript adapters - Keep MiniMax-M2.7 and MiniMax-M2.7-highspeed as alternatives - Remove older models (MiniMax-M2.5, MiniMax-M2.5-highspeed) - Update related unit/e2e tests and examples Signed-off-by: octo-patch --- .../adapters/minimax/backend/chat.py | 8 ++++---- python/examples/backend/providers/minimax.py | 12 ++++++------ .../adapters/minimax/test_minimax_chat.py | 18 +++++++++--------- .../minimax/test_minimax_integration.py | 2 +- .../examples/backend/providers/minimax.ts | 4 ++-- .../src/adapters/minimax/backend/chat.ts | 2 +- typescript/tests/e2e/adapters/minimax.test.ts | 14 +++++++------- 7 files changed, 30 insertions(+), 30 deletions(-) diff --git a/python/beeai_framework/adapters/minimax/backend/chat.py b/python/beeai_framework/adapters/minimax/backend/chat.py index 91b561c8a..bb6eb9295 100644 --- a/python/beeai_framework/adapters/minimax/backend/chat.py +++ b/python/beeai_framework/adapters/minimax/backend/chat.py @@ -21,8 +21,8 @@ class MiniMaxChatModel(LiteLLMChatModel): MiniMax provides an OpenAI-compatible API. This adapter routes requests through LiteLLM's OpenAI provider with the MiniMax base URL. - Available models include MiniMax-M2.7, MiniMax-M2.7-highspeed, - MiniMax-M2.5, and MiniMax-M2.5-highspeed. + Available models include MiniMax-M3 (default), MiniMax-M2.7, + and MiniMax-M2.7-highspeed. """ @property @@ -44,14 +44,14 @@ def __init__( Args: model_id: The ID of the MiniMax model to use. If not provided, it falls back to the MINIMAX_CHAT_MODEL environment variable, - and then defaults to 'MiniMax-M2.7'. + and then defaults to 'MiniMax-M3'. api_key: The MiniMax API key. Falls back to MINIMAX_API_KEY env var. base_url: The MiniMax API base URL. Falls back to MINIMAX_API_BASE env var, then defaults to 'https://api.minimax.io/v1'. **kwargs: Additional settings to configure the provider. """ super().__init__( - model_id if model_id else os.getenv("MINIMAX_CHAT_MODEL", "MiniMax-M2.7"), + model_id if model_id else os.getenv("MINIMAX_CHAT_MODEL", "MiniMax-M3"), provider_id="openai", **kwargs, ) diff --git a/python/examples/backend/providers/minimax.py b/python/examples/backend/providers/minimax.py index 3de712045..72b7bc24b 100644 --- a/python/examples/backend/providers/minimax.py +++ b/python/examples/backend/providers/minimax.py @@ -16,28 +16,28 @@ async def minimax_from_name() -> None: - llm = ChatModel.from_name("minimax:MiniMax-M2.7") + llm = ChatModel.from_name("minimax:MiniMax-M3") user_message = UserMessage("what states are part of New England?") response = await llm.run([user_message]) print(response.get_text_content()) async def minimax_sync() -> None: - llm = MiniMaxChatModel("MiniMax-M2.7") + llm = MiniMaxChatModel("MiniMax-M3") user_message = UserMessage("what is the capital of Massachusetts?") response = await llm.run([user_message]) print(response.get_text_content()) async def minimax_stream() -> None: - llm = MiniMaxChatModel("MiniMax-M2.7") + llm = MiniMaxChatModel("MiniMax-M3") user_message = UserMessage("How many islands make up the country of Cape Verde?") response = await llm.run([user_message], stream=True) print(response.get_text_content()) async def minimax_stream_abort() -> None: - llm = MiniMaxChatModel("MiniMax-M2.7") + llm = MiniMaxChatModel("MiniMax-M3") user_message = UserMessage("What is the smallest of the Cape Verde islands?") try: @@ -55,14 +55,14 @@ async def minimax_structure() -> None: class TestSchema(BaseModel): answer: str = Field(description="your final answer") - llm = MiniMaxChatModel("MiniMax-M2.7") + llm = MiniMaxChatModel("MiniMax-M3") user_message = UserMessage("How many islands make up the country of Cape Verde?") response = await llm.run([user_message], response_format=TestSchema) print(response.output_structured) async def minimax_stream_parser() -> None: - llm = MiniMaxChatModel("MiniMax-M2.7") + llm = MiniMaxChatModel("MiniMax-M3") parser = LinePrefixParser( nodes={ diff --git a/python/tests/adapters/minimax/test_minimax_chat.py b/python/tests/adapters/minimax/test_minimax_chat.py index 12c7c5e55..0d25d2abd 100644 --- a/python/tests/adapters/minimax/test_minimax_chat.py +++ b/python/tests/adapters/minimax/test_minimax_chat.py @@ -34,12 +34,12 @@ class TestMiniMaxChatModelInit: @patch.dict(os.environ, {"MINIMAX_API_KEY": "test-key-123"}) def test_default_model_id(self) -> None: model = MiniMaxChatModel() - assert model.model_id == "MiniMax-M2.7" + assert model.model_id == "MiniMax-M3" @patch.dict(os.environ, {"MINIMAX_API_KEY": "test-key-123"}) def test_custom_model_id(self) -> None: - model = MiniMaxChatModel("MiniMax-M2.5") - assert model.model_id == "MiniMax-M2.5" + model = MiniMaxChatModel("MiniMax-M2.7") + assert model.model_id == "MiniMax-M2.7" @patch.dict(os.environ, {"MINIMAX_API_KEY": "test-key-123"}) def test_highspeed_model_id(self) -> None: @@ -48,11 +48,11 @@ def test_highspeed_model_id(self) -> None: @patch.dict( os.environ, - {"MINIMAX_API_KEY": "test-key-123", "MINIMAX_CHAT_MODEL": "MiniMax-M2.5-highspeed"}, + {"MINIMAX_API_KEY": "test-key-123", "MINIMAX_CHAT_MODEL": "MiniMax-M2.7-highspeed"}, ) def test_model_from_env(self) -> None: model = MiniMaxChatModel() - assert model.model_id == "MiniMax-M2.5-highspeed" + assert model.model_id == "MiniMax-M2.7-highspeed" @patch.dict(os.environ, {"MINIMAX_API_KEY": "test-key-123"}) def test_provider_id(self) -> None: @@ -100,12 +100,12 @@ class TestMiniMaxModelLoading: @patch.dict(os.environ, {"MINIMAX_API_KEY": "test-key-123"}) def test_load_from_name(self) -> None: - model = ChatModel.from_name("minimax:MiniMax-M2.7") + model = ChatModel.from_name("minimax:MiniMax-M3") assert isinstance(model, MiniMaxChatModel) - assert model.model_id == "MiniMax-M2.7" + assert model.model_id == "MiniMax-M3" @patch.dict(os.environ, {"MINIMAX_API_KEY": "test-key-123"}) def test_load_from_alias(self) -> None: - model = ChatModel.from_name("minimax:MiniMax-M2.5") + model = ChatModel.from_name("minimax:MiniMax-M2.7") assert isinstance(model, MiniMaxChatModel) - assert model.model_id == "MiniMax-M2.5" + assert model.model_id == "MiniMax-M2.7" diff --git a/python/tests/adapters/minimax/test_minimax_integration.py b/python/tests/adapters/minimax/test_minimax_integration.py index 34d9544c0..0b4f8f94a 100644 --- a/python/tests/adapters/minimax/test_minimax_integration.py +++ b/python/tests/adapters/minimax/test_minimax_integration.py @@ -22,7 +22,7 @@ @pytest.fixture def chat_model() -> MiniMaxChatModel: - return MiniMaxChatModel("MiniMax-M2.7") + return MiniMaxChatModel("MiniMax-M3") @pytest.fixture diff --git a/typescript/examples/backend/providers/minimax.ts b/typescript/examples/backend/providers/minimax.ts index 6c84d8f4b..c412a8266 100644 --- a/typescript/examples/backend/providers/minimax.ts +++ b/typescript/examples/backend/providers/minimax.ts @@ -8,7 +8,7 @@ import { z } from "zod"; import { OpenMeteoTool } from "beeai-framework/tools/weather/openMeteo"; const llm = new MiniMaxChatModel( - "MiniMax-M2.7", + "MiniMax-M3", // {}, // { // apiKey: "MINIMAX_API_KEY", @@ -25,7 +25,7 @@ llm.config({ }); async function minimaxFromName() { - const minimaxLLM = await ChatModel.fromName("minimax:MiniMax-M2.7"); + const minimaxLLM = await ChatModel.fromName("minimax:MiniMax-M3"); const response = await minimaxLLM.create({ messages: [new UserMessage("what states are part of New England?")], }); diff --git a/typescript/src/adapters/minimax/backend/chat.ts b/typescript/src/adapters/minimax/backend/chat.ts index 0c0d992f3..c9303cc65 100644 --- a/typescript/src/adapters/minimax/backend/chat.ts +++ b/typescript/src/adapters/minimax/backend/chat.ts @@ -14,7 +14,7 @@ export type MiniMaxChatModelId = NonNullable; export class MiniMaxChatModel extends VercelChatModel { constructor( - modelId: MiniMaxChatModelId = getEnv("MINIMAX_CHAT_MODEL", "MiniMax-M2.7"), + modelId: MiniMaxChatModelId = getEnv("MINIMAX_CHAT_MODEL", "MiniMax-M3"), parameters: ChatModelParameters = {}, client?: MiniMaxClient | MiniMaxClientSettings, ) { diff --git a/typescript/tests/e2e/adapters/minimax.test.ts b/typescript/tests/e2e/adapters/minimax.test.ts index 8035210db..006f4eae8 100644 --- a/typescript/tests/e2e/adapters/minimax.test.ts +++ b/typescript/tests/e2e/adapters/minimax.test.ts @@ -60,13 +60,13 @@ describe("MiniMaxChatModel", () => { it("should instantiate with default model", () => { const model = new MiniMaxChatModel(); expect(model).toBeInstanceOf(MiniMaxChatModel); - expect(model.modelId).toBe("MiniMax-M2.7"); + expect(model.modelId).toBe("MiniMax-M3"); }); it("should instantiate with custom model id", () => { - const model = new MiniMaxChatModel("MiniMax-M2.5"); + const model = new MiniMaxChatModel("MiniMax-M2.7"); expect(model).toBeInstanceOf(MiniMaxChatModel); - expect(model.modelId).toBe("MiniMax-M2.5"); + expect(model.modelId).toBe("MiniMax-M2.7"); }); it("should accept highspeed model", () => { @@ -76,18 +76,18 @@ describe("MiniMaxChatModel", () => { }); it("should use env var for model id", () => { - process.env.MINIMAX_CHAT_MODEL = "MiniMax-M2.5-highspeed"; + process.env.MINIMAX_CHAT_MODEL = "MiniMax-M2.7-highspeed"; const model = new MiniMaxChatModel(); - expect(model.modelId).toBe("MiniMax-M2.5-highspeed"); + expect(model.modelId).toBe("MiniMax-M2.7-highspeed"); }); it("should accept custom parameters", () => { - const model = new MiniMaxChatModel("MiniMax-M2.7", { temperature: 0.5 }); + const model = new MiniMaxChatModel("MiniMax-M3", { temperature: 0.5 }); expect(model).toBeInstanceOf(MiniMaxChatModel); }); it("should accept custom client settings", () => { - const model = new MiniMaxChatModel("MiniMax-M2.7", {}, { + const model = new MiniMaxChatModel("MiniMax-M3", {}, { apiKey: "custom-key", baseURL: "https://proxy.example.com/v1", }); From 0b16c5d2308eab2bc196a3d8e7e6bd5999e2ca5e Mon Sep 17 00:00:00 2001 From: octo-patch Date: Tue, 16 Jun 2026 13:25:21 +0800 Subject: [PATCH 4/5] docs: add MiniMax provider entry to new Astro docs After the Mintlify -> Astro Starlight migration (#1462), the provider table in the new docs location was missing the MiniMax row. Add it so the documentation continues to advertise MiniMax as a supported chat provider in the new docs site. Signed-off-by: octo-patch --- docs/src/content/docs/modules/backend.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/src/content/docs/modules/backend.mdx b/docs/src/content/docs/modules/backend.mdx index d13026766..32808b980 100644 --- a/docs/src/content/docs/modules/backend.mdx +++ b/docs/src/content/docs/modules/backend.mdx @@ -37,6 +37,7 @@ The following table depicts supported providers. Each provider requires specific | Google Gemini | ✅ | ✅ | GEMINI_CHAT_MODEL
**GEMINI_API_KEY**
GEMINI_API_HEADERS | | MistralAI | ✅ | ✅ | MISTRALAI_CHAT_MODEL
MISTRALAI_EMBEDDING_MODEL
**MISTRALAI_API_KEY**
MISTRALAI_API_BASE | | Transformers | ✅ | ✅ | TRANSFORMERS_CHAT_MODEL
HF_TOKEN| +| MiniMax | ✅ | ❌ | MINIMAX_CHAT_MODEL
**MINIMAX_API_KEY**
MINIMAX_API_BASE
MINIMAX_API_HEADERS | If you don't see your provider raise an issue [here](https://github.com/i-am-bee/beeai-framework/issues). From 85120e94482c59b12050c1b9eaf561db26adb9f6 Mon Sep 17 00:00:00 2001 From: octo-patch Date: Tue, 16 Jun 2026 15:15:23 +0800 Subject: [PATCH 5/5] fix: satisfy lint checks for minimax provider Sort imports in the Python chat adapter, use a raw string for the pytest.raises regex (RUF043), and drop an unused vitest import plus reformat the e2e test so ruff and the TypeScript lint/prettier checks pass. Signed-off-by: octo-patch --- .../adapters/minimax/backend/chat.py | 1 + python/tests/adapters/minimax/test_minimax_chat.py | 2 +- typescript/tests/e2e/adapters/minimax.test.ts | 14 +++++++++----- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/python/beeai_framework/adapters/minimax/backend/chat.py b/python/beeai_framework/adapters/minimax/backend/chat.py index bb6eb9295..897f66ab3 100644 --- a/python/beeai_framework/adapters/minimax/backend/chat.py +++ b/python/beeai_framework/adapters/minimax/backend/chat.py @@ -2,6 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 import os + from typing_extensions import Unpack from beeai_framework.adapters.litellm import LiteLLMChatModel, utils diff --git a/python/tests/adapters/minimax/test_minimax_chat.py b/python/tests/adapters/minimax/test_minimax_chat.py index 0d25d2abd..845478a2a 100644 --- a/python/tests/adapters/minimax/test_minimax_chat.py +++ b/python/tests/adapters/minimax/test_minimax_chat.py @@ -86,7 +86,7 @@ def test_missing_api_key_raises(self) -> None: with patch.dict(os.environ, {}, clear=True): # Remove any existing MINIMAX_API_KEY os.environ.pop("MINIMAX_API_KEY", None) - with pytest.raises(ValueError, match="api_key.*required"): + with pytest.raises(ValueError, match=r"api_key.*required"): MiniMaxChatModel() @patch.dict(os.environ, {"MINIMAX_API_KEY": "test-key-123"}) diff --git a/typescript/tests/e2e/adapters/minimax.test.ts b/typescript/tests/e2e/adapters/minimax.test.ts index 006f4eae8..33fcf6f54 100644 --- a/typescript/tests/e2e/adapters/minimax.test.ts +++ b/typescript/tests/e2e/adapters/minimax.test.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import { describe, it, expect, beforeEach, afterEach } from "vitest"; import { BackendProviders } from "@/backend/constants.js"; import { MiniMaxChatModel } from "@/adapters/minimax/backend/chat.js"; import { MiniMaxClient } from "@/adapters/minimax/backend/client.js"; @@ -87,10 +87,14 @@ describe("MiniMaxChatModel", () => { }); it("should accept custom client settings", () => { - const model = new MiniMaxChatModel("MiniMax-M3", {}, { - apiKey: "custom-key", - baseURL: "https://proxy.example.com/v1", - }); + const model = new MiniMaxChatModel( + "MiniMax-M3", + {}, + { + apiKey: "custom-key", + baseURL: "https://proxy.example.com/v1", + }, + ); expect(model).toBeInstanceOf(MiniMaxChatModel); }); });