Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions config.live.lua
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,16 @@ return {
auth_env = "OPENROUTER_API_KEY",
tier = "marketplace",
market_price_cap = { input = 1000, output = 1000 },
-- OpenRouter marketplace rows default `vendor/model` to the
-- provider-neutral family `model`, while wire_model_id keeps the
-- exact OpenRouter slug. Keep this map only for the canonicalization
-- exceptions where stripping the vendor isn't the right family
-- (dated or suffixed slugs).
service_aliases = {
["anthropic/claude-opus-4.8"] = "claude-opus-4-8",
["google/gemma-3-27b-it"] = "gemma-3-27b",
["qwen/qwen3-235b-a22b-2507"] = "qwen3-235b-a22b",
},
},
-- AntSeed buyer proxies: candidates and prices come from the live
-- peer market (sources/antseed.py reads the /market dump and feeds
Expand Down
2 changes: 1 addition & 1 deletion core
43 changes: 37 additions & 6 deletions sources/openrouter.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,21 @@ def __init__(self, catalog: dict, env_get=os.environ.get,
# sync hook — offers_sync runs inside rank, so it must not rebuild the
# whole catalog per call. Empty until the first refresh populates it.
self._offers: list[dict] = []
# provider_model_id -> curated family, from the catalog's served_by
providers = catalog.get("providers") or {}
market_cfg = providers.get("openrouter_market") or {}
self._market_aliases: dict[str, str] = {
str(raw): str(family)
for aliases in (
market_cfg.get("service_aliases") or {},
market_cfg.get("model_aliases") or {},
)
for raw, family in aliases.items()
if raw and family
}
# provider_model_id -> curated family, from the catalog's served_by.
# Static curated routes keep the provider id `openrouter`; dynamic
# marketplace routes use `openrouter_market` and may alias raw model ids
# to policy-facing families below.
self._family_by_id: dict[str, str] = {}
for family, model in (catalog.get("models") or {}).items():
for served in model.get("served_by") or []:
Expand Down Expand Up @@ -125,12 +139,16 @@ def _offer_for(self, m: dict) -> dict | None:
caps["supports_seed"] = True
if traits.get("in_image"):
caps["supports_vision"] = True
family = self._market_family_for(mid)
return {
# the raw OpenRouter id IS the family. NOT a second-class "uncurated"
# row: it carries the full live model_meta (benchmarks/modalities/caps
# + ranks) inline as `traits`, so it ranks on real benchmark just like
# a curated family — config.live.lua's mfield reads c.offer.traits.
"model_family": mid,
# The policy-facing family is provider-agnostic by default:
# `openai/gpt-5-mini` -> `gpt-5-mini`. Exact provider-local aliases
# handle cases where the OpenRouter tail is not the canonical family
# we want, while wire_model_id preserves the actual provider slug.
# Either way this is not a second-class "uncurated" row: it carries
# full live model_meta inline as `traits`, so it ranks on real
# benchmark just like a curated family.
"model_family": family,
"wire_model_id": mid,
"seller_endpoint": self._base_url,
"price_in_usd_per_mtok": price_in,
Expand All @@ -141,6 +159,19 @@ def _offer_for(self, m: dict) -> dict | None:
"quality_hint": None,
}

def _market_family_for(self, model_id: str) -> str:
"""Policy-facing family for an OpenRouter marketplace model.

OpenRouter ids are provider-scoped (`vendor/model`). Router policies are
provider-agnostic, so the default family is the model part. Exact aliases
override this only for canonicalization exceptions such as dated or
provider-specific suffixes.
"""
alias = self._market_aliases.get(model_id)
if alias:
return alias
return model_id.rsplit("/", 1)[-1]

def offers_sync(self, provider_id: str) -> list[dict]:
"""Whole live OpenRouter catalog as marketplace offers (the long tail
beyond the curated families). Read from the cached /models snapshot the
Expand Down
71 changes: 59 additions & 12 deletions tests/test_sources.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
},
}


class FakeHost:
def __init__(self):
self.pushed = []
Expand Down Expand Up @@ -224,8 +223,8 @@ def test_openrouter_discovery_offers_carry_full_live_traits():
asyncio.run(s.pricing()) # populates the snapshot + live traits
offers = {o["model_family"]: o for o in s.offers_sync("openrouter_market")}
# curated family skipped (no dup); non-numeric pricing skipped
assert set(offers) == {"z-ai/glm-5.2", "acme/cheap-7b"}
glm = offers["z-ai/glm-5.2"]
assert set(offers) == {"glm-5.2", "cheap-7b"}
glm = offers["glm-5.2"]
assert glm["wire_model_id"] == "z-ai/glm-5.2"
assert glm["seller_endpoint"].endswith("openrouter.ai/api/v1")
assert round(glm["price_in_usd_per_mtok"], 4) == 0.4
Expand All @@ -237,17 +236,65 @@ def test_openrouter_discovery_offers_carry_full_live_traits():
assert t["cap_tools"] is True and t["cap_reasoning"] is True
# ranks are dynamic, across the live catalog (glm beats the weaker cheap-7b)
assert t["bench_intelligence_rank"] == 1
assert offers["acme/cheap-7b"]["traits"]["bench_intelligence_rank"] == 2
assert offers["cheap-7b"]["traits"]["bench_intelligence_rank"] == 2


def test_openrouter_discovery_derives_policy_families_from_raw_model_ids():
from sources.openrouter import OpenRouterSource

catalog = {
"providers": {
"openrouter": {"auth_env": "OPENROUTER_API_KEY"},
"openrouter_market": {
"discovery": "marketplace",
"discovery_id": "openrouter_market",
"service_aliases": {
"qwen/qwen3-235b-a22b-2507": "qwen3-235b-a22b",
},
},
},
"models": {
"gpt-5.5": {"served_by": [
{"provider": "openrouter", "provider_model_id": "openai/gpt-5.5"},
]},
},
}
body = {"data": [
{"id": "openai/gpt-5.5", "pricing": {
"prompt": "0.000005", "completion": "0.00003"}},
{"id": "openai/gpt-5-mini", "pricing": {
"prompt": "0.00000025", "completion": "0.000002"}},
{"id": "meta-llama/llama-4-maverick", "pricing": {
"prompt": "0.0000002", "completion": "0.0000006"}},
{"id": "unknown/raw-family", "pricing": {
"prompt": "0.0000001", "completion": "0.0000001"}},
{"id": "qwen/qwen3-235b-a22b-2507", "pricing": {
"prompt": "0.0000005", "completion": "0.000001"}},
]}
s = OpenRouterSource(catalog, env_get={"OPENROUTER_API_KEY": "sk-test"}.get,
client=FakeClient({"/models": FakeResponse(200, body)}))

asyncio.run(s.pricing())

offers = {o["model_family"]: o for o in s.offers_sync("openrouter_market")}
assert set(offers) == {
"gpt-5-mini", "llama-4-maverick", "raw-family", "qwen3-235b-a22b"}
assert offers["gpt-5-mini"]["wire_model_id"] == "openai/gpt-5-mini"
assert offers["llama-4-maverick"]["wire_model_id"] == "meta-llama/llama-4-maverick"
assert offers["raw-family"]["wire_model_id"] == "unknown/raw-family"
assert offers["qwen3-235b-a22b"]["wire_model_id"] == "qwen/qwen3-235b-a22b-2507"
assert "openai/gpt-5-mini" not in offers
assert "gpt-5.5" not in offers # curated static OpenRouter route stays deduped


def test_openrouter_market_book_exposes_meta_for_dashboard():
s = _or_source({"/models": FakeResponse(200, OR_DISCOVERY_BODY)})
asyncio.run(s.pricing())
book = s.market_book()
fams = {r["model_family"]: r for r in book["rows"]}
assert set(fams) == {"z-ai/glm-5.2", "acme/cheap-7b"}
assert fams["z-ai/glm-5.2"]["source"] == "openrouter"
assert book["families"]["z-ai/glm-5.2"]["meta"]["bench_intelligence"] == 0.6
assert set(fams) == {"glm-5.2", "cheap-7b"}
assert fams["glm-5.2"]["source"] == "openrouter"
assert book["families"]["glm-5.2"]["meta"]["bench_intelligence"] == 0.6


def test_openrouter_model_meta_still_keyed_by_curated_family():
Expand All @@ -263,19 +310,19 @@ def test_openrouter_discovery_rejects_negative_priced_models():
# negative = "cheapest") and bill a NEGATIVE cost. Free ($0) models stay.
body = {"data": [
{"id": "z-ai/glm-5.2", "pricing": {"prompt": "0.0000004", "completion": "0.0000016"}},
{"id": "free/model", "pricing": {"prompt": "0", "completion": "0"}},
{"id": "free/free-model", "pricing": {"prompt": "0", "completion": "0"}},
{"id": "junk/sentinel", "pricing": {"prompt": "-1", "completion": "-1"}},
{"id": "junk/neg-out", "pricing": {"prompt": "0.000001", "completion": "-0.5"}},
]}
s = _or_source({"/models": FakeResponse(200, body)})
prices = asyncio.run(s.pricing()) # populates the snapshot + offers cache
# discovery offers: negatives gone, the $0 free model kept
assert {o["model_family"] for o in s.offers_sync("openrouter_market")} == \
{"z-ai/glm-5.2", "free/model"}
{"glm-5.2", "free-model"}
# the curated price-enrichment list (pricing()) also drops negatives
served = {p["served_model_id"] for p in prices}
assert "junk/sentinel" not in served and "junk/neg-out" not in served
assert {"z-ai/glm-5.2", "free/model"} <= served
assert {"z-ai/glm-5.2", "free/free-model"} <= served


def test_openrouter_discovery_stamps_capability_flags_for_meets_req():
Expand All @@ -294,13 +341,13 @@ def test_openrouter_discovery_stamps_capability_flags_for_meets_req():
s = _or_source({"/models": FakeResponse(200, body)})
asyncio.run(s.pricing())
offers = {o["model_family"]: o for o in s.offers_sync("openrouter_market")}
caps = offers["z-ai/glm-5.2"]["capabilities"]
caps = offers["glm-5.2"]["capabilities"]
assert caps.get("supports_tools") is True
assert caps.get("supports_json_mode") is True
assert caps.get("supports_seed") is True
assert caps.get("supports_vision") is True
# a model that does not declare tools must NOT claim the capability
assert "supports_tools" not in offers["plain/text-only"]["capabilities"]
assert "supports_tools" not in offers["text-only"]["capabilities"]


def test_pushed_price_lands_in_dump_state():
Expand Down