From f072685a696d362103915a79c8d6b3de48b28be7 Mon Sep 17 00:00:00 2001 From: jenkins Date: Sat, 15 Aug 2026 04:07:30 -0300 Subject: [PATCH] hermes: resolve durable lane model ids --- services/hermes/scripts/cli_lane_runner.py | 18 ++++- testing/tests/test_hermes_cli_lane_routing.py | 81 +++++++++++++++++++ 2 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 testing/tests/test_hermes_cli_lane_routing.py diff --git a/services/hermes/scripts/cli_lane_runner.py b/services/hermes/scripts/cli_lane_runner.py index 5faa2351..d1116626 100644 --- a/services/hermes/scripts/cli_lane_runner.py +++ b/services/hermes/scripts/cli_lane_runner.py @@ -169,10 +169,26 @@ def select_route( with open_request(request, timeout=60) as response: selected = str(response.headers.get("x-model-router-selected-model") or "") rationale = str(response.headers.get("x-model-router-rationale") or "") - response.read() + response_body = response.read() except (OSError, urllib.error.URLError) as exc: raise RuntimeError(f"Switchyard worker routing failed: {exc}") from exc provider, model, effort = _decode_worker_target(selected) + # Switchyard preserves the stable tier target in the selection header and + # top-level response model. The worker broker's assistant content contains + # the steward-resolved provider model required by the native CLI. + try: + response_document = json.loads(response_body) + resolved_target = str(response_document["choices"][0]["message"]["content"] or "") + resolved_provider, resolved_model, resolved_effort = _decode_worker_target(resolved_target) + required_prefix = "gpt-" if provider == "codex" else "claude-" + if ( + resolved_provider == provider + and resolved_effort == effort + and resolved_model.startswith(required_prefix) + ): + model = resolved_model + except (AttributeError, IndexError, KeyError, RuntimeError, TypeError, ValueError, json.JSONDecodeError): + pass if exclude_provider and provider == exclude_provider: raise RuntimeError( f"Switchyard selected excluded provider {exclude_provider} for retry" diff --git a/testing/tests/test_hermes_cli_lane_routing.py b/testing/tests/test_hermes_cli_lane_routing.py new file mode 100644 index 00000000..5aac2f4e --- /dev/null +++ b/testing/tests/test_hermes_cli_lane_routing.py @@ -0,0 +1,81 @@ +"""Regression tests for durable Hermes worker-route model resolution.""" + +from __future__ import annotations + +import importlib.util +import json +import sys +from pathlib import Path + + +SCRIPT = ( + Path(__file__).parents[2] / "services/hermes/scripts/cli_lane_runner.py" +) +SPEC = importlib.util.spec_from_file_location("cli_lane_routing", SCRIPT) +assert SPEC and SPEC.loader +lanes = importlib.util.module_from_spec(SPEC) +sys.modules[SPEC.name] = lanes +SPEC.loader.exec_module(lanes) + + +class SwitchyardResponse: + """Return a tier header and independently resolved broker content.""" + + def __init__(self, selected: str, resolved_target: str): + self.headers = { + "x-model-router-selected-model": selected, + "x-model-router-rationale": "test route", + } + self.resolved_target = resolved_target + + def __enter__(self): + return self + + def __exit__(self, *_args): + return False + + def read(self) -> bytes: + return json.dumps( + { + "model": self.headers["x-model-router-selected-model"], + "choices": [ + {"message": {"content": self.resolved_target}} + ], + } + ).encode() + + +def test_switchyard_tier_is_resolved_before_invoking_codex(): + """Codex receives the exact account-visible ID, not a tier shorthand.""" + route = lanes.select_route( + "Repair the failing implementation.", + "cli-auto", + open_request=lambda *_args, **_kwargs: SwitchyardResponse( + "worker/codex/terra/xhigh", + "worker/codex/gpt-5.6-terra/xhigh", + ), + ) + + assert (route.provider, route.model, route.effort) == ( + "codex", + "gpt-5.6-terra", + "xhigh", + ) + + +def test_mismatched_broker_resolution_cannot_change_route_decision(): + """Resolved content cannot change Switchyard's provider or effort.""" + route = lanes.select_route( + "Repair it.", + "cli-auto", + open_request=lambda *_args, **_kwargs: SwitchyardResponse( + "worker/codex/terra/xhigh", + "worker/claude/claude-opus-5/high", + ), + ) + + assert (route.provider, route.model, route.effort) == ( + "codex", + "terra", + "xhigh", + )