From a0939901df6534ace6bb8044c59b491148a1b27c Mon Sep 17 00:00:00 2001 From: kshitij <82637225+kshitijk4poor@users.noreply.github.com> Date: Fri, 14 Aug 2026 00:46:09 +0530 Subject: [PATCH] fix: address review feedback from #85512 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - /model switch now refreshes agent._custom_providers from the config loaded during the switch before re-evaluating cache policy — a prompt_caching flag added to config.yaml after session start was invisible to a mid-session switch (policy read the stale init-time snapshot while context_length resolution used the live list). - Production-path test: real config.yaml in the modern providers: dict shape through the real loader chain, exercising the init-order fallback (no _custom_providers attr) for both the fable opt-in and the opus explicit opt-out. - Pin operator kill-switch precedence: _cache_disabled (prompt_caching. cache_ttl falsy) beats an explicit per-model prompt_caching: true. --- agent/agent_runtime_helpers.py | 7 +++ .../test_anthropic_prompt_cache_policy.py | 62 +++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/agent/agent_runtime_helpers.py b/agent/agent_runtime_helpers.py index 35d9848496cb5..a9bf1a1d38df5 100644 --- a/agent/agent_runtime_helpers.py +++ b/agent/agent_runtime_helpers.py @@ -2756,6 +2756,13 @@ def switch_model(agent, new_model, new_provider, api_key='', base_url='', api_mo ) # ── Re-evaluate prompt caching ── + # Refresh the custom-provider snapshot from the config just loaded above + # so the per-model ``prompt_caching`` capability lookup sees the same + # live list the context-length resolution used — without this, a flag + # added to config.yaml after session start is invisible to a /model + # switch (the policy would read the stale init-time snapshot). + if _sm_custom_providers is not None: + agent._custom_providers = _sm_custom_providers agent._use_prompt_caching, agent._use_native_cache_layout = ( agent._anthropic_prompt_cache_policy( provider=new_provider, diff --git a/tests/run_agent/test_anthropic_prompt_cache_policy.py b/tests/run_agent/test_anthropic_prompt_cache_policy.py index 9fe66cd4c3628..018c6edc79e71 100644 --- a/tests/run_agent/test_anthropic_prompt_cache_policy.py +++ b/tests/run_agent/test_anthropic_prompt_cache_policy.py @@ -231,6 +231,68 @@ class TestThirdPartyAnthropicGateway: assert agent._anthropic_prompt_cache_policy() == (False, False) + def test_operator_cache_disable_beats_explicit_capability_true(self): + """prompt_caching.cache_ttl disable (agent._cache_disabled) is a + global operator kill-switch — it must win over a per-model + prompt_caching: true declaration (#33555 semantics).""" + agent = _make_agent( + provider="custom:anthropic-proxy", + base_url="https://gateway.example.com/anthropic", + api_mode="anthropic_messages", + model="fable", + ) + agent._custom_providers = [ + { + "name": "anthropic-proxy", + "base_url": "https://gateway.example.com/anthropic", + "models": {"fable": {"prompt_caching": True}}, + } + ] + agent._cache_disabled = True + + assert agent._anthropic_prompt_cache_policy() == (False, False) + + def test_modern_providers_yaml_through_real_loader(self, tmp_path, monkeypatch): + """Production path: a real config.yaml in the modern ``providers:`` + dict shape, loaded through the real normalizer chain — including the + init-order fallback where ``_custom_providers`` is NOT yet set on the + agent and the policy loads config itself.""" + import textwrap + + hermes_home = tmp_path / ".hermes" + hermes_home.mkdir() + (hermes_home / "config.yaml").write_text( + textwrap.dedent( + """ + providers: + anthropic-proxy: + api: https://gateway.example.com/anthropic + transport: anthropic_messages + models: + fable: + context_length: 1000000 + prompt_caching: true + opus: + prompt_caching: false + """ + ) + ) + monkeypatch.setenv("HERMES_HOME", str(hermes_home)) + # load_config's cache is keyed by resolved config path, so pointing + # HERMES_HOME at a fresh tempdir needs no cache invalidation. + agent = _make_agent( + provider="custom:anthropic-proxy", + base_url="https://gateway.example.com/anthropic", + api_mode="anthropic_messages", + model="fable", + ) + # No agent._custom_providers — exercises the config fallback the + # init-time call (agent_init before the snapshot assignment) hits. + assert agent._anthropic_prompt_cache_policy() == (True, True) + + agent.model = "opus" + assert agent._anthropic_prompt_cache_policy() == (False, False) + class TestMiniMaxAnthropicWire: """MiniMax's own model family on its Anthropic-compatible endpoint.