fix: auto-detect China region for MiniMax API endpoint selection
This commit is contained in:
parent
da71eaebd2
commit
b163440f6f
@ -145,13 +145,50 @@ Use the interactive config wizard to set MiniMax without editing JSON:
|
||||
|
||||
## Configuration options
|
||||
|
||||
- `models.providers.minimax.baseUrl`: prefer `https://api.minimax.io/anthropic` (Anthropic-compatible); `https://api.minimax.io/v1` is optional for OpenAI-compatible payloads.
|
||||
- `models.providers.minimax.baseUrl`: auto-detected based on timezone:
|
||||
- China mainland/HK/TW: `https://api.minimaxi.com/anthropic` (domestic)
|
||||
- Overseas: `https://api.minimax.io/anthropic` (default)
|
||||
- For OpenAI-compatible payloads, replace `/anthropic` with `/v1`
|
||||
- `models.providers.minimax.api`: prefer `anthropic-messages`; `openai-completions` is optional for OpenAI-compatible payloads.
|
||||
- `models.providers.minimax.apiKey`: MiniMax API key (`MINIMAX_API_KEY`).
|
||||
- `models.providers.minimax.models`: define `id`, `name`, `reasoning`, `contextWindow`, `maxTokens`, `cost`.
|
||||
- `agents.defaults.models`: alias models you want in the allowlist.
|
||||
- `models.mode`: keep `merge` if you want to add MiniMax alongside built-ins.
|
||||
|
||||
## China Mainland Users
|
||||
|
||||
OpenClaw automatically detects China mainland timezones (Asia/Shanghai, Asia/Hong_Kong,
|
||||
Asia/Taipei, etc.) and uses the domestic endpoint (`api.minimaxi.com`) for faster,
|
||||
more reliable connections.
|
||||
|
||||
> [!NOTE]
|
||||
> The domain difference is subtle: `minimaxi.com` (with extra 'i') vs `minimax.io`.
|
||||
|
||||
To manually override the baseUrl (e.g., if timezone detection doesn't work for your setup):
|
||||
|
||||
```bash
|
||||
openclaw config set models.providers.minimax.baseUrl "https://api.minimaxi.com/anthropic"
|
||||
```
|
||||
|
||||
Or edit `openclaw.json` directly:
|
||||
|
||||
```json5
|
||||
{
|
||||
models: {
|
||||
providers: {
|
||||
minimax: {
|
||||
baseUrl: "https://api.minimaxi.com/anthropic",
|
||||
apiKey: "${MINIMAX_API_KEY}",
|
||||
api: "anthropic-messages",
|
||||
models: [...]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then restart the gateway with `openclaw gateway restart`.
|
||||
|
||||
## Notes
|
||||
|
||||
- Model refs are `minimax/<model>`.
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { isChinaRegion } from "../infra/region-utils.js";
|
||||
|
||||
type MinimaxBaseResp = {
|
||||
status_code?: number;
|
||||
status_msg?: string;
|
||||
@ -9,11 +11,12 @@ function coerceApiHost(params: {
|
||||
env?: NodeJS.ProcessEnv;
|
||||
}): string {
|
||||
const env = params.env ?? process.env;
|
||||
const defaultHost = isChinaRegion() ? "https://api.minimaxi.com" : "https://api.minimax.io";
|
||||
const raw =
|
||||
params.apiHost?.trim() ||
|
||||
env.MINIMAX_API_HOST?.trim() ||
|
||||
params.modelBaseUrl?.trim() ||
|
||||
"https://api.minimax.io";
|
||||
defaultHost;
|
||||
|
||||
try {
|
||||
const url = new URL(raw);
|
||||
@ -24,7 +27,7 @@ function coerceApiHost(params: {
|
||||
const url = new URL(`https://${raw}`);
|
||||
return url.origin;
|
||||
} catch {
|
||||
return "https://api.minimax.io";
|
||||
return defaultHost;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -13,11 +13,14 @@ import {
|
||||
SYNTHETIC_MODEL_CATALOG,
|
||||
} from "./synthetic-models.js";
|
||||
import { discoverVeniceModels, VENICE_BASE_URL } from "./venice-models.js";
|
||||
import { isChinaRegion } from "../infra/region-utils.js";
|
||||
|
||||
type ModelsConfig = NonNullable<OpenClawConfig["models"]>;
|
||||
export type ProviderConfig = NonNullable<ModelsConfig["providers"]>[string];
|
||||
|
||||
const MINIMAX_API_BASE_URL = "https://api.minimax.chat/v1";
|
||||
function getMinimaxImplicitBaseUrl(): string {
|
||||
return isChinaRegion() ? "https://api.minimaxi.com/v1" : "https://api.minimax.chat/v1";
|
||||
}
|
||||
const MINIMAX_DEFAULT_MODEL_ID = "MiniMax-M2.1";
|
||||
const MINIMAX_DEFAULT_VISION_MODEL_ID = "MiniMax-VL-01";
|
||||
const MINIMAX_DEFAULT_CONTEXT_WINDOW = 200000;
|
||||
@ -254,7 +257,7 @@ export function normalizeProviders(params: {
|
||||
|
||||
function buildMinimaxProvider(): ProviderConfig {
|
||||
return {
|
||||
baseUrl: MINIMAX_API_BASE_URL,
|
||||
baseUrl: getMinimaxImplicitBaseUrl(),
|
||||
api: "openai-completions",
|
||||
models: [
|
||||
{
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { isChinaRegion } from "../infra/region-utils.js";
|
||||
import {
|
||||
buildMinimaxApiModelDefinition,
|
||||
buildMinimaxModelDefinition,
|
||||
DEFAULT_MINIMAX_BASE_URL,
|
||||
DEFAULT_MINIMAX_CONTEXT_WINDOW,
|
||||
DEFAULT_MINIMAX_MAX_TOKENS,
|
||||
MINIMAX_API_BASE_URL,
|
||||
getMinimaxBaseUrl,
|
||||
MINIMAX_HOSTED_COST,
|
||||
MINIMAX_HOSTED_MODEL_ID,
|
||||
MINIMAX_HOSTED_MODEL_REF,
|
||||
@ -81,7 +81,7 @@ export function applyMinimaxHostedProviderConfig(
|
||||
const mergedModels = hasHostedModel ? existingModels : [...existingModels, hostedModel];
|
||||
providers.minimax = {
|
||||
...existingProvider,
|
||||
baseUrl: params?.baseUrl?.trim() || DEFAULT_MINIMAX_BASE_URL,
|
||||
baseUrl: params?.baseUrl?.trim() || getMinimaxBaseUrl(isChinaRegion(), "v1"),
|
||||
apiKey: "minimax",
|
||||
api: "openai-completions",
|
||||
models: mergedModels.length > 0 ? mergedModels : [hostedModel],
|
||||
@ -164,7 +164,7 @@ export function applyMinimaxApiProviderConfig(
|
||||
const normalizedApiKey = resolvedApiKey?.trim() === "minimax" ? "" : resolvedApiKey;
|
||||
providers.minimax = {
|
||||
...existingProviderRest,
|
||||
baseUrl: MINIMAX_API_BASE_URL,
|
||||
baseUrl: getMinimaxBaseUrl(isChinaRegion(), "anthropic"),
|
||||
api: "anthropic-messages",
|
||||
...(normalizedApiKey?.trim() ? { apiKey: normalizedApiKey } : {}),
|
||||
models: mergedModels.length > 0 ? mergedModels : [apiModel],
|
||||
|
||||
@ -2,6 +2,26 @@ import type { ModelDefinitionConfig } from "../config/types.js";
|
||||
|
||||
export const DEFAULT_MINIMAX_BASE_URL = "https://api.minimax.io/v1";
|
||||
export const MINIMAX_API_BASE_URL = "https://api.minimax.io/anthropic";
|
||||
|
||||
export const MINIMAX_CHINA_BASE_URL = "https://api.minimaxi.com/v1";
|
||||
export const MINIMAX_CHINA_API_BASE_URL = "https://api.minimaxi.com/anthropic";
|
||||
|
||||
/**
|
||||
* Returns the appropriate MiniMax base URL based on region.
|
||||
*
|
||||
* @param isChinaRegion - Whether the user is in China/Greater China
|
||||
* @param api - Which API variant to use: "v1" for OpenAI-compatible, "anthropic" for Anthropic-compatible
|
||||
* @returns The appropriate base URL for the region and API variant
|
||||
*/
|
||||
export function getMinimaxBaseUrl(
|
||||
isChinaRegion: boolean,
|
||||
api: "v1" | "anthropic" = "anthropic",
|
||||
): string {
|
||||
if (isChinaRegion) {
|
||||
return api === "v1" ? MINIMAX_CHINA_BASE_URL : MINIMAX_CHINA_API_BASE_URL;
|
||||
}
|
||||
return api === "v1" ? DEFAULT_MINIMAX_BASE_URL : MINIMAX_API_BASE_URL;
|
||||
}
|
||||
export const MINIMAX_HOSTED_MODEL_ID = "MiniMax-M2.1";
|
||||
export const MINIMAX_HOSTED_MODEL_REF = `minimax/${MINIMAX_HOSTED_MODEL_ID}`;
|
||||
export const DEFAULT_MINIMAX_CONTEXT_WINDOW = 200000;
|
||||
|
||||
52
src/infra/region-utils.ts
Normal file
52
src/infra/region-utils.ts
Normal file
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Region detection utilities for provider endpoint selection.
|
||||
*
|
||||
* Some providers (e.g., MiniMax) have region-specific endpoints. This module
|
||||
* provides timezone-based region detection to automatically select the
|
||||
* appropriate endpoint for users in different regions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Timezone identifiers for China and Greater China regions.
|
||||
* These timezones indicate the user is likely in mainland China, Hong Kong,
|
||||
* Macau, or Taiwan and may benefit from using domestic API endpoints.
|
||||
*/
|
||||
const CHINA_TIMEZONES = new Set([
|
||||
"Asia/Shanghai",
|
||||
"Asia/Chongqing",
|
||||
"Asia/Harbin",
|
||||
"Asia/Urumqi",
|
||||
"PRC",
|
||||
"Asia/Hong_Kong",
|
||||
"Hongkong",
|
||||
"Asia/Macau",
|
||||
"Asia/Taipei",
|
||||
"ROC",
|
||||
]);
|
||||
|
||||
/**
|
||||
* Detects if the current environment is likely in China or Greater China
|
||||
* based on the system timezone.
|
||||
*
|
||||
* @returns `true` if the timezone indicates China/Greater China region
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* if (isChinaRegion()) {
|
||||
* // Use domestic API endpoint
|
||||
* baseUrl = "https://api.minimaxi.com/anthropic";
|
||||
* } else {
|
||||
* // Use overseas API endpoint
|
||||
* baseUrl = "https://api.minimax.io/anthropic";
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export function isChinaRegion(): boolean {
|
||||
try {
|
||||
const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
return CHINA_TIMEZONES.has(tz);
|
||||
} catch {
|
||||
// If timezone detection fails, default to overseas
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user