Files
rune/tests/test_transport_selection.py
T
Nick a2463ad80b
CI Pipeline / best-practices (push) Successful in 9s
CI Pipeline / documentation (push) Successful in 4s
Auto-version and Release / release (push) Successful in 38s
CI Pipeline / canary (push) Successful in 33s
CI Pipeline / lint (push) Successful in 39s
CI Pipeline / type-check (push) Successful in 27s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / unit-tests (push) Successful in 1m2s
CI Pipeline / required-checks (push) Successful in 1s
deploy / deploy (push) Successful in 2m48s
fix(operator): approval-resume uses provider-prefix transport selection
_runtime_for_model hardcoded OllamaChatTransport, so the post-approval
follow-up model call hit localhost with the cloud-pinned name → 400
'invalid model name'. The direct turn path was fixed in 0.66.17; the resume
path now delegates to the same _transport_for authority (one selection
rule, two call sites). Red-first regression tests added.
2026-09-12 10:49:42 +01:00

97 lines
4.3 KiB
Python

"""Transport selection (T15 PL1 substrate): provider-prefix keyed, not routing_mode.
Observed live: an operator-requested model keeps routing_mode='local' (line
~887), so keying selection on routing_mode=='cloud' still sent pinned
'Verboo Code/glm-5.3-flash' to OllamaChatTransport → 400. Selection must key
on the model's provider prefix."""
import importlib.util
import sys
import tempfile
from pathlib import Path
from unittest import mock
ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT / "src"))
from rune import rune_operator # noqa: E402
from rune.openai_compat_transport import OpenAICompatTransport # noqa: E402
from rune.local_tool_runtime import OllamaChatTransport # noqa: E402
class _FakeRuntime:
def __init__(self, transport, executor, model, tools):
self.transport = transport
self.model = model
def run(self, messages, options=None):
from rune.tool_protocol import OperatorResponse
return OperatorResponse(success=True, user_text="done", model=self.model)
def _send(op, description, model):
captured = {}
class _RT(_FakeRuntime):
def __init__(self, transport, executor, model, tools):
super().__init__(transport, executor, model, tools)
captured["transport"] = transport
captured["model"] = model
with mock.patch.object(rune_operator, "LocalToolRuntime", _RT):
op.send_task(description, model=model)
return captured
def test_pinned_cloud_selects_openai_compat_transport():
"""Selection is the unit under test — config resolution (cloud_transport_for
reads the user's mimocode config, absent in CI) is mocked."""
from unittest import mock as _mock
import tempfile
op = rune_operator.RuneOperator(storage_path=str(Path(tempfile.mkdtemp()) / "op.json"))
import rune.openai_compat_transport as _oct
with _mock.patch.object(_oct, "cloud_transport_for",
side_effect=lambda model, timeout=120: OpenAICompatTransport(
"https://mock/v1", "test-key", model.split("/", 1)[0])):
captured = _send(op, "Fix the bug in /mnt/workdrive/pl1_heldout/greeting.py: returns 'Helo' not 'Hello'. Verify by running python3 /mnt/workdrive/pl1_heldout/check_greeting.py", "Verboo Code/glm-5.3-flash")
assert isinstance(captured["transport"], OpenAICompatTransport)
assert captured["model"] == "Verboo Code/glm-5.3-flash"
def test_local_model_keeps_ollama_transport():
import tempfile
op = rune_operator.RuneOperator(storage_path=str(Path(tempfile.mkdtemp()) / "op.json"))
captured = _send(op, "inspect the log for errors", "qwen2.5:3b")
assert isinstance(captured["transport"], OllamaChatTransport)
def test_bare_model_name_keeps_ollama_transport():
import tempfile
op = rune_operator.RuneOperator(storage_path=str(Path(tempfile.mkdtemp()) / "op.json"))
captured = _send(op, "inspect the log for errors", "qwen2.5:3b")
assert isinstance(captured["transport"], OllamaChatTransport)
class TestResumeTransportSelection:
"""Approval-resume path must use the SAME provider-prefix selection as
the direct turn. Observed live (PL1 Task A, 2026-09-12): after an
approval gate, the resumed turn's follow-up model call went to
OllamaChatTransport with the cloud-pinned name → localhost 400
'invalid model name' — the direct path had been fixed in 0.66.17 but
_runtime_for_model (resume) still hardcoded Ollama."""
def test_resume_path_uses_cloud_transport_for_pinned_model(self):
import rune.openai_compat_transport as _oct
op = rune_operator.RuneOperator(
storage_path=str(Path(tempfile.mkdtemp()) / "op.json"))
with mock.patch.object(
_oct, "cloud_transport_for",
side_effect=lambda model, timeout=120: OpenAICompatTransport(
"https://mock/v1", "test-key", model.split("/", 1)[0]),
):
rt = op._runtime_for_model("Verboo Code/glm-5.3-flash", "fix the bug")
assert isinstance(rt.transport, OpenAICompatTransport), type(rt.transport)
def test_resume_path_keeps_ollama_for_local_model(self):
op = rune_operator.RuneOperator(
storage_path=str(Path(tempfile.mkdtemp()) / "op.json"))
rt = op._runtime_for_model("qwen2.5:3b", "inspect the log")
assert isinstance(rt.transport, OllamaChatTransport), type(rt.transport)