refactor: remove all strix/ model alias machinery

The Strix proxy / ``strix/`` model namespace is gone. Users now pass
real provider aliases directly (``anthropic/claude-sonnet-4-6``,
``openai/gpt-5.4``, ``gemini/...``, ``openrouter/...``).

Deleted:
- ``STRIX_API_BASE`` constant in ``strix/config/config.py`` (and the
  auto-set api_base branch for ``strix/`` models in ``resolve_llm_config``).
- ``STRIX_MODEL_MAP`` and the ``StrixModelProvider`` /
  ``LitellmAnthropicProvider`` classes from
  ``strix/llm/multi_provider_setup.py``.
- ``is_anthropic_override`` flag on ``AnthropicCachingLitellmModel``
  (only existed because ``strix/<alias>`` resolved to ``openai/<base>``
  on the wire while staying Anthropic underneath; with no proxy, the
  model-name substring check is enough).
- ``startswith("strix/")`` branches in ``cli.py`` / ``main.py`` /
  ``dedupe.py`` and the ``uses_strix_models`` env-validation flag.

The new ``build_multi_provider`` registers a single ``anthropic/``
route that wraps litellm in :class:`AnthropicCachingLitellmModel`
(prompt caching). Every other prefix falls through to the SDK's
built-in routing.

Defaults flipped from ``strix/claude-sonnet-4.6`` →
``anthropic/claude-sonnet-4-6`` in run_config_factory and
agents_graph/tools.py + corresponding tests.

Tests updated:
- ``test_anthropic_cache_wrapper.py``: drop the override-flag tests.
- ``test_multi_provider_setup.py``: rewrite around the new single
  ``_AnthropicCachingProvider`` route.
- ``test_tool_registration_modes.py::test_load_skill_import_...``:
  load_skill no longer fails when there's no live agent instance — it
  echoes the requested skills back with ``success=True``.

Tests: 281/281 passing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
0xallam
2026-04-25 09:37:14 -07:00
parent d8881498ee
commit af42499b95
13 changed files with 69 additions and 223 deletions
+3 -33
View File
@@ -1,16 +1,14 @@
"""Phase 0 smoke tests for AnthropicCachingLitellmModel."""
"""Smoke tests for AnthropicCachingLitellmModel."""
from __future__ import annotations
import pytest
from strix.llm.anthropic_cache_wrapper import AnthropicCachingLitellmModel
def _make(model: str, **kwargs: object) -> AnthropicCachingLitellmModel:
def _make(model: str) -> AnthropicCachingLitellmModel:
# ``LitellmModel.__init__`` only validates that model is a string; we
# don't need a real API key for in-memory ``_patch`` testing.
return AnthropicCachingLitellmModel(model=model, api_key="test-key", **kwargs)
return AnthropicCachingLitellmModel(model=model, api_key="test-key")
def test_is_anthropic_detects_anthropic_prefix() -> None:
@@ -33,18 +31,6 @@ def test_is_anthropic_false_for_gemini() -> None:
assert m._is_anthropic() is False
def test_explicit_override_true_wins() -> None:
"""For Strix proxy routing where api_model is openai/<base> but
canonical is Anthropic, the override forces cache injection."""
m = _make("openai/claude-sonnet-4.6", is_anthropic_override=True)
assert m._is_anthropic() is True
def test_explicit_override_false_wins() -> None:
m = _make("anthropic/claude-3-5-sonnet", is_anthropic_override=False)
assert m._is_anthropic() is False
def test_patch_anthropic_adds_cache_control_to_system() -> None:
m = _make("anthropic/claude-3-5-sonnet")
items: list = [
@@ -86,19 +72,3 @@ def test_patch_skips_non_string_system_content() -> None:
def test_patch_handles_empty_list() -> None:
m = _make("anthropic/claude-3-5-sonnet")
assert m._patch([]) == []
@pytest.mark.parametrize(
"model",
[
"openai/claude-sonnet-4.6", # Strix proxy with Anthropic underneath
"openai/gpt-5.4", # Strix proxy with OpenAI underneath
],
)
def test_strix_proxy_routing_with_override(model: str) -> None:
"""Strix proxy uses openai/<base> for the API URL but the underlying
provider varies. The override flag is the source of truth."""
m_anth = _make(model, is_anthropic_override=True)
m_oai = _make(model, is_anthropic_override=False)
assert m_anth._is_anthropic() is True
assert m_oai._is_anthropic() is False
+18 -40
View File
@@ -1,64 +1,42 @@
"""Phase 0 smoke tests for multi_provider_setup."""
"""Smoke tests for the multi-provider setup."""
from __future__ import annotations
import pytest
from agents.exceptions import UserError
from agents.extensions.models.litellm_model import LitellmModel
from strix.config.config import STRIX_API_BASE
from strix.llm.anthropic_cache_wrapper import AnthropicCachingLitellmModel
from strix.llm.multi_provider_setup import (
LitellmAnthropicProvider,
StrixModelProvider,
_AnthropicCachingProvider,
build_multi_provider,
)
def test_strix_provider_resolves_anthropic_alias_with_override() -> None:
provider = StrixModelProvider()
model = provider.get_model("claude-sonnet-4.6")
def test_anthropic_provider_wraps_in_caching_model() -> None:
provider = _AnthropicCachingProvider()
model = provider.get_model("claude-sonnet-4-6")
assert isinstance(model, AnthropicCachingLitellmModel)
# Goes via Strix proxy as openai/<base>, but is_anthropic still True.
assert model.model == "openai/claude-sonnet-4.6"
assert str(model.base_url) == STRIX_API_BASE
# The provider re-prefixes with ``anthropic/`` so litellm routes correctly.
assert model.model == "anthropic/claude-sonnet-4-6"
assert model._is_anthropic() is True
def test_strix_provider_resolves_openai_alias_without_override() -> None:
provider = StrixModelProvider()
model = provider.get_model("gpt-5.4")
# Plain LitellmModel, NOT the caching subclass.
assert isinstance(model, LitellmModel)
assert not isinstance(model, AnthropicCachingLitellmModel)
assert model.model == "openai/gpt-5.4"
def test_anthropic_provider_preserves_existing_anthropic_prefix() -> None:
"""If the alias already carries ``anthropic/``, don't double-prefix."""
provider = _AnthropicCachingProvider()
model = provider.get_model("anthropic/claude-3-5-sonnet-20241022")
assert model.model == "anthropic/claude-3-5-sonnet-20241022"
def test_strix_provider_unknown_alias_raises_user_error() -> None:
"""C17 (AUDIT_R3): unknown alias must surface a clear error with valid options."""
provider = StrixModelProvider()
with pytest.raises(UserError, match="Unknown Strix model alias"):
provider.get_model("typo-model-name")
def test_strix_provider_empty_name_raises() -> None:
provider = StrixModelProvider()
def test_anthropic_provider_empty_name_raises() -> None:
provider = _AnthropicCachingProvider()
with pytest.raises(UserError, match="non-empty"):
provider.get_model(None)
def test_litellm_anthropic_provider_wraps_in_caching_model() -> None:
provider = LitellmAnthropicProvider()
model = provider.get_model("claude-3-5-sonnet-20241022")
assert isinstance(model, AnthropicCachingLitellmModel)
assert model.model == "anthropic/claude-3-5-sonnet-20241022"
assert model._is_anthropic() is True
def test_build_multi_provider_registers_strix_prefix() -> None:
def test_build_multi_provider_routes_anthropic_through_caching_wrapper() -> None:
"""The configured MultiProvider should hit our caching wrapper for the
``anthropic/`` prefix."""
mp = build_multi_provider()
# The MultiProvider stores the map; the easiest check is that resolving
# "strix/claude-sonnet-4.6" goes through StrixModelProvider.
model = mp.get_model("strix/claude-sonnet-4.6")
model = mp.get_model("anthropic/claude-sonnet-4-6")
assert isinstance(model, AnthropicCachingLitellmModel)
assert model.model == "openai/claude-sonnet-4.6"
+1 -1
View File
@@ -170,7 +170,7 @@ def test_sandbox_config_omitted_when_no_session() -> None:
def test_model_default_is_strix_claude() -> None:
"""Production default per AUDIT/PLAYBOOK convention."""
cfg = make_run_config(sandbox_session=None)
assert cfg.model == "strix/claude-sonnet-4.6"
assert cfg.model == "anthropic/claude-sonnet-4-6"
def test_multi_provider_is_built() -> None:
+3 -3
View File
@@ -281,7 +281,7 @@ async def test_create_agent_spawns_and_registers_child() -> None:
"tool_server_host_port": 12345,
"caido_host_port": None,
"tracer": None,
"model": "strix/claude-sonnet-4.6",
"model": "anthropic/claude-sonnet-4-6",
"model_settings": None,
"max_turns": 300,
"is_whitebox": False,
@@ -354,7 +354,7 @@ async def test_create_agent_inherits_parent_history() -> None:
"tool_server_host_port": 12345,
"caido_host_port": None,
"tracer": None,
"model": "strix/claude-sonnet-4.6",
"model": "anthropic/claude-sonnet-4-6",
"model_settings": None,
"max_turns": 300,
}
@@ -485,7 +485,7 @@ async def test_create_agent_spawn_is_cancelable_via_bus() -> None:
"tool_server_host_port": 12345,
"caido_host_port": None,
"tracer": None,
"model": "strix/claude-sonnet-4.6",
"model": "anthropic/claude-sonnet-4-6",
"model_settings": None,
"max_turns": 300,
}
+4 -1
View File
@@ -96,4 +96,7 @@ def test_load_skill_import_does_not_register_create_agent_in_sandbox(
names_after = set(registry.get_tool_names())
assert "create_agent" not in names_after
assert result["success"] is False
# load_skill no longer reaches into the legacy _agent_instances global —
# it returns ``success=True`` with the requested skills echoed back.
assert result["success"] is True
assert result["loaded_skills"] == ["nmap"]