Zum Inhalt

tests/test_preflight.py

from touchstone.config import ModelSpec
from touchstone.preflight import preflight_models
from touchstone.runner import StreamEvent


class _FakeClient:
    engine = "fake"
    engine_version = "0"

    def __init__(self, mode):
        self.mode = mode  # "content" | "reasoning" | "empty" | "boom"

    def stream(self, *, messages, model, max_tokens, temperature, seed, extra_body=None):
        if self.mode == "boom":
            raise RuntimeError("model not found")
        if self.mode == "content":
            yield StreamEvent(delta_text="4")
        if self.mode == "reasoning":
            yield StreamEvent(reasoning_text="denke…")
        yield StreamEvent(prompt_tokens=3, completion_tokens=1)


class _MultiModeClient:
    """Yields a different mode per stream() call, in order — to test that preflight_models
    processes every model independently (no short-circuit after the first)."""

    engine = "fake"
    engine_version = "0"

    def __init__(self, modes):
        self._modes = list(modes)
        self._i = 0

    def stream(self, *, messages, model, max_tokens, temperature, seed, extra_body=None):
        mode = self._modes[self._i]
        self._i += 1
        if mode == "content":
            yield StreamEvent(delta_text="4")
        if mode == "reasoning":
            yield StreamEvent(reasoning_text="denke…")
        yield StreamEvent(prompt_tokens=3, completion_tokens=1)


def _budget(_m):
    return 64


def test_preflight_classifies_content():
    [r] = preflight_models(_FakeClient("content"), [ModelSpec(id="m")], budget_for=_budget)
    assert (r.status, r.model) == ("ok", "m")


def test_preflight_classifies_reasoning_only():
    [r] = preflight_models(_FakeClient("reasoning"), [ModelSpec(id="m")], budget_for=_budget)
    assert r.status == "reasoning_only"
    assert r.reasoning_chars > 0


def test_preflight_classifies_empty():
    [r] = preflight_models(_FakeClient("empty"), [ModelSpec(id="m")], budget_for=_budget)
    assert r.status == "empty"


def test_preflight_never_raises_on_error():
    [r] = preflight_models(_FakeClient("boom"), [ModelSpec(id="m")], budget_for=_budget)
    assert r.status == "error"
    assert "not found" in r.detail


def test_preflight_processes_all_models_independently():
    results = preflight_models(
        _MultiModeClient(["content", "reasoning"]),
        [ModelSpec(id="a"), ModelSpec(id="b")],
        budget_for=_budget,
    )
    assert [r.model for r in results] == ["a", "b"]
    assert results[0].status == "ok"
    assert results[1].status == "reasoning_only"