"""Keep Hermes boundaries on the Atlas Switchyard routing authority.""" from __future__ import annotations import json import os from datetime import datetime, timezone from pathlib import Path from typing import Any try: from .provider_status import provider_status_text except ImportError: # Direct module loading in the small unit-test harness. from provider_status import provider_status_text try: from .hux_mode import selection as _hux_mode_selection except ImportError: try: # Direct module loading in the small unit-test harness. from hux_mode import selection as _hux_mode_selection except ImportError: # A ConfigMap rendered before hux_mode.py shipped. def _hux_mode_selection(session): # noqa: ARG001 - contract shim return None POLICY_PATH = Path("/opt/data/workspace/coordinator/route-policy.json") POLICY_VERSION = 2 SWITCHYARD_PROVIDER = "atlas-switchyard" ROUTER_PROFILE = os.environ.get("HERMES_AUTO_ROUTER_PROFILE", "").strip().lower() if ROUTER_PROFILE not in {"chat", "triage", "agent"}: ROUTER_PROFILE = ( "chat" if os.environ.get("HERMES_AUTO_ROUTER_CHAT_MODE", "0") == "1" else "agent" ) PROFILE_ROUTE = { "chat": "atlas/auto/fast", "triage": "atlas/auto/deep", "agent": "atlas/auto/balanced", } PRIORITY_ROUTE = { "fast": "atlas/auto/fast", "balanced": "atlas/auto/balanced", "deep": "atlas/auto/deep", "maximum": "atlas/auto/maximum", } AUTO_ROUTES = frozenset(PRIORITY_ROUTE.values()) MANUAL_ROUTES = frozenset( { "atlas/manual/codex/luna", "atlas/manual/codex/terra", "atlas/manual/codex/sol", "atlas/manual/codex/auto", "atlas/manual/claude/haiku", "atlas/manual/claude/fable", "atlas/manual/claude/sonnet", "atlas/manual/claude/opus", "atlas/manual/claude/auto", "atlas/manual/local/qwen-14b", } ) ALL_ROUTES = AUTO_ROUTES | MANUAL_ROUTES EFFORTS = frozenset({"none", "minimal", "low", "medium", "high", "xhigh"}) ROUTABLE_EFFORTS = frozenset({"low", "medium", "high", "xhigh"}) EXACT_MANUAL_ROUTES = frozenset( f"{route}/{effort}" for route in MANUAL_ROUTES if not route.endswith("/local/qwen-14b") for effort in ROUTABLE_EFFORTS ) ALL_REQUEST_ROUTES = ALL_ROUTES | EXACT_MANUAL_ROUTES PROVIDER_DEFAULT = { "codex": "atlas/manual/codex/auto", "claude": "atlas/manual/claude/auto", "local": "atlas/manual/local/qwen-14b", } def _load_policy() -> dict[str, Any]: """Load the small persistent UI policy without making it an authority.""" try: value = json.loads(POLICY_PATH.read_text(encoding="utf-8")) except (OSError, ValueError, TypeError): value = {} if not isinstance(value, dict): value = {} if value.get("version") != POLICY_VERSION: value = { "version": POLICY_VERSION, "mode": "auto", "auto_route": PROFILE_ROUTE[ROUTER_PROFILE], } if value.get("mode") not in {"auto", "manual"}: value["mode"] = "auto" route = str(value.get("auto_route") or "") if route not in AUTO_ROUTES: value["auto_route"] = PROFILE_ROUTE[ROUTER_PROFILE] return value def _write_policy(value: dict[str, Any]) -> None: """Persist route preference atomically inside the current workspace.""" value["version"] = POLICY_VERSION POLICY_PATH.parent.mkdir(parents=True, exist_ok=True) temporary = POLICY_PATH.with_suffix(".json.tmp") temporary.write_text( json.dumps(value, indent=2, sort_keys=True) + "\n", encoding="utf-8", ) temporary.replace(POLICY_PATH) def _runtime_agent(ctx: Any) -> Any | None: """Return the foreground agent when the hook did not provide a child.""" cli = getattr(getattr(ctx, "_manager", None), "_cli_ref", None) return getattr(cli, "agent", None) if cli is not None else None def _normalise_manual_route(provider: str, model: str = "") -> str: """Map a provider/model override to one public Switchyard route.""" provider = provider.strip().lower() model = model.strip().lower() if provider not in PROVIDER_DEFAULT: return "" if not model: return PROVIDER_DEFAULT[provider] aliases = { "codex": { "luna": "atlas/manual/codex/luna", "gpt-5.6-luna": "atlas/manual/codex/luna", "terra": "atlas/manual/codex/terra", "gpt-5.6-terra": "atlas/manual/codex/terra", "sol": "atlas/manual/codex/sol", "gpt-5.6-sol": "atlas/manual/codex/sol", }, "claude": { "haiku": "atlas/manual/claude/haiku", "claude-haiku-4-5-20251001": "atlas/manual/claude/haiku", "fable": "atlas/manual/claude/fable", "claude-fable-5": "atlas/manual/claude/fable", "sonnet": "atlas/manual/claude/sonnet", "claude-sonnet-5": "atlas/manual/claude/sonnet", "opus": "atlas/manual/claude/opus", "claude-opus-5": "atlas/manual/claude/opus", }, "local": { "qwen": "atlas/manual/local/qwen-14b", "qwen-14b": "atlas/manual/local/qwen-14b", "qwen2.5:14b-instruct-q4_0": "atlas/manual/local/qwen-14b", }, } return aliases[provider].get(model, "") def _explicit_ui_route(agent: Any) -> str: """Return an exact route selected by the WebUI or command-line caller.""" if not bool(getattr(agent, "_hermes_explicit_model_pick", False)): return "" route = str(getattr(agent, "model", "") or "").strip() return route if route in ALL_REQUEST_ROUTES else "" def _explicit_ui_effort(agent: Any) -> str: """Return an exact WebUI effort override, capped by the route catalog.""" effort = str( getattr(agent, "_hermes_explicit_reasoning_effort", "") or "" ).strip().lower() return effort if effort in EFFORTS else "" def _boundary_selection(agent: Any, session_id: str = "") -> tuple[str, str, str]: """Select only a public route; Switchyard selects the actual target.""" policy = _load_policy() ui_route = _explicit_ui_route(agent) ui_effort = _explicit_ui_effort(agent) if ui_route: mode = "auto" if ui_route in AUTO_ROUTES else "manual" if ui_route in EXACT_MANUAL_ROUTES: effort = ui_route.rsplit("/", 1)[-1] return ui_route, effort, f"ui-{mode}" return ui_route, ui_effort, f"ui-{mode}" # HUX-06: a friendly mode selected for this conversation shapes the next # request. Automatic modes stay provider-neutral pools; only private may # pin the local route. Any HUX absence or failure falls straight through. hux = _hux_mode_selection(session_id) if session_id else None if hux and hux[0] in ALL_REQUEST_ROUTES: return hux[0], ui_effort or hux[1], "hux-mode" if policy["mode"] == "manual": manual = policy.get("manual") if isinstance(manual, dict): route = str(manual.get("route") or "") effort = str(manual.get("effort") or "") if route in MANUAL_ROUTES and effort in EFFORTS: return route, ui_effort or effort, "manual" priority = str( getattr(agent, "_hermes_routing_priority", "") or "" ).strip().lower() route = PRIORITY_ROUTE.get(priority) if route: return route, ui_effort, "ui-auto" return str(policy["auto_route"]), ui_effort, "auto" def _resolved_route(route: str, effort: str) -> str: """Bind a manual family and UI effort to an exact Switchyard route.""" if route in EXACT_MANUAL_ROUTES: return route if route not in MANUAL_ROUTES or route.endswith("/local/qwen-14b"): return route provider_effort = effort if effort in ROUTABLE_EFFORTS else "low" return f"{route}/{provider_effort}" def _switch_agent(ctx: Any, agent: Any, route: str, effort: str) -> None: """Point one live Hermes agent at Switchyard and remove local failover.""" runtime_agent = _runtime_agent(ctx) cli = ( getattr(getattr(ctx, "_manager", None), "_cli_ref", None) if agent is runtime_agent else None ) if agent.provider != SWITCHYARD_PROVIDER or agent.model != route: from hermes_cli.inventory import load_picker_context from hermes_cli.model_switch import switch_model picker = load_picker_context() result = switch_model( raw_input=route, current_provider=agent.provider or "", current_model=agent.model or "", current_base_url=agent.base_url or "", current_api_key=agent.api_key or "", is_global=False, explicit_provider=SWITCHYARD_PROVIDER, user_providers=picker.user_providers, custom_providers=picker.custom_providers, ) if not result.success: raise RuntimeError(result.error_message or "Switchyard model switch failed") agent.switch_model( new_model=result.new_model, new_provider=result.target_provider, api_key=result.api_key, base_url=result.base_url, api_mode=result.api_mode, ) if cli is not None: cli.model = result.new_model cli.provider = result.target_provider cli.requested_provider = result.target_provider cli.api_key = result.api_key or cli.api_key cli.base_url = result.base_url or "" cli.api_mode = result.api_mode or cli.api_mode cli._explicit_api_key = result.api_key cli._explicit_base_url = result.base_url reasoning = None if effort: from hermes_constants import parse_reasoning_effort reasoning = parse_reasoning_effort(effort) agent.reasoning_config = reasoning if cli is not None: cli.reasoning_config = reasoning app = getattr(cli, "_app", None) if app is not None: app.invalidate() # Cross-provider recovery belongs to Switchyard. A Hermes fallback here # would create a second control plane and could bypass a manual constraint. agent._fallback_chain = [] agent._fallback_index = 0 agent._fallback_activated = False agent._fallback_model = None agent._hermes_switchyard_route = route if agent is runtime_agent: try: from agent.auxiliary_client import set_runtime_main set_runtime_main( agent.provider or "", agent.model or "", base_url=agent.base_url or "", api_key=agent.api_key or "", api_mode=agent.api_mode or "", ) except Exception: pass def _record_boundary( policy: dict[str, Any], route: str, effort: str, source: str, scope: str ) -> None: """Record the public request route without pretending it is the target.""" record = { "route": route, "effort_override": effort or None, "source": source, "scope": scope, "authority": "switchyard", "updated_at": datetime.now(timezone.utc).isoformat(), } policy["last_boundary"] = record counter = f"{scope}_boundaries_total" policy[counter] = int(policy.get(counter) or 0) + 1 _write_policy(policy) def _route_boundary(ctx: Any, scope: str, **kwargs: Any) -> None: """Route a user turn, tool continuation, or delegated child.""" agent = kwargs.get("agent") or kwargs.get("child") or _runtime_agent(ctx) if agent is None: return requested_route, effort, source = _boundary_selection( agent, str(kwargs.get("session_id") or "") ) route = _resolved_route(requested_route, effort) _switch_agent(ctx, agent, route, effort) policy = _load_policy() _record_boundary(policy, route, effort, source, scope) if scope != "turn": return emit = getattr(agent, "_emit_status", None) if callable(emit): override = f" · effort {effort}" if effort else "" emit( f"{source.upper()} via Switchyard → {route}{override} · " "target and fallback selected per boundary" ) def _pre_turn(ctx: Any, **kwargs: Any) -> None: """Route a visible user turn unless Hermes is handling a slash command.""" message = str(kwargs.get("user_message") or "").strip() if message.startswith("/"): return _route_boundary(ctx, "turn", **kwargs) def _status_text(ctx: Any) -> str: """Describe the route contract without claiming an unseen target.""" policy = _load_policy() agent = _runtime_agent(ctx) runtime = "not initialized" if agent is not None: runtime = f"{agent.provider}/{agent.model}" if policy["mode"] == "manual": manual = policy.get("manual") or {} preference = ( f"{manual.get('route', 'invalid')} at " f"{manual.get('effort', 'default')}" ) else: preference = str(policy["auto_route"]) last = policy.get("last_boundary") or {} last_text = str(last.get("route") or "none yet") return ( "Routing authority: Switchyard\n" f"Service posture: {ROUTER_PROFILE}\n" f"Mode: {policy['mode'].upper()} ({preference})\n" f"Current Hermes endpoint: {runtime}\n" f"Last public route: {last_text}\n" "Switchyard independently selects provider/model/effort and fallback " "for every model-call boundary.\n" "Commands: /route auto [fast|balanced|deep|maximum] | " "/route manual " " [model] | /route status" ) def _route_command(ctx: Any, raw_args: str) -> str: """Persist an AUTO posture or constrained Switchyard route.""" args = raw_args.strip().split() if not args or args[0].lower() == "status": return _status_text(ctx) mode = args[0].lower() policy = _load_policy() if mode == "auto": posture = args[1].lower() if len(args) > 1 else "" route = PRIORITY_ROUTE.get(posture, PROFILE_ROUTE[ROUTER_PROFILE]) if posture and posture not in PRIORITY_ROUTE: return "AUTO posture must be fast, balanced, deep, or maximum." policy = {"mode": "auto", "auto_route": route} _write_policy(policy) return "AUTO routing enabled.\n" + _status_text(ctx) if mode != "manual" or len(args) < 3: return ( "Usage: /route auto [fast|balanced|deep|maximum] | " "/route manual " " [model] | /route status" ) provider = args[1].lower() effort = args[2].lower() model = args[3] if len(args) > 3 else "" route = _normalise_manual_route(provider, model) if not route: return "Unknown provider/model combination for a Switchyard route." if effort not in EFFORTS: return "Effort must be none, minimal, low, medium, high, or xhigh." policy = { "mode": "manual", "auto_route": PROFILE_ROUTE[ROUTER_PROFILE], "manual": {"route": route, "effort": effort}, } _write_policy(policy) return "Manual Switchyard constraint enabled.\n" + _status_text(ctx) def register(ctx: Any) -> None: """Register thin boundary hooks; Switchyard owns every routing decision.""" ctx.register_hook("pre_turn_route", lambda **kwargs: _pre_turn(ctx, **kwargs)) ctx.register_hook( "pre_internal_route", lambda **kwargs: _route_boundary(ctx, "internal", **kwargs), ) try: ctx.register_hook( "pre_subagent_route", lambda **kwargs: _route_boundary(ctx, "subagent", **kwargs), ) except ValueError: pass ctx.register_command( "route", lambda raw_args: _route_command(ctx, raw_args), description="Show or constrain Switchyard AUTO routing", args_hint="auto [posture]|status|manual provider effort [model]", ) ctx.register_command( "providers", lambda _raw_args: provider_status_text(), description="Show Codex, Claude, local, and Switchyard status", )