Files
opensquilla--opensquilla/tests/test_engine/test_runtime_ensemble_credential_guard.py
2026-07-13 13:12:33 +08:00

291 lines
8.9 KiB
Python

from __future__ import annotations
from collections.abc import AsyncIterator
from typing import Any
import pytest
from opensquilla.engine.runtime import TurnRunner
from opensquilla.gateway.config import GatewayConfig, SquillaRouterConfig
from opensquilla.provider import ChatConfig, EnsembleProvider, Message
from opensquilla.provider.selector import ProviderConfig
class _Provider:
provider_name = "fake"
def chat(
self,
messages: list[Message],
tools: list[Any] | None = None,
config: ChatConfig | None = None,
) -> AsyncIterator[Any]:
raise AssertionError("credential-guard tests must not start provider chat")
async def list_models(self) -> list[Any]:
return []
class _FakeSelector:
def __init__(self, *, provider: str, api_key: str) -> None:
self._cfg = ProviderConfig(
provider=provider,
model="base-model",
api_key=api_key,
base_url="https://example.invalid/api",
)
@property
def current_config(self) -> ProviderConfig:
return self._cfg
def override_model(self, model: str) -> None:
self._cfg = ProviderConfig(
provider=self._cfg.provider,
model=model,
api_key=self._cfg.api_key,
base_url=self._cfg.base_url,
proxy=self._cfg.proxy,
provider_routing=self._cfg.provider_routing,
)
def resolve(self) -> _Provider:
return _Provider()
def _static_b5_config(**ensemble_overrides: Any) -> GatewayConfig:
return GatewayConfig(
squilla_router=SquillaRouterConfig(enabled=False),
llm_ensemble={"enabled": True, **ensemble_overrides},
)
async def test_static_b5_wrap_skipped_without_openrouter_credential(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.delenv("OPENROUTER_API_KEY", raising=False)
runner = TurnRunner(provider_selector=None, config=_static_b5_config())
selector = _FakeSelector(provider="groq", api_key="sk-groq-synthetic")
single_provider = _Provider()
turn, provider = await runner._run_pipeline(
"hello",
"agent:main:test",
single_provider,
selector,
[],
"system prompt",
[],
)
# The model-override step may re-resolve a fresh single-model provider from
# the selector; the guard's contract is that no ensemble wrap happens.
assert not isinstance(provider, EnsembleProvider)
assert isinstance(provider, _Provider)
assert turn.metadata["ensemble_wrap_skipped_reason"] == (
"static_openrouter_b5_no_credential"
)
assert "ensemble_enabled" not in turn.metadata
async def test_static_b5_wraps_when_openrouter_env_key_present(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setenv("OPENROUTER_API_KEY", "sk-or-synthetic")
runner = TurnRunner(provider_selector=None, config=_static_b5_config())
selector = _FakeSelector(provider="groq", api_key="sk-groq-synthetic")
turn, provider = await runner._run_pipeline(
"hello",
"agent:main:test",
_Provider(),
selector,
[],
"system prompt",
[],
)
assert isinstance(provider, EnsembleProvider)
assert turn.metadata["ensemble_enabled"] is True
assert "ensemble_wrap_skipped_reason" not in turn.metadata
async def test_static_b5_wraps_when_active_provider_is_keyed_openrouter(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.delenv("OPENROUTER_API_KEY", raising=False)
runner = TurnRunner(provider_selector=None, config=_static_b5_config())
selector = _FakeSelector(provider="openrouter", api_key="sk-or-synthetic")
turn, provider = await runner._run_pipeline(
"hello",
"agent:main:test",
_Provider(),
selector,
[],
"system prompt",
[],
)
assert isinstance(provider, EnsembleProvider)
assert turn.metadata["ensemble_enabled"] is True
assert "ensemble_wrap_skipped_reason" not in turn.metadata
async def test_static_tokenrhythm_b5_wrap_skipped_without_tokenrhythm_credential(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.delenv("TOKENRHYTHM_API_KEY", raising=False)
# An OpenRouter key must not unlock the tokenrhythm profile.
monkeypatch.setenv("OPENROUTER_API_KEY", "sk-or-synthetic")
runner = TurnRunner(
provider_selector=None,
config=_static_b5_config(selection_mode="static_tokenrhythm_b5"),
)
selector = _FakeSelector(provider="groq", api_key="sk-groq-synthetic")
turn, provider = await runner._run_pipeline(
"hello",
"agent:main:test",
_Provider(),
selector,
[],
"system prompt",
[],
)
assert not isinstance(provider, EnsembleProvider)
assert turn.metadata["ensemble_wrap_skipped_reason"] == (
"static_tokenrhythm_b5_no_credential"
)
assert "ensemble_enabled" not in turn.metadata
async def test_static_tokenrhythm_b5_wraps_when_active_provider_is_keyed(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.delenv("TOKENRHYTHM_API_KEY", raising=False)
runner = TurnRunner(
provider_selector=None,
config=_static_b5_config(selection_mode="static_tokenrhythm_b5"),
)
selector = _FakeSelector(provider="tokenrhythm", api_key="sk-tr-synthetic")
turn, provider = await runner._run_pipeline(
"hello",
"agent:main:test",
_Provider(),
selector,
[],
"system prompt",
[],
)
assert isinstance(provider, EnsembleProvider)
assert turn.metadata["ensemble_enabled"] is True
assert "ensemble_wrap_skipped_reason" not in turn.metadata
async def test_router_dynamic_wrap_is_not_credential_gated(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.delenv("OPENROUTER_API_KEY", raising=False)
runner = TurnRunner(
provider_selector=None,
config=_static_b5_config(selection_mode="router_dynamic"),
)
selector = _FakeSelector(provider="groq", api_key="sk-groq-synthetic")
turn, provider = await runner._run_pipeline(
"hello",
"agent:main:test",
_Provider(),
selector,
[],
"system prompt",
[],
)
assert isinstance(provider, EnsembleProvider)
assert turn.metadata["ensemble_enabled"] is True
assert "ensemble_wrap_skipped_reason" not in turn.metadata
def _custom_b5_guard_config(candidates: list[dict[str, Any]]) -> GatewayConfig:
return GatewayConfig(
squilla_router=SquillaRouterConfig(enabled=False),
llm={
"provider": "groq",
"model": "base-model",
"api_key": "sk-groq-synthetic",
"base_url": "https://example.invalid/api",
},
llm_ensemble={
"enabled": True,
"selection_mode": "custom_b5",
"candidates": candidates,
},
)
async def test_custom_b5_wrap_skipped_when_a_member_credential_is_missing(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.delenv("OPENROUTER_API_KEY", raising=False)
cfg = _custom_b5_guard_config(
[
{"provider": "groq", "model": "candidate-a"},
{"provider": "openrouter", "model": "z-ai/glm-5.2"},
]
)
runner = TurnRunner(provider_selector=None, config=cfg)
selector = _FakeSelector(provider="groq", api_key="sk-groq-synthetic")
turn, provider = await runner._run_pipeline(
"hello",
"agent:main:test",
_Provider(),
selector,
[],
"system prompt",
[],
)
assert not isinstance(provider, EnsembleProvider)
assert turn.metadata["ensemble_wrap_skipped_reason"] == (
"custom_b5_not_ready:missing_credential:openrouter"
)
assert "ensemble_enabled" not in turn.metadata
async def test_custom_b5_wraps_when_every_member_resolves_a_key(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setenv("OPENROUTER_API_KEY", "sk-or-synthetic")
cfg = _custom_b5_guard_config(
[
{"provider": "groq", "model": "candidate-a", "role": "primary"},
{"provider": "openrouter", "model": "z-ai/glm-5.2", "role": "contrast"},
{"provider": "groq", "model": "fuser", "role": "aggregator"},
]
)
runner = TurnRunner(provider_selector=None, config=cfg)
selector = _FakeSelector(provider="groq", api_key="sk-groq-synthetic")
turn, provider = await runner._run_pipeline(
"hello",
"agent:main:test",
_Provider(),
selector,
[],
"system prompt",
[],
)
assert isinstance(provider, EnsembleProvider)
assert provider.profile_name == "custom_b5"
assert [member.label for member in provider.proposers] == ["primary", "contrast"]
assert provider.aggregator.provider_config.model == "fuser"
assert turn.metadata["ensemble_enabled"] is True
assert "ensemble_wrap_skipped_reason" not in turn.metadata