diff --git a/docs/src/content/docs/modules/backend.mdx b/docs/src/content/docs/modules/backend.mdx
index fbd5ee0c9..675099d79 100644
--- a/docs/src/content/docs/modules/backend.mdx
+++ b/docs/src/content/docs/modules/backend.mdx
@@ -37,7 +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 |
+| MiniMax | ✅ | ❌ | MINIMAX_CHAT_MODEL
**MINIMAX_API_KEY**
MINIMAX_API_BASE
MINIMAX_API_REGION
MINIMAX_API_HEADERS |
If you don't see your provider raise an issue [here](https://github.com/i-am-bee/beeai-framework/issues).
@@ -49,6 +49,10 @@ or [TypeScript](https://github.com/i-am-bee/beeai-framework/blob/main/typescript
Google Gemini, MistralAI, and Transformers are supported in Python only. The Transformers chat model does not support tool calling.
+
+ MiniMax serves the same API from two regional gateways. Select one with `MINIMAX_API_REGION` (or the `region` option): `global` (default, `https://api.minimax.io/v1`) or `cn` (`https://api.minimaxi.com/v1`). An explicit `MINIMAX_API_BASE` / `base_url` always takes precedence, so you no longer have to look up and type the regional URL by hand.
+
+
---
### Backend initialization
diff --git a/python/beeai_framework/adapters/minimax/__init__.py b/python/beeai_framework/adapters/minimax/__init__.py
index 128f60bff..96dd29bbf 100644
--- a/python/beeai_framework/adapters/minimax/__init__.py
+++ b/python/beeai_framework/adapters/minimax/__init__.py
@@ -1,6 +1,16 @@
# Copyright 2025 © BeeAI a Series of LF Projects, LLC
# SPDX-License-Identifier: Apache-2.0
-from beeai_framework.adapters.minimax.backend.chat import MiniMaxChatModel
+from beeai_framework.adapters.minimax.backend.chat import (
+ MINIMAX_API_BASE,
+ MINIMAX_API_BASE_CN,
+ MiniMaxChatModel,
+ resolve_minimax_base_url,
+)
-__all__ = ["MiniMaxChatModel"]
+__all__ = [
+ "MINIMAX_API_BASE",
+ "MINIMAX_API_BASE_CN",
+ "MiniMaxChatModel",
+ "resolve_minimax_base_url",
+]
diff --git a/python/beeai_framework/adapters/minimax/backend/chat.py b/python/beeai_framework/adapters/minimax/backend/chat.py
index 897f66ab3..670a1d0f6 100644
--- a/python/beeai_framework/adapters/minimax/backend/chat.py
+++ b/python/beeai_framework/adapters/minimax/backend/chat.py
@@ -13,6 +13,37 @@
logger = Logger(__name__)
MINIMAX_API_BASE = "https://api.minimax.io/v1"
+MINIMAX_API_BASE_CN = "https://api.minimaxi.com/v1"
+
+# Region identifiers accepted by ``region`` / the MINIMAX_API_REGION env var,
+# mapped to the matching OpenAI-compatible base URL. MiniMax serves the same API
+# from two regional gateways; this mapping lets callers select one by name
+# instead of discovering and typing the base URL by hand.
+MINIMAX_REGION_BASE_URLS = {
+ "global": MINIMAX_API_BASE,
+ "global_en": MINIMAX_API_BASE,
+ "cn": MINIMAX_API_BASE_CN,
+ "cn_zh": MINIMAX_API_BASE_CN,
+}
+DEFAULT_MINIMAX_REGION = "global"
+
+
+def resolve_minimax_base_url(region: str | None) -> str:
+ """
+ Resolve a MiniMax region identifier to its OpenAI-compatible base URL.
+
+ An empty or missing region resolves to the global endpoint. Unknown
+ identifiers raise ``ValueError`` listing the supported regions.
+ """
+ normalized = (region or "").strip().lower()
+ if not normalized:
+ return MINIMAX_API_BASE
+ try:
+ return MINIMAX_REGION_BASE_URLS[normalized]
+ except KeyError:
+ raise ValueError(
+ f"Unknown MiniMax region '{region}'. Supported regions: {', '.join(sorted(MINIMAX_REGION_BASE_URLS))}."
+ ) from None
class MiniMaxChatModel(LiteLLMChatModel):
@@ -22,6 +53,12 @@ class MiniMaxChatModel(LiteLLMChatModel):
MiniMax provides an OpenAI-compatible API. This adapter routes requests
through LiteLLM's OpenAI provider with the MiniMax base URL.
+ MiniMax exposes the same API from two regional gateways: the global
+ endpoint (https://api.minimax.io/v1) and the CN endpoint
+ (https://api.minimaxi.com/v1). Select one with the ``region`` argument or
+ the MINIMAX_API_REGION environment variable, or override it entirely with
+ an explicit ``base_url`` / MINIMAX_API_BASE.
+
Available models include MiniMax-M3 (default), MiniMax-M2.7,
and MiniMax-M2.7-highspeed.
"""
@@ -37,6 +74,7 @@ def __init__(
*,
api_key: str | None = None,
base_url: str | None = None,
+ region: str | None = None,
**kwargs: Unpack[ChatModelKwargs],
) -> None:
"""
@@ -48,7 +86,13 @@ def __init__(
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'.
+ env var, then to the endpoint selected by ``region``, and finally
+ to the global endpoint 'https://api.minimax.io/v1'.
+ region: The MiniMax region whose endpoint is used when neither
+ ``base_url`` nor MINIMAX_API_BASE is set. Accepts 'global'
+ (alias 'global_en', https://api.minimax.io/v1) or 'cn'
+ (alias 'cn_zh', https://api.minimaxi.com/v1). Falls back to the
+ MINIMAX_API_REGION env var, then to the global endpoint.
**kwargs: Additional settings to configure the provider.
"""
super().__init__(
@@ -57,6 +101,7 @@ def __init__(
**kwargs,
)
+ region = region if region is not None else os.getenv("MINIMAX_API_REGION")
self._assert_setting_value("api_key", api_key, envs=["MINIMAX_API_KEY"])
self._assert_setting_value(
"base_url",
@@ -64,7 +109,7 @@ def __init__(
envs=["MINIMAX_API_BASE"],
aliases=["api_base"],
allow_empty=True,
- fallback=MINIMAX_API_BASE,
+ fallback=resolve_minimax_base_url(region),
)
self._settings["extra_headers"] = utils.parse_extra_headers(
self._settings.get("extra_headers"), os.getenv("MINIMAX_API_HEADERS")
diff --git a/python/examples/backend/providers/minimax.py b/python/examples/backend/providers/minimax.py
index 72b7bc24b..9aad9c75a 100644
--- a/python/examples/backend/providers/minimax.py
+++ b/python/examples/backend/providers/minimax.py
@@ -23,6 +23,10 @@ async def minimax_from_name() -> None:
async def minimax_sync() -> None:
+ # Select a regional gateway by name instead of hard-coding the URL:
+ # region="global" -> https://api.minimax.io/v1 (default)
+ # region="cn" -> https://api.minimaxi.com/v1
+ # An explicit base_url / MINIMAX_API_BASE still takes precedence.
llm = MiniMaxChatModel("MiniMax-M3")
user_message = UserMessage("what is the capital of Massachusetts?")
response = await llm.run([user_message])
diff --git a/python/tests/adapters/minimax/test_minimax_chat.py b/python/tests/adapters/minimax/test_minimax_chat.py
index 845478a2a..475fad1d7 100644
--- a/python/tests/adapters/minimax/test_minimax_chat.py
+++ b/python/tests/adapters/minimax/test_minimax_chat.py
@@ -6,7 +6,12 @@
import pytest
-from beeai_framework.adapters.minimax.backend.chat import MINIMAX_API_BASE, MiniMaxChatModel
+from beeai_framework.adapters.minimax.backend.chat import (
+ MINIMAX_API_BASE,
+ MINIMAX_API_BASE_CN,
+ MiniMaxChatModel,
+ resolve_minimax_base_url,
+)
from beeai_framework.backend.chat import ChatModel
from beeai_framework.backend.constants import BackendProviders
@@ -109,3 +114,74 @@ def test_load_from_alias(self) -> None:
model = ChatModel.from_name("minimax:MiniMax-M2.7")
assert isinstance(model, MiniMaxChatModel)
assert model.model_id == "MiniMax-M2.7"
+
+
+class TestMiniMaxRegionSelection:
+ """Test regional (global / CN) endpoint selection."""
+
+ def test_resolve_global_variants(self) -> None:
+ assert resolve_minimax_base_url("global") == MINIMAX_API_BASE
+ assert resolve_minimax_base_url("global_en") == MINIMAX_API_BASE
+
+ def test_resolve_cn_variants(self) -> None:
+ assert resolve_minimax_base_url("cn") == MINIMAX_API_BASE_CN
+ assert resolve_minimax_base_url("cn_zh") == MINIMAX_API_BASE_CN
+
+ def test_resolve_is_case_insensitive_and_trimmed(self) -> None:
+ assert resolve_minimax_base_url(" CN ") == MINIMAX_API_BASE_CN
+
+ def test_resolve_empty_defaults_to_global(self) -> None:
+ assert resolve_minimax_base_url(None) == MINIMAX_API_BASE
+ assert resolve_minimax_base_url("") == MINIMAX_API_BASE
+
+ def test_resolve_unknown_region_raises(self) -> None:
+ with pytest.raises(ValueError, match=r"Unknown MiniMax region"):
+ resolve_minimax_base_url("mars")
+
+ def test_endpoints_differ(self) -> None:
+ assert MINIMAX_API_BASE == "https://api.minimax.io/v1"
+ assert MINIMAX_API_BASE_CN == "https://api.minimaxi.com/v1"
+ assert MINIMAX_API_BASE != MINIMAX_API_BASE_CN
+
+ @patch.dict(os.environ, {"MINIMAX_API_KEY": "test-key-123"})
+ def test_region_param_selects_cn(self) -> None:
+ model = MiniMaxChatModel(region="cn")
+ assert model._settings.get("base_url") == MINIMAX_API_BASE_CN
+
+ @patch.dict(os.environ, {"MINIMAX_API_KEY": "test-key-123"})
+ def test_region_param_selects_global(self) -> None:
+ model = MiniMaxChatModel(region="global")
+ assert model._settings.get("base_url") == MINIMAX_API_BASE
+
+ @patch.dict(
+ os.environ,
+ {"MINIMAX_API_KEY": "test-key-123", "MINIMAX_API_REGION": "cn_zh"},
+ )
+ def test_region_from_env_selects_cn(self) -> None:
+ model = MiniMaxChatModel()
+ assert model._settings.get("base_url") == MINIMAX_API_BASE_CN
+
+ @patch.dict(
+ os.environ,
+ {"MINIMAX_API_KEY": "test-key-123", "MINIMAX_API_REGION": "cn"},
+ )
+ def test_explicit_base_url_overrides_region(self) -> None:
+ model = MiniMaxChatModel(base_url="https://proxy.example.com/v1", region="cn")
+ assert model._settings.get("base_url") == "https://proxy.example.com/v1"
+
+ @patch.dict(
+ os.environ,
+ {
+ "MINIMAX_API_KEY": "test-key-123",
+ "MINIMAX_API_BASE": "https://api.minimax.io/v1",
+ "MINIMAX_API_REGION": "cn",
+ },
+ )
+ def test_api_base_env_overrides_region(self) -> None:
+ model = MiniMaxChatModel()
+ assert model._settings.get("base_url") == MINIMAX_API_BASE
+
+ @patch.dict(os.environ, {"MINIMAX_API_KEY": "test-key-123"})
+ def test_default_without_region_is_global(self) -> None:
+ model = MiniMaxChatModel()
+ assert model._settings.get("base_url") == MINIMAX_API_BASE
diff --git a/typescript/examples/backend/providers/minimax.ts b/typescript/examples/backend/providers/minimax.ts
index c412a8266..89290bd90 100644
--- a/typescript/examples/backend/providers/minimax.ts
+++ b/typescript/examples/backend/providers/minimax.ts
@@ -12,7 +12,12 @@ const llm = new MiniMaxChatModel(
// {},
// {
// apiKey: "MINIMAX_API_KEY",
- // baseURL: "https://api.minimax.io/v1",
+ // // Pick a regional gateway by name instead of hard-coding the URL:
+ // // "global" -> https://api.minimax.io/v1 (default)
+ // // "cn" -> https://api.minimaxi.com/v1
+ // region: "global",
+ // // ...or override the base URL directly (takes precedence over region):
+ // // baseURL: "https://api.minimax.io/v1",
// },
);
diff --git a/typescript/src/adapters/minimax/backend/client.ts b/typescript/src/adapters/minimax/backend/client.ts
index b058b7a76..7aed3f2ad 100644
--- a/typescript/src/adapters/minimax/backend/client.ts
+++ b/typescript/src/adapters/minimax/backend/client.ts
@@ -8,21 +8,70 @@ 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 const MINIMAX_API_BASE = "https://api.minimax.io/v1";
+export const MINIMAX_API_BASE_CN = "https://api.minimaxi.com/v1";
-export type MiniMaxClientSettings = OpenAIProviderSettings;
+/**
+ * Region identifiers accepted by `region` / the MINIMAX_API_REGION env var,
+ * mapped to the matching OpenAI-compatible base URL. MiniMax serves the same
+ * API from two regional gateways; this mapping lets callers select one by name
+ * instead of discovering and typing the base URL by hand.
+ */
+export const MINIMAX_REGION_BASE_URLS = {
+ global: MINIMAX_API_BASE,
+ global_en: MINIMAX_API_BASE,
+ cn: MINIMAX_API_BASE_CN,
+ cn_zh: MINIMAX_API_BASE_CN,
+} as const;
+
+export type MiniMaxRegion = keyof typeof MINIMAX_REGION_BASE_URLS;
+
+/**
+ * Resolve a MiniMax region identifier to its OpenAI-compatible base URL.
+ *
+ * An empty or missing region resolves to the global endpoint. Unknown
+ * identifiers throw an error listing the supported regions.
+ */
+export function resolveMiniMaxBaseURL(region?: string): string {
+ const normalized = region?.trim().toLowerCase();
+ if (!normalized) {
+ return MINIMAX_API_BASE;
+ }
+ const baseURL = (MINIMAX_REGION_BASE_URLS as Record)[normalized];
+ if (!baseURL) {
+ throw new Error(
+ `Unknown MiniMax region "${region}". Supported regions: ${Object.keys(
+ MINIMAX_REGION_BASE_URLS,
+ ).join(", ")}.`,
+ );
+ }
+ return baseURL;
+}
+
+export interface MiniMaxClientSettings extends OpenAIProviderSettings {
+ /**
+ * Region whose endpoint is used when neither `baseURL` nor MINIMAX_API_BASE
+ * is set. Falls back to the MINIMAX_API_REGION env var, then to the global
+ * endpoint.
+ */
+ region?: MiniMaxRegion;
+}
export class MiniMaxClient extends BackendClient {
protected create(): OpenAIProvider {
+ const { region, ...settings } = this.settings ?? {};
return createOpenAI({
- ...this.settings,
- apiKey: this.settings?.apiKey || getEnv("MINIMAX_API_KEY"),
- baseURL: this.settings?.baseURL || getEnv("MINIMAX_API_BASE", MINIMAX_API_BASE),
+ ...settings,
+ apiKey: settings.apiKey || getEnv("MINIMAX_API_KEY"),
+ baseURL:
+ settings.baseURL ||
+ getEnv("MINIMAX_API_BASE") ||
+ resolveMiniMaxBaseURL(region ?? getEnv("MINIMAX_API_REGION")),
headers: {
...parseHeadersFromEnv("MINIMAX_API_HEADERS"),
- ...this.settings?.headers,
+ ...settings.headers,
},
- fetch: vercelFetcher(this.settings?.fetch),
+ fetch: vercelFetcher(settings.fetch),
});
}
}
diff --git a/typescript/tests/e2e/adapters/minimax.test.ts b/typescript/tests/e2e/adapters/minimax.test.ts
index 33fcf6f54..15d7a3f2d 100644
--- a/typescript/tests/e2e/adapters/minimax.test.ts
+++ b/typescript/tests/e2e/adapters/minimax.test.ts
@@ -6,7 +6,12 @@
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";
+import {
+ MiniMaxClient,
+ MINIMAX_API_BASE,
+ MINIMAX_API_BASE_CN,
+ resolveMiniMaxBaseURL,
+} from "@/adapters/minimax/backend/client.js";
describe("MiniMax Provider Registration", () => {
it("should be registered in BackendProviders", () => {
@@ -98,3 +103,40 @@ describe("MiniMaxChatModel", () => {
expect(model).toBeInstanceOf(MiniMaxChatModel);
});
});
+
+describe("MiniMax regional endpoints", () => {
+ it("should expose distinct global and CN endpoints", () => {
+ expect(MINIMAX_API_BASE).toBe("https://api.minimax.io/v1");
+ expect(MINIMAX_API_BASE_CN).toBe("https://api.minimaxi.com/v1");
+ expect(MINIMAX_API_BASE).not.toBe(MINIMAX_API_BASE_CN);
+ });
+
+ it("should resolve global region variants", () => {
+ expect(resolveMiniMaxBaseURL("global")).toBe(MINIMAX_API_BASE);
+ expect(resolveMiniMaxBaseURL("global_en")).toBe(MINIMAX_API_BASE);
+ });
+
+ it("should resolve CN region variants", () => {
+ expect(resolveMiniMaxBaseURL("cn")).toBe(MINIMAX_API_BASE_CN);
+ expect(resolveMiniMaxBaseURL("cn_zh")).toBe(MINIMAX_API_BASE_CN);
+ });
+
+ it("should be case-insensitive and trim whitespace", () => {
+ expect(resolveMiniMaxBaseURL(" CN ")).toBe(MINIMAX_API_BASE_CN);
+ });
+
+ it("should default to the global endpoint when region is missing", () => {
+ expect(resolveMiniMaxBaseURL()).toBe(MINIMAX_API_BASE);
+ expect(resolveMiniMaxBaseURL("")).toBe(MINIMAX_API_BASE);
+ });
+
+ it("should throw for an unknown region", () => {
+ expect(() => resolveMiniMaxBaseURL("mars")).toThrowError(/Unknown MiniMax region/);
+ });
+
+ it("should build a client for the CN region without throwing", () => {
+ const client = new MiniMaxClient({ apiKey: "test-key", region: "cn" });
+ expect(client).toBeDefined();
+ expect(client.instance).toBeDefined();
+ });
+});