diff --git a/agent/agent_runtime_helpers.py b/agent/agent_runtime_helpers.py index fc56ad3ca90..3e5cd63536b 100644 --- a/agent/agent_runtime_helpers.py +++ b/agent/agent_runtime_helpers.py @@ -1569,8 +1569,12 @@ def anthropic_prompt_cache_policy( # moonshotai/kimi-k2.6 falls through to (False, False), serving ~1% # cache hits on 64K-token prompts and re-billing the full prompt on # every turn. Observed within-turn progression with cache enabled: - # 1% → 67% → 84% → 97% (#25970). - is_kimi = "kimi" in model_lower or "moonshot" in model_lower + # 1% → 67% → 84% → 97% (#25970). Reuses the canonical family matcher + # (covers bare k1./k2./k25 release slugs the substring check missed). + from agent.anthropic_adapter import _model_name_is_kimi_family + is_kimi = ( + _model_name_is_kimi_family(eff_model) or "moonshot" in model_lower + ) is_openrouter = base_url_host_matches(eff_base_url, "openrouter.ai") # Nous Portal proxies to OpenRouter behind the scenes — identical # OpenAI-wire envelope cache_control semantics. Treat it as an diff --git a/tests/run_agent/test_anthropic_prompt_cache_policy.py b/tests/run_agent/test_anthropic_prompt_cache_policy.py index 56e146d358c..679a9219fbe 100644 --- a/tests/run_agent/test_anthropic_prompt_cache_policy.py +++ b/tests/run_agent/test_anthropic_prompt_cache_policy.py @@ -105,6 +105,17 @@ class TestKimiMoonshotOnOpenRouter: ) assert agent._anthropic_prompt_cache_policy() == (True, False) + def test_kimi_bare_release_slug_on_openrouter_caches(self): + """Bare release slugs (k2-thinking) lack the 'kimi'/'moonshot' substring; + the canonical family matcher must still catch them.""" + agent = _make_agent( + provider="openrouter", + base_url="https://openrouter.ai/api/v1", + api_mode="chat_completions", + model="k2-thinking", + ) + assert agent._anthropic_prompt_cache_policy() == (True, False) + def test_kimi_on_non_openrouter_host_does_not_cache(self): agent = _make_agent( provider="custom",