/ tests / gateway / test_session_info.py
test_session_info.py
  1  """Tests for GatewayRunner._format_session_info — session config surfacing."""
  2  
  3  import pytest
  4  from unittest.mock import patch, MagicMock
  5  from pathlib import Path
  6  
  7  from gateway.run import GatewayRunner
  8  
  9  
 10  @pytest.fixture()
 11  def runner():
 12      """Create a bare GatewayRunner without __init__."""
 13      return GatewayRunner.__new__(GatewayRunner)
 14  
 15  
 16  def _patch_info(tmp_path, config_yaml, model, runtime):
 17      """Return a context-manager stack that patches _format_session_info deps."""
 18      cfg_path = tmp_path / "config.yaml"
 19      if config_yaml is not None:
 20          cfg_path.write_text(config_yaml)
 21      return (
 22          patch("gateway.run._hermes_home", tmp_path),
 23          patch("gateway.run._resolve_gateway_model", return_value=model),
 24          patch("gateway.run._resolve_runtime_agent_kwargs", return_value=runtime),
 25      )
 26  
 27  
 28  class TestFormatSessionInfo:
 29  
 30      def test_includes_model_name(self, runner, tmp_path):
 31          p1, p2, p3 = _patch_info(tmp_path, "model:\n  default: anthropic/claude-opus-4.6\n  provider: openrouter\n",
 32                                    "anthropic/claude-opus-4.6",
 33                                    {"provider": "openrouter", "base_url": "https://openrouter.ai/api/v1", "api_key": "k"})
 34          with p1, p2, p3:
 35              info = runner._format_session_info()
 36          assert "claude-opus-4.6" in info
 37  
 38      def test_includes_provider(self, runner, tmp_path):
 39          p1, p2, p3 = _patch_info(tmp_path, "model:\n  default: test-model\n  provider: openrouter\n",
 40                                    "test-model",
 41                                    {"provider": "openrouter", "base_url": "", "api_key": ""})
 42          with p1, p2, p3:
 43              info = runner._format_session_info()
 44          assert "openrouter" in info
 45  
 46      def test_config_context_length(self, runner, tmp_path):
 47          p1, p2, p3 = _patch_info(tmp_path, "model:\n  default: test-model\n  context_length: 32768\n",
 48                                    "test-model",
 49                                    {"provider": "custom", "base_url": "", "api_key": ""})
 50          with p1, p2, p3:
 51              info = runner._format_session_info()
 52          assert "32K" in info
 53          assert "config" in info
 54  
 55      def test_default_fallback_hint(self, runner, tmp_path):
 56          p1, p2, p3 = _patch_info(tmp_path, "model:\n  default: unknown-model-xyz\n",
 57                                    "unknown-model-xyz",
 58                                    {"provider": "", "base_url": "", "api_key": ""})
 59          with p1, p2, p3:
 60              info = runner._format_session_info()
 61          assert "256K" in info
 62          assert "model.context_length" in info
 63  
 64      def test_local_endpoint_shown(self, runner, tmp_path):
 65          p1, p2, p3 = _patch_info(
 66              tmp_path,
 67              "model:\n  default: qwen3:8b\n  provider: custom\n  base_url: http://localhost:11434/v1\n  context_length: 8192\n",
 68              "qwen3:8b",
 69              {"provider": "custom", "base_url": "http://localhost:11434/v1", "api_key": ""})
 70          with p1, p2, p3:
 71              info = runner._format_session_info()
 72          assert "localhost:11434" in info
 73          assert "8K" in info
 74  
 75      def test_cloud_endpoint_hidden(self, runner, tmp_path):
 76          p1, p2, p3 = _patch_info(tmp_path, "model:\n  default: test-model\n  provider: openrouter\n",
 77                                    "test-model",
 78                                    {"provider": "openrouter", "base_url": "https://openrouter.ai/api/v1", "api_key": "k"})
 79          with p1, p2, p3:
 80              info = runner._format_session_info()
 81          assert "Endpoint" not in info
 82  
 83      def test_million_context_format(self, runner, tmp_path):
 84          p1, p2, p3 = _patch_info(tmp_path, "model:\n  default: test-model\n  context_length: 1000000\n",
 85                                    "test-model",
 86                                    {"provider": "", "base_url": "", "api_key": ""})
 87          with p1, p2, p3:
 88              info = runner._format_session_info()
 89          assert "1.0M" in info
 90  
 91      def test_missing_config(self, runner, tmp_path):
 92          """No config.yaml should not crash."""
 93          p1, p2, p3 = _patch_info(tmp_path, None,  # don't create config
 94                                    "anthropic/claude-sonnet-4.6",
 95                                    {"provider": "openrouter", "base_url": "", "api_key": ""})
 96          with p1, p2, p3:
 97              info = runner._format_session_info()
 98          assert "Model" in info
 99          assert "Context" in info
100  
101      def test_runtime_resolution_failure_doesnt_crash(self, runner, tmp_path):
102          """If runtime resolution raises, should still produce output."""
103          cfg_path = tmp_path / "config.yaml"
104          cfg_path.write_text("model:\n  default: test-model\n  context_length: 4096\n")
105          with patch("gateway.run._hermes_home", tmp_path), \
106               patch("gateway.run._resolve_gateway_model", return_value="test-model"), \
107               patch("gateway.run._resolve_runtime_agent_kwargs", side_effect=RuntimeError("no creds")):
108              info = runner._format_session_info()
109          assert "4K" in info
110          assert "config" in info