diff --git a/.env.example b/.env.example index a6e98751a3..f2c5769c65 100644 --- a/.env.example +++ b/.env.example @@ -43,6 +43,7 @@ # KIMI_BASE_URL=https://api.kimi.com/coding/v1 # Default for sk-kimi- keys # KIMI_BASE_URL=https://api.moonshot.ai/v1 # For legacy Moonshot keys # KIMI_BASE_URL=https://api.moonshot.cn/v1 # For Moonshot China keys +# KIMI_CN_API_KEY= # Dedicated Moonshot China key # ============================================================================= # LLM PROVIDER (MiniMax) diff --git a/agent/auxiliary_client.py b/agent/auxiliary_client.py index c1c2e2f9a3..5016662d58 100644 --- a/agent/auxiliary_client.py +++ b/agent/auxiliary_client.py @@ -64,6 +64,8 @@ _PROVIDER_ALIASES = { "zhipu": "zai", "kimi": "kimi-coding", "moonshot": "kimi-coding", + "kimi-cn": "kimi-coding-cn", + "moonshot-cn": "kimi-coding-cn", "minimax-china": "minimax-cn", "minimax_cn": "minimax-cn", "claude": "anthropic", @@ -94,6 +96,7 @@ _API_KEY_PROVIDER_AUX_MODELS: Dict[str, str] = { "gemini": "gemini-3-flash-preview", "zai": "glm-4.5-flash", "kimi-coding": "kimi-k2-turbo-preview", + "kimi-coding-cn": "kimi-k2-turbo-preview", "minimax": "MiniMax-M2.7", "minimax-cn": "MiniMax-M2.7", "anthropic": "claude-haiku-4-5-20251001", diff --git a/agent/model_metadata.py b/agent/model_metadata.py index 97ac0b8b8d..4c8d678dc9 100644 --- a/agent/model_metadata.py +++ b/agent/model_metadata.py @@ -24,7 +24,7 @@ logger = logging.getLogger(__name__) # are preserved so the full model name reaches cache lookups and server queries. _PROVIDER_PREFIXES: frozenset[str] = frozenset({ "openrouter", "nous", "openai-codex", "copilot", "copilot-acp", - "gemini", "zai", "kimi-coding", "minimax", "minimax-cn", "anthropic", "deepseek", + "gemini", "zai", "kimi-coding", "kimi-coding-cn", "minimax", "minimax-cn", "anthropic", "deepseek", "opencode-zen", "opencode-go", "ai-gateway", "kilocode", "alibaba", "qwen-oauth", "xiaomi", @@ -32,7 +32,7 @@ _PROVIDER_PREFIXES: frozenset[str] = frozenset({ # Common aliases "google", "google-gemini", "google-ai-studio", "glm", "z-ai", "z.ai", "zhipu", "github", "github-copilot", - "github-models", "kimi", "moonshot", "claude", "deep-seek", + "github-models", "kimi", "moonshot", "kimi-cn", "moonshot-cn", "claude", "deep-seek", "opencode", "zen", "go", "vercel", "kilo", "dashscope", "aliyun", "qwen", "mimo", "xiaomi-mimo", "qwen-portal", @@ -211,6 +211,7 @@ _URL_TO_PROVIDER: Dict[str, str] = { "api.anthropic.com": "anthropic", "api.z.ai": "zai", "api.moonshot.ai": "kimi-coding", + "api.moonshot.cn": "kimi-coding-cn", "api.kimi.com": "kimi-coding", "api.minimax": "minimax", "dashscope.aliyuncs.com": "alibaba", diff --git a/hermes_cli/auth.py b/hermes_cli/auth.py index b92c1fc26d..795e5ea09f 100644 --- a/hermes_cli/auth.py +++ b/hermes_cli/auth.py @@ -160,6 +160,13 @@ PROVIDER_REGISTRY: Dict[str, ProviderConfig] = { api_key_env_vars=("KIMI_API_KEY",), base_url_env_var="KIMI_BASE_URL", ), + "kimi-coding-cn": ProviderConfig( + id="kimi-coding-cn", + name="Kimi / Moonshot (China)", + auth_type="api_key", + inference_base_url="https://api.moonshot.cn/v1", + api_key_env_vars=("KIMI_CN_API_KEY",), + ), "minimax": ProviderConfig( id="minimax", name="MiniMax", @@ -892,6 +899,7 @@ def resolve_provider( "glm": "zai", "z-ai": "zai", "z.ai": "zai", "zhipu": "zai", "google": "gemini", "google-gemini": "gemini", "google-ai-studio": "gemini", "kimi": "kimi-coding", "kimi-for-coding": "kimi-coding", "moonshot": "kimi-coding", + "kimi-cn": "kimi-coding-cn", "moonshot-cn": "kimi-coding-cn", "minimax-china": "minimax-cn", "minimax_cn": "minimax-cn", "claude": "anthropic", "claude-code": "anthropic", "github": "copilot", "github-copilot": "copilot", diff --git a/hermes_cli/config.py b/hermes_cli/config.py index f524e792a5..738960bb47 100644 --- a/hermes_cli/config.py +++ b/hermes_cli/config.py @@ -816,6 +816,14 @@ OPTIONAL_ENV_VARS = { "category": "provider", "advanced": True, }, + "KIMI_CN_API_KEY": { + "description": "Kimi / Moonshot China API key", + "prompt": "Kimi (China) API key", + "url": "https://platform.moonshot.cn/", + "password": True, + "category": "provider", + "advanced": True, + }, "MINIMAX_API_KEY": { "description": "MiniMax API key (international)", "prompt": "MiniMax API key", @@ -2452,6 +2460,7 @@ _FALLBACK_COMMENT = """ # nous (OAuth — hermes auth) — Nous Portal # zai (ZAI_API_KEY) — Z.AI / GLM # kimi-coding (KIMI_API_KEY) — Kimi / Moonshot +# kimi-coding-cn (KIMI_CN_API_KEY) — Kimi / Moonshot (China) # minimax (MINIMAX_API_KEY) — MiniMax # minimax-cn (MINIMAX_CN_API_KEY) — MiniMax (China) # @@ -2495,6 +2504,7 @@ _COMMENTED_SECTIONS = """ # nous (OAuth — hermes auth) — Nous Portal # zai (ZAI_API_KEY) — Z.AI / GLM # kimi-coding (KIMI_API_KEY) — Kimi / Moonshot +# kimi-coding-cn (KIMI_CN_API_KEY) — Kimi / Moonshot (China) # minimax (MINIMAX_API_KEY) — MiniMax # minimax-cn (MINIMAX_CN_API_KEY) — MiniMax (China) # diff --git a/hermes_cli/main.py b/hermes_cli/main.py index f653b4cd07..97281d5a95 100644 --- a/hermes_cli/main.py +++ b/hermes_cli/main.py @@ -1045,6 +1045,7 @@ def select_provider_and_model(args=None): "gemini": "Google AI Studio", "zai": "Z.AI / GLM", "kimi-coding": "Kimi / Moonshot", + "kimi-coding-cn": "Kimi / Moonshot (China)", "minimax": "MiniMax", "minimax-cn": "MiniMax (China)", "opencode-zen": "OpenCode Zen", @@ -1079,6 +1080,7 @@ def select_provider_and_model(args=None): ("gemini", "Google AI Studio (Gemini models — OpenAI-compatible endpoint)"), ("zai", "Z.AI / GLM (Zhipu AI direct API)"), ("kimi-coding", "Kimi / Moonshot (Moonshot AI direct API)"), + ("kimi-coding-cn", "Kimi / Moonshot China (Moonshot CN direct API)"), ("minimax", "MiniMax (global direct API)"), ("minimax-cn", "MiniMax China (domestic direct API)"), ("kilocode", "Kilo Code (Kilo Gateway API)"), @@ -1205,7 +1207,7 @@ def select_provider_and_model(args=None): _model_flow_anthropic(config, current_model) elif selected_provider == "kimi-coding": _model_flow_kimi(config, current_model) - elif selected_provider in ("gemini", "zai", "minimax", "minimax-cn", "kilocode", "opencode-zen", "opencode-go", "ai-gateway", "alibaba", "huggingface", "xiaomi"): + elif selected_provider in ("gemini", "zai", "kimi-coding-cn", "minimax", "minimax-cn", "kilocode", "opencode-zen", "opencode-go", "ai-gateway", "alibaba", "huggingface", "xiaomi"): _model_flow_api_key_provider(config, selected_provider, current_model) # ── Post-switch cleanup: clear stale OPENAI_BASE_URL ────────────── @@ -4626,7 +4628,7 @@ For more help on a command: ) chat_parser.add_argument( "--provider", - choices=["auto", "openrouter", "nous", "openai-codex", "copilot-acp", "copilot", "anthropic", "gemini", "huggingface", "zai", "kimi-coding", "minimax", "minimax-cn", "kilocode", "xiaomi"], + choices=["auto", "openrouter", "nous", "openai-codex", "copilot-acp", "copilot", "anthropic", "gemini", "huggingface", "zai", "kimi-coding", "kimi-coding-cn", "minimax", "minimax-cn", "kilocode", "xiaomi"], default=None, help="Inference provider (default: auto)" ) diff --git a/hermes_cli/models.py b/hermes_cli/models.py index 8308b102e5..c3f1408d1b 100644 --- a/hermes_cli/models.py +++ b/hermes_cli/models.py @@ -158,6 +158,12 @@ _PROVIDER_MODELS: dict[str, list[str]] = { "kimi-k2-turbo-preview", "kimi-k2-0905-preview", ], + "kimi-coding-cn": [ + "kimi-k2.5", + "kimi-k2-thinking", + "kimi-k2-turbo-preview", + "kimi-k2-0905-preview", + ], "moonshot": [ "kimi-k2.5", "kimi-k2-thinking", @@ -488,6 +494,7 @@ _PROVIDER_LABELS = { "gemini": "Google AI Studio", "zai": "Z.AI / GLM", "kimi-coding": "Kimi / Moonshot", + "kimi-coding-cn": "Kimi / Moonshot (China)", "minimax": "MiniMax", "minimax-cn": "MiniMax (China)", "anthropic": "Anthropic", @@ -519,6 +526,8 @@ _PROVIDER_ALIASES = { "google-ai-studio": "gemini", "kimi": "kimi-coding", "moonshot": "kimi-coding", + "kimi-cn": "kimi-coding-cn", + "moonshot-cn": "kimi-coding-cn", "minimax-china": "minimax-cn", "minimax_cn": "minimax-cn", "claude": "anthropic", @@ -841,7 +850,7 @@ def list_available_providers() -> list[dict[str, str]]: _PROVIDER_ORDER = [ "openrouter", "nous", "openai-codex", "copilot", "copilot-acp", "gemini", "huggingface", - "zai", "kimi-coding", "minimax", "minimax-cn", "kilocode", "anthropic", "alibaba", + "zai", "kimi-coding", "kimi-coding-cn", "minimax", "minimax-cn", "kilocode", "anthropic", "alibaba", "qwen-oauth", "xiaomi", "opencode-zen", "opencode-go", "ai-gateway", "deepseek", "custom", diff --git a/website/docs/getting-started/quickstart.md b/website/docs/getting-started/quickstart.md index c16aa30787..983cedd804 100644 --- a/website/docs/getting-started/quickstart.md +++ b/website/docs/getting-started/quickstart.md @@ -51,6 +51,7 @@ hermes setup # Or configure everything at once | **OpenRouter** | Multi-provider routing across many models | Enter your API key | | **Z.AI** | GLM / Zhipu-hosted models | Set `GLM_API_KEY` / `ZAI_API_KEY` | | **Kimi / Moonshot** | Moonshot-hosted coding and chat models | Set `KIMI_API_KEY` | +| **Kimi / Moonshot China** | China-region Moonshot endpoint | Set `KIMI_CN_API_KEY` | | **MiniMax** | International MiniMax endpoint | Set `MINIMAX_API_KEY` | | **MiniMax China** | China-region MiniMax endpoint | Set `MINIMAX_CN_API_KEY` | | **Alibaba Cloud** | Qwen models via DashScope | Set `DASHSCOPE_API_KEY` | diff --git a/website/docs/reference/environment-variables.md b/website/docs/reference/environment-variables.md index e7cb4d1e05..177f87ab90 100644 --- a/website/docs/reference/environment-variables.md +++ b/website/docs/reference/environment-variables.md @@ -31,6 +31,7 @@ All variables go in `~/.hermes/.env`. You can also set them with `hermes config | `GLM_BASE_URL` | Override z.ai base URL (default: `https://api.z.ai/api/paas/v4`) | | `KIMI_API_KEY` | Kimi / Moonshot AI API key ([moonshot.ai](https://platform.moonshot.ai)) | | `KIMI_BASE_URL` | Override Kimi base URL (default: `https://api.moonshot.ai/v1`) | +| `KIMI_CN_API_KEY` | Kimi / Moonshot China API key ([moonshot.cn](https://platform.moonshot.cn)) | | `MINIMAX_API_KEY` | MiniMax API key — global endpoint ([minimax.io](https://www.minimax.io)) | | `MINIMAX_BASE_URL` | Override MiniMax base URL (default: `https://api.minimax.io/v1`) | | `MINIMAX_CN_API_KEY` | MiniMax API key — China endpoint ([minimaxi.com](https://www.minimaxi.com)) | @@ -67,7 +68,7 @@ For native Anthropic auth, Hermes prefers Claude Code's own credential files whe | Variable | Description | |----------|-------------| -| `HERMES_INFERENCE_PROVIDER` | Override provider selection: `auto`, `openrouter`, `nous`, `openai-codex`, `copilot`, `copilot-acp`, `anthropic`, `huggingface`, `zai`, `kimi-coding`, `minimax`, `minimax-cn`, `kilocode`, `xiaomi`, `alibaba`, `deepseek`, `opencode-zen`, `opencode-go`, `ai-gateway` (default: `auto`) | +| `HERMES_INFERENCE_PROVIDER` | Override provider selection: `auto`, `openrouter`, `nous`, `openai-codex`, `copilot`, `copilot-acp`, `anthropic`, `huggingface`, `zai`, `kimi-coding`, `kimi-coding-cn`, `minimax`, `minimax-cn`, `kilocode`, `xiaomi`, `alibaba`, `deepseek`, `opencode-zen`, `opencode-go`, `ai-gateway` (default: `auto`) | | `HERMES_PORTAL_BASE_URL` | Override Nous Portal URL (for development/testing) | | `NOUS_INFERENCE_BASE_URL` | Override Nous inference API URL | | `HERMES_NOUS_MIN_KEY_TTL_SECONDS` | Min agent key TTL before re-mint (default: 1800 = 30min) | diff --git a/website/docs/user-guide/configuration.md b/website/docs/user-guide/configuration.md index 44a1142f53..2383cb6403 100644 --- a/website/docs/user-guide/configuration.md +++ b/website/docs/user-guide/configuration.md @@ -601,7 +601,7 @@ Every model slot in Hermes — auxiliary tasks, compression, fallback — uses t When `base_url` is set, Hermes ignores the provider and calls that endpoint directly (using `api_key` or `OPENAI_API_KEY` for auth). When only `provider` is set, Hermes uses that provider's built-in auth and base URL. -Available providers for auxiliary tasks: `auto`, `openrouter`, `nous`, `codex`, `copilot`, `anthropic`, `main`, `zai`, `kimi-coding`, `minimax`, any provider registered in the [provider registry](/docs/reference/environment-variables), or any named custom provider from your `custom_providers` list (e.g. `provider: "beans"`). +Available providers for auxiliary tasks: `auto`, `openrouter`, `nous`, `codex`, `copilot`, `anthropic`, `main`, `zai`, `kimi-coding`, `kimi-coding-cn`, `minimax`, any provider registered in the [provider registry](/docs/reference/environment-variables), or any named custom provider from your `custom_providers` list (e.g. `provider: "beans"`). :::warning `"main"` is for auxiliary tasks only The `"main"` provider option means "use whatever provider my main agent uses" — it's only valid inside `auxiliary:`, `compression:`, and `fallback_model:` configs. It is **not** a valid value for your top-level `model.provider` setting. If you use a custom OpenAI-compatible endpoint, set `provider: custom` in your `model:` section. See [AI Providers](/docs/integrations/providers) for all main model provider options.