fix: address review feedback from #85512

- /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.
This commit is contained in:
kshitij 2026-08-14 00:46:09 +05:30
parent 4fa728b6be
commit a0939901df
2 changed files with 69 additions and 0 deletions

View File

@ -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,

View File

@ -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.