mirror of
https://github.com/usestrix/strix.git
synced 2026-08-24 11:52:38 +02:00
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:
co-authored by
Claude Opus 4.7
parent
d8881498ee
commit
af42499b95
@@ -1,116 +1,52 @@
|
||||
"""Multi-provider routing setup for Strix on top of the SDK MultiProvider.
|
||||
"""Multi-provider routing setup.
|
||||
|
||||
The SDK's ``MultiProvider`` resolves a model name like ``"strix/claude-sonnet-4.6"``
|
||||
by stripping the prefix (``"strix"``) and dispatching to a registered
|
||||
``ModelProvider`` keyed on that prefix. We register two custom providers:
|
||||
|
||||
- ``"strix"`` → ``StrixModelProvider``: aliases the short name to a Strix-proxy
|
||||
``openai/<base>`` model URL, but knows whether the underlying provider is
|
||||
Anthropic so cache-control still gets injected at the message layer.
|
||||
- ``"litellm/anthropic"`` → ``LitellmAnthropicProvider``: direct Anthropic
|
||||
routing via LiteLLM, always Anthropic, always caching.
|
||||
|
||||
Other prefixes fall through to the SDK's built-in OpenAI / LiteLLM defaults.
|
||||
Wraps the SDK's :class:`MultiProvider` and registers a custom Anthropic
|
||||
route so models named ``anthropic/<model>`` go through
|
||||
:class:`AnthropicCachingLitellmModel` (which injects ``cache_control``
|
||||
on the system message). Every other prefix
|
||||
(``openai/`` / ``gemini/`` / ``openrouter/`` / ``litellm/...``) falls
|
||||
through to the SDK's built-in litellm routing.
|
||||
|
||||
References:
|
||||
- PLAYBOOK.md §2.7
|
||||
- AUDIT_R3.md C17 (model alias validation; raise UserError on unknown alias)
|
||||
- AUDIT_R3.md C17 (model alias validation; raise UserError on bad alias)
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from agents.exceptions import UserError
|
||||
from agents.extensions.models.litellm_model import LitellmModel
|
||||
from agents.models.interface import Model, ModelProvider
|
||||
from agents.models.multi_provider import MultiProvider, MultiProviderMap
|
||||
|
||||
from strix.config.config import STRIX_API_BASE
|
||||
from strix.llm.anthropic_cache_wrapper import AnthropicCachingLitellmModel
|
||||
|
||||
|
||||
# Strix-proxy aliases. Each maps the user-facing alias (right of
|
||||
# ``strix/``) to the canonical provider/model used for capability
|
||||
# lookups (litellm reads e.g. ``anthropic/claude-sonnet-4-6`` to
|
||||
# decide on prompt-caching support).
|
||||
STRIX_MODEL_MAP: dict[str, str] = {
|
||||
"claude-sonnet-4.6": "anthropic/claude-sonnet-4-6",
|
||||
"claude-opus-4.6": "anthropic/claude-opus-4-6",
|
||||
"gpt-5.2": "openai/gpt-5.2",
|
||||
"gpt-5.1": "openai/gpt-5.1",
|
||||
"gpt-5.4": "openai/gpt-5.4",
|
||||
"gemini-3-pro-preview": "gemini/gemini-3-pro-preview",
|
||||
"gemini-3-flash-preview": "gemini/gemini-3-flash-preview",
|
||||
"glm-5": "openrouter/z-ai/glm-5",
|
||||
"glm-4.7": "openrouter/z-ai/glm-4.7",
|
||||
}
|
||||
class _AnthropicCachingProvider(ModelProvider):
|
||||
"""Routes ``anthropic/<model>`` aliases through
|
||||
:class:`AnthropicCachingLitellmModel`.
|
||||
|
||||
|
||||
def _is_anthropic_canonical(canonical: str) -> bool:
|
||||
"""Return True if ``canonical`` looks like an Anthropic provider/model."""
|
||||
c = canonical.lower()
|
||||
return "anthropic/" in c or "claude" in c
|
||||
|
||||
|
||||
class StrixModelProvider(ModelProvider):
|
||||
"""Resolves the ``strix/`` prefix.
|
||||
|
||||
The MultiProvider strips the prefix before calling ``get_model``, so we
|
||||
receive ``"claude-sonnet-4.6"`` for ``"strix/claude-sonnet-4.6"``. The
|
||||
``api_model`` (what we actually send over the wire) is always
|
||||
``openai/<base>`` against the Strix proxy (which is OpenAI-compatible).
|
||||
The ``canonical`` model name is what the upstream provider sees and is
|
||||
used to decide whether to inject Anthropic prompt caching at the message
|
||||
layer.
|
||||
|
||||
C17: unknown aliases raise ``UserError`` listing valid options instead of
|
||||
failing opaquely later in the LLM call.
|
||||
"""
|
||||
|
||||
def get_model(self, model_name: str | None) -> Model:
|
||||
if not model_name:
|
||||
raise UserError("StrixModelProvider requires a non-empty model name.")
|
||||
if model_name not in STRIX_MODEL_MAP:
|
||||
valid = ", ".join(sorted(STRIX_MODEL_MAP.keys()))
|
||||
raise UserError(
|
||||
f"Unknown Strix model alias 'strix/{model_name}'. Valid aliases: {valid}",
|
||||
)
|
||||
canonical = STRIX_MODEL_MAP[model_name]
|
||||
api_model = f"openai/{model_name}"
|
||||
if _is_anthropic_canonical(canonical):
|
||||
return AnthropicCachingLitellmModel(
|
||||
model=api_model,
|
||||
base_url=STRIX_API_BASE,
|
||||
is_anthropic_override=True,
|
||||
)
|
||||
return LitellmModel(model=api_model, base_url=STRIX_API_BASE)
|
||||
|
||||
|
||||
class LitellmAnthropicProvider(ModelProvider):
|
||||
"""Resolves the ``litellm/anthropic`` prefix.
|
||||
|
||||
The MultiProvider strips the matched prefix; for ``litellm/anthropic/...``
|
||||
with a registered provider mapping of ``"litellm/anthropic"``, the call
|
||||
arrives with ``model_name`` like ``"claude-sonnet-4-5-20250929"`` (the
|
||||
suffix after the prefix). Always wraps in the caching model.
|
||||
The SDK's ``MultiProvider`` strips the matched prefix before calling
|
||||
``get_model``, so we receive bare ``"<model>"`` (e.g.
|
||||
``"claude-sonnet-4-6"``) and re-prefix with ``anthropic/`` so litellm
|
||||
routes to the Anthropic API.
|
||||
"""
|
||||
|
||||
def get_model(self, model_name: str | None) -> Model:
|
||||
if not model_name:
|
||||
raise UserError(
|
||||
"LitellmAnthropicProvider requires a non-empty model name.",
|
||||
"Anthropic provider requires a non-empty model name (e.g. 'claude-sonnet-4-6').",
|
||||
)
|
||||
# Re-prefix for litellm so it routes to Anthropic.
|
||||
full = f"anthropic/{model_name}"
|
||||
full = model_name if model_name.startswith("anthropic/") else f"anthropic/{model_name}"
|
||||
return AnthropicCachingLitellmModel(model=full)
|
||||
|
||||
|
||||
def build_multi_provider() -> MultiProvider:
|
||||
"""Build the configured MultiProvider for Strix.
|
||||
"""Build the configured MultiProvider.
|
||||
|
||||
Registers Strix-specific prefix routes; OpenAI and other LiteLLM-prefixed
|
||||
models are handled by the SDK's built-in routing.
|
||||
Registers the ``anthropic/`` route through our caching wrapper so
|
||||
prompt caching kicks in; everything else falls through to the SDK's
|
||||
built-in routing.
|
||||
"""
|
||||
pmap = MultiProviderMap() # type: ignore[no-untyped-call]
|
||||
pmap.add_provider("strix", StrixModelProvider())
|
||||
pmap.add_provider("litellm/anthropic", LitellmAnthropicProvider())
|
||||
pmap.add_provider("anthropic", _AnthropicCachingProvider())
|
||||
return MultiProvider(provider_map=pmap)
|
||||
|
||||
Reference in New Issue
Block a user