diff --git a/hermes_cli/doctor.py b/hermes_cli/doctor.py index 34a57aad2..892ff0021 100644 --- a/hermes_cli/doctor.py +++ b/hermes_cli/doctor.py @@ -42,6 +42,7 @@ _PROVIDER_ENV_HINTS = ( "ZAI_API_KEY", "Z_AI_API_KEY", "KIMI_API_KEY", + "KIMI_CN_API_KEY", "MINIMAX_API_KEY", "MINIMAX_CN_API_KEY", "KILOCODE_API_KEY", @@ -749,7 +750,7 @@ def run_doctor(args): print(f" Checking {_pname} API...", end="", flush=True) try: import httpx - _base = os.getenv(_base_env, "") + _base = os.getenv(_base_env, "") if _base_env else "" # Auto-detect Kimi Code keys (sk-kimi-) → api.kimi.com if not _base and _key.startswith("sk-kimi-"): _base = "https://api.kimi.com/coding/v1" diff --git a/tests/hermes_cli/test_doctor.py b/tests/hermes_cli/test_doctor.py index faaa7a8a2..dd15336f6 100644 --- a/tests/hermes_cli/test_doctor.py +++ b/tests/hermes_cli/test_doctor.py @@ -40,6 +40,10 @@ class TestProviderEnvDetection: content = "OPENAI_BASE_URL=http://localhost:8080/v1\n" assert _has_provider_env_config(content) + def test_detects_kimi_cn_api_key(self): + content = "KIMI_CN_API_KEY=sk-test\n" + assert _has_provider_env_config(content) + def test_returns_false_when_no_provider_settings(self): content = "TERMINAL_ENV=local\n" assert not _has_provider_env_config(content) @@ -292,3 +296,50 @@ def test_run_doctor_termux_does_not_mark_browser_available_without_agent_browser assert "system dependency not met" in out assert "agent-browser is not installed (expected in the tested Termux path)" in out assert "npm install -g agent-browser && agent-browser install" in out + + +def test_run_doctor_kimi_cn_env_is_detected_and_probe_is_null_safe(monkeypatch, tmp_path): + home = tmp_path / ".hermes" + home.mkdir(parents=True, exist_ok=True) + (home / "config.yaml").write_text("memory: {}\n", encoding="utf-8") + (home / ".env").write_text("KIMI_CN_API_KEY=sk-test\n", encoding="utf-8") + project = tmp_path / "project" + project.mkdir(exist_ok=True) + + monkeypatch.setattr(doctor_mod, "HERMES_HOME", home) + monkeypatch.setattr(doctor_mod, "PROJECT_ROOT", project) + monkeypatch.setattr(doctor_mod, "_DHH", str(home)) + monkeypatch.setenv("KIMI_CN_API_KEY", "sk-test") + + fake_model_tools = types.SimpleNamespace( + check_tool_availability=lambda *a, **kw: ([], []), + TOOLSET_REQUIREMENTS={}, + ) + monkeypatch.setitem(sys.modules, "model_tools", fake_model_tools) + + try: + from hermes_cli import auth as _auth_mod + monkeypatch.setattr(_auth_mod, "get_nous_auth_status", lambda: {}) + monkeypatch.setattr(_auth_mod, "get_codex_auth_status", lambda: {}) + except Exception: + pass + + calls = [] + + def fake_get(url, headers=None, timeout=None): + calls.append((url, headers, timeout)) + return types.SimpleNamespace(status_code=200) + + import httpx + monkeypatch.setattr(httpx, "get", fake_get) + + import io, contextlib + buf = io.StringIO() + with contextlib.redirect_stdout(buf): + doctor_mod.run_doctor(Namespace(fix=False)) + out = buf.getvalue() + + assert "API key or custom endpoint configured" in out + assert "Kimi / Moonshot (China)" in out + assert "str expected, not NoneType" not in out + assert any(url == "https://api.moonshot.cn/v1/models" for url, _, _ in calls)