docs/openrouter-sync-operations #1

Merged
torbjorn merged 6 commits from docs/openrouter-sync-operations into main 2026-04-01 22:01:02 +00:00
2 changed files with 54 additions and 34 deletions
Showing only changes of commit 4c4421b28f - Show all commits

View File

@@ -22,18 +22,10 @@ class OpenRouterModelRegistry(CapabilityModelRegistry):
LIVE_DEFAULT_FILENAME = "openrouter_models_live.json"
def __init__(self, config_path: str | None = None, live_config_path: str | None = None) -> None:
self._live_use_resources = False
self._live_resource = None
self._live_config_path: Path | None = None
self._live_default_path = Path(__file__).resolve().parents[3] / "conf" / self.LIVE_DEFAULT_FILENAME
super().__init__(
env_var_name="OPENROUTER_MODELS_CONFIG_PATH",
default_filename="openrouter_models.json",
provider=ProviderType.OPENROUTER,
friendly_prefix="OpenRouter ({model})",
config_path=config_path,
)
if live_config_path:
self._live_config_path = Path(live_config_path)
else:
@@ -44,13 +36,19 @@ class OpenRouterModelRegistry(CapabilityModelRegistry):
try:
resource = importlib.resources.files("conf").joinpath(self.LIVE_DEFAULT_FILENAME)
if hasattr(resource, "read_text"):
self._live_use_resources = True
self._live_resource = resource
else:
raise AttributeError("resource accessor not available")
except Exception:
self._live_config_path = self._live_default_path
self.reload()
super().__init__(
env_var_name="OPENROUTER_MODELS_CONFIG_PATH",
default_filename="openrouter_models.json",
provider=ProviderType.OPENROUTER,
friendly_prefix="OpenRouter ({model})",
config_path=config_path,
)
def reload(self) -> None:
live_data = self._load_live_config_data()
@@ -62,13 +60,12 @@ class OpenRouterModelRegistry(CapabilityModelRegistry):
self._build_maps(configs)
def _load_live_config_data(self) -> dict:
if self._live_use_resources:
if self._live_resource is not None:
try:
resource = importlib.resources.files("conf").joinpath(self.LIVE_DEFAULT_FILENAME)
if hasattr(resource, "read_text"):
config_text = resource.read_text(encoding="utf-8")
if hasattr(self._live_resource, "read_text"):
config_text = self._live_resource.read_text(encoding="utf-8")
else:
with resource.open("r", encoding="utf-8") as handle:
with self._live_resource.open("r", encoding="utf-8") as handle:
config_text = handle.read()
data = json.loads(config_text)
except FileNotFoundError:

View File

@@ -23,10 +23,14 @@ class TestOpenRouterModelRegistry:
assert len(registry.list_models()) > 0
assert len(registry.list_aliases()) > 0
def test_registry_initialization_with_live_catalogue_defaults(self):
def test_default_init_resolves_live_only_model(self):
registry = OpenRouterModelRegistry()
assert registry.list_models()
config = registry.resolve("x-ai/grok-4")
assert config is not None
assert config.model_name == "x-ai/grok-4"
assert config.context_window == 256000
assert config.supports_extended_thinking is True
def test_custom_config_path(self):
"""Test registry with custom config path."""
@@ -48,17 +52,15 @@ class TestOpenRouterModelRegistry:
try:
registry = OpenRouterModelRegistry(config_path=temp_path)
assert len(registry.list_models()) == 1
assert "test/model-1" in registry.list_models()
assert "test1" in registry.list_aliases()
assert "t1" in registry.list_aliases()
assert registry.resolve("x-ai/grok-4") is not None
finally:
os.unlink(temp_path)
def test_environment_variable_override(self):
def test_environment_variable_override(self, monkeypatch):
"""Test OPENROUTER_MODELS_CONFIG_PATH environment variable."""
original_env = os.environ.get("OPENROUTER_MODELS_CONFIG_PATH")
# Create custom config
config_data = {
"models": [
@@ -72,7 +74,7 @@ class TestOpenRouterModelRegistry:
try:
# Set environment variable
os.environ["OPENROUTER_MODELS_CONFIG_PATH"] = temp_path
monkeypatch.setenv("OPENROUTER_MODELS_CONFIG_PATH", temp_path)
# Create registry without explicit path
registry = OpenRouterModelRegistry()
@@ -82,11 +84,6 @@ class TestOpenRouterModelRegistry:
assert "envtest" in registry.list_aliases()
finally:
# Restore environment
if original_env is not None:
os.environ["OPENROUTER_MODELS_CONFIG_PATH"] = original_env
else:
del os.environ["OPENROUTER_MODELS_CONFIG_PATH"]
os.unlink(temp_path)
def test_alias_resolution(self):
@@ -202,9 +199,8 @@ class TestOpenRouterModelRegistry:
with patch.dict("os.environ", {}, clear=True):
registry = OpenRouterModelRegistry(config_path="/non/existent/path.json")
# Should initialize with empty maps
assert len(registry.list_models()) == 0
assert len(registry.list_aliases()) == 0
assert len(registry.list_models()) > 0
assert registry.resolve("x-ai/grok-4") is not None
assert registry.resolve("anything") is None
def test_invalid_json_config(self):
@@ -215,9 +211,8 @@ class TestOpenRouterModelRegistry:
try:
registry = OpenRouterModelRegistry(config_path=temp_path)
# Should handle gracefully and initialize empty
assert len(registry.list_models()) == 0
assert len(registry.list_aliases()) == 0
assert len(registry.list_models()) > 0
assert registry.resolve("x-ai/grok-4") is not None
finally:
os.unlink(temp_path)
@@ -348,6 +343,34 @@ class TestOpenRouterModelRegistry:
assert "openai/o3" in registry.list_models()
assert registry.resolve("o3") is not None
def test_invalid_live_json_keeps_curated_models_working(self):
curated_data = {
"models": [
{
"model_name": "openai/gpt-5.2",
"aliases": ["gpt5.2"],
"context_window": 400000,
"max_output_tokens": 128000,
}
]
}
with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as curated_file:
json.dump(curated_data, curated_file)
curated_path = curated_file.name
with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as live_file:
live_file.write("{ invalid json }")
live_path = live_file.name
try:
registry = OpenRouterModelRegistry(config_path=curated_path, live_config_path=live_path)
assert "openai/gpt-5.2" in registry.list_models()
assert registry.resolve("gpt5.2") is not None
finally:
os.unlink(curated_path)
os.unlink(live_path)
def test_model_with_all_capabilities(self):
"""Test model with all capability flags."""
from providers.shared import TemperatureConstraint