Merge b163440f6f into 09be5d45d5
This commit is contained in:
commit
792ff8a74e
@ -145,13 +145,50 @@ Use the interactive config wizard to set MiniMax without editing JSON:
|
|||||||
|
|
||||||
## Configuration options
|
## 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.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.apiKey`: MiniMax API key (`MINIMAX_API_KEY`).
|
||||||
- `models.providers.minimax.models`: define `id`, `name`, `reasoning`, `contextWindow`, `maxTokens`, `cost`.
|
- `models.providers.minimax.models`: define `id`, `name`, `reasoning`, `contextWindow`, `maxTokens`, `cost`.
|
||||||
- `agents.defaults.models`: alias models you want in the allowlist.
|
- `agents.defaults.models`: alias models you want in the allowlist.
|
||||||
- `models.mode`: keep `merge` if you want to add MiniMax alongside built-ins.
|
- `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
|
## Notes
|
||||||
|
|
||||||
- Model refs are `minimax/<model>`.
|
- Model refs are `minimax/<model>`.
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import { isChinaRegion } from "../infra/region-utils.js";
|
||||||
|
|
||||||
type MinimaxBaseResp = {
|
type MinimaxBaseResp = {
|
||||||
status_code?: number;
|
status_code?: number;
|
||||||
status_msg?: string;
|
status_msg?: string;
|
||||||
@ -9,11 +11,12 @@ function coerceApiHost(params: {
|
|||||||
env?: NodeJS.ProcessEnv;
|
env?: NodeJS.ProcessEnv;
|
||||||
}): string {
|
}): string {
|
||||||
const env = params.env ?? process.env;
|
const env = params.env ?? process.env;
|
||||||
|
const defaultHost = isChinaRegion() ? "https://api.minimaxi.com" : "https://api.minimax.io";
|
||||||
const raw =
|
const raw =
|
||||||
params.apiHost?.trim() ||
|
params.apiHost?.trim() ||
|
||||||
env.MINIMAX_API_HOST?.trim() ||
|
env.MINIMAX_API_HOST?.trim() ||
|
||||||
params.modelBaseUrl?.trim() ||
|
params.modelBaseUrl?.trim() ||
|
||||||
"https://api.minimax.io";
|
defaultHost;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const url = new URL(raw);
|
const url = new URL(raw);
|
||||||
@ -24,7 +27,7 @@ function coerceApiHost(params: {
|
|||||||
const url = new URL(`https://${raw}`);
|
const url = new URL(`https://${raw}`);
|
||||||
return url.origin;
|
return url.origin;
|
||||||
} catch {
|
} catch {
|
||||||
return "https://api.minimax.io";
|
return defaultHost;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -13,11 +13,14 @@ import {
|
|||||||
SYNTHETIC_MODEL_CATALOG,
|
SYNTHETIC_MODEL_CATALOG,
|
||||||
} from "./synthetic-models.js";
|
} from "./synthetic-models.js";
|
||||||
import { discoverVeniceModels, VENICE_BASE_URL } from "./venice-models.js";
|
import { discoverVeniceModels, VENICE_BASE_URL } from "./venice-models.js";
|
||||||
|
import { isChinaRegion } from "../infra/region-utils.js";
|
||||||
|
|
||||||
type ModelsConfig = NonNullable<OpenClawConfig["models"]>;
|
type ModelsConfig = NonNullable<OpenClawConfig["models"]>;
|
||||||
export type ProviderConfig = NonNullable<ModelsConfig["providers"]>[string];
|
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_MODEL_ID = "MiniMax-M2.1";
|
||||||
const MINIMAX_DEFAULT_VISION_MODEL_ID = "MiniMax-VL-01";
|
const MINIMAX_DEFAULT_VISION_MODEL_ID = "MiniMax-VL-01";
|
||||||
const MINIMAX_DEFAULT_CONTEXT_WINDOW = 200000;
|
const MINIMAX_DEFAULT_CONTEXT_WINDOW = 200000;
|
||||||
@ -254,7 +257,7 @@ export function normalizeProviders(params: {
|
|||||||
|
|
||||||
function buildMinimaxProvider(): ProviderConfig {
|
function buildMinimaxProvider(): ProviderConfig {
|
||||||
return {
|
return {
|
||||||
baseUrl: MINIMAX_API_BASE_URL,
|
baseUrl: getMinimaxImplicitBaseUrl(),
|
||||||
api: "openai-completions",
|
api: "openai-completions",
|
||||||
models: [
|
models: [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import type { OpenClawConfig } from "../config/config.js";
|
import type { OpenClawConfig } from "../config/config.js";
|
||||||
|
import { isChinaRegion } from "../infra/region-utils.js";
|
||||||
import {
|
import {
|
||||||
buildMinimaxApiModelDefinition,
|
buildMinimaxApiModelDefinition,
|
||||||
buildMinimaxModelDefinition,
|
buildMinimaxModelDefinition,
|
||||||
DEFAULT_MINIMAX_BASE_URL,
|
|
||||||
DEFAULT_MINIMAX_CONTEXT_WINDOW,
|
DEFAULT_MINIMAX_CONTEXT_WINDOW,
|
||||||
DEFAULT_MINIMAX_MAX_TOKENS,
|
DEFAULT_MINIMAX_MAX_TOKENS,
|
||||||
MINIMAX_API_BASE_URL,
|
getMinimaxBaseUrl,
|
||||||
MINIMAX_HOSTED_COST,
|
MINIMAX_HOSTED_COST,
|
||||||
MINIMAX_HOSTED_MODEL_ID,
|
MINIMAX_HOSTED_MODEL_ID,
|
||||||
MINIMAX_HOSTED_MODEL_REF,
|
MINIMAX_HOSTED_MODEL_REF,
|
||||||
@ -81,7 +81,7 @@ export function applyMinimaxHostedProviderConfig(
|
|||||||
const mergedModels = hasHostedModel ? existingModels : [...existingModels, hostedModel];
|
const mergedModels = hasHostedModel ? existingModels : [...existingModels, hostedModel];
|
||||||
providers.minimax = {
|
providers.minimax = {
|
||||||
...existingProvider,
|
...existingProvider,
|
||||||
baseUrl: params?.baseUrl?.trim() || DEFAULT_MINIMAX_BASE_URL,
|
baseUrl: params?.baseUrl?.trim() || getMinimaxBaseUrl(isChinaRegion(), "v1"),
|
||||||
apiKey: "minimax",
|
apiKey: "minimax",
|
||||||
api: "openai-completions",
|
api: "openai-completions",
|
||||||
models: mergedModels.length > 0 ? mergedModels : [hostedModel],
|
models: mergedModels.length > 0 ? mergedModels : [hostedModel],
|
||||||
@ -164,7 +164,7 @@ export function applyMinimaxApiProviderConfig(
|
|||||||
const normalizedApiKey = resolvedApiKey?.trim() === "minimax" ? "" : resolvedApiKey;
|
const normalizedApiKey = resolvedApiKey?.trim() === "minimax" ? "" : resolvedApiKey;
|
||||||
providers.minimax = {
|
providers.minimax = {
|
||||||
...existingProviderRest,
|
...existingProviderRest,
|
||||||
baseUrl: MINIMAX_API_BASE_URL,
|
baseUrl: getMinimaxBaseUrl(isChinaRegion(), "anthropic"),
|
||||||
api: "anthropic-messages",
|
api: "anthropic-messages",
|
||||||
...(normalizedApiKey?.trim() ? { apiKey: normalizedApiKey } : {}),
|
...(normalizedApiKey?.trim() ? { apiKey: normalizedApiKey } : {}),
|
||||||
models: mergedModels.length > 0 ? mergedModels : [apiModel],
|
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 DEFAULT_MINIMAX_BASE_URL = "https://api.minimax.io/v1";
|
||||||
export const MINIMAX_API_BASE_URL = "https://api.minimax.io/anthropic";
|
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_ID = "MiniMax-M2.1";
|
||||||
export const MINIMAX_HOSTED_MODEL_REF = `minimax/${MINIMAX_HOSTED_MODEL_ID}`;
|
export const MINIMAX_HOSTED_MODEL_REF = `minimax/${MINIMAX_HOSTED_MODEL_ID}`;
|
||||||
export const DEFAULT_MINIMAX_CONTEXT_WINDOW = 200000;
|
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