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
8 changes: 7 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ prefixes determine routing:
- **Google**: gemini-3.8-flash, gemini-3.7-flash, gemini-3.6-flash, gemini-3.5-flash, gemini-3.5-flash-lite, gemini-2.5-flash, gemini-2.5-flash-lite, gemini-2.5-pro, gemini-3-flash-preview, gemini-3.1-pro-preview; image generation: gemini-2.5-flash-image, gemini-3.1-flash-image
- **xAI**: grok-4.6, grok-4.5, grok-4.3, grok-4.20-reasoning, grok-4.20-non-reasoning; image generation: grok-2-image, grok-imagine-image-2.0
- **ByteDance** (BytePlus ModelArk, OpenAI-compatible, ap-southeast): seed-1.6, seed-1.8, seed-2.0-lite, deepseek-v4-flash, deepseek-v4-pro, glm-5.2 (Z.ai's model served via a ModelArk deployment endpoint); image generation: seedream-4.0, seedream-5.0-lite, seedance-4.5, seedance-5.0
- **OpenRouter** (OpenAI-compatible): hy4-preview, hermes-4-405b, hermes-4-70b, hy3
- **OpenRouter** (OpenAI-compatible): hy4-preview, hermes-4-405b, hy3
- **Z.ai** (Model API, OpenAI-compatible): image generation: glm-image (glm-5.2 chat is routed through BytePlus ModelArk, see ByteDance above)

Models kept registered but no longer offered to new clients — each still
Expand All @@ -149,6 +149,12 @@ provider actually bills, not at its pre-retirement rate:
repointed or retired with its snapshot; if repointed, they become mispriced
the way the xAI slugs were.

A model the provider does not serve at all is removed outright rather than
repriced — no request to it can succeed. `hermes-4-70b` went this way when
OpenRouter delisted it. For OpenRouter models, `openrouter.ai/api/v1/models`
is authoritative for availability as well as price; a pricing page keeps
quoting a rate after the endpoints are gone.

Image generation via OpenAI (gpt-image-2.5-flare, gpt-image-2.5-sunburst, gpt-image-2), xAI (grok-2-image, grok-imagine-image-2.0), ByteDance
(seedream-4.0, seedream-5.0-lite, seedance-4.5, seedance-5.0), and Z.ai (glm-image) is served
through a provider `/images/generations` endpoint rather than the chat path (see
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ The gateway solves this by running inside a hardware-isolated Nitro Enclave wher
| Google | gemini-3.8-flash, gemini-3.7-flash, gemini-3.6-flash, gemini-3.5-flash, gemini-3.5-flash-lite, gemini-2.5-flash, gemini-2.5-flash-lite, gemini-2.5-pro, gemini-3-flash-preview, gemini-3.1-pro-preview |
| xAI | grok-4.6, grok-4.5, grok-4.3, grok-4.20-reasoning, grok-4.20-non-reasoning |
| ByteDance | seed-1.6, seed-1.8, seed-2.0-lite, dola-seed-2.0-mini, deepseek-v4-flash, deepseek-v4-pro, glm-5.2 |
| OpenRouter | hy4-preview, hermes-4-405b, hermes-4-70b, hy3 |
| OpenRouter | hy4-preview, hermes-4-405b, hy3 |

Image generation: gpt-image-2, gpt-image-2.5-flare, gpt-image-2.5-sunburst,
gemini-2.5-flash-image, gemini-3.1-flash-image, grok-2-image,
Expand Down
21 changes: 9 additions & 12 deletions tee_gateway/model_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -939,25 +939,24 @@ class SupportedModel(Enum):
input_price_usd=Decimal("0.000000834"),
output_price_usd=Decimal("0.000002501"),
)
# Nous no longer serves Hermes 4 through Nous Portal, so both models route
# through their canonical OpenRouter slugs and use OpenRouter list pricing.
# Nous no longer serves Hermes 4 through Nous Portal, so it routes through
# its canonical OpenRouter slug and uses OpenRouter list pricing. Only the
# 405B is served — OpenRouter has delisted hermes-4-70b. A model's pricing
# page outlives its endpoints, so check /api/v1/models for availability
# rather than trusting a quoted rate.
HERMES_4_405B = ModelConfig(
provider="openrouter",
api_name="nousresearch/hermes-4-405b",
input_price_usd=Decimal("0.000001"),
output_price_usd=Decimal("0.000003"),
)
HERMES_4_70B = ModelConfig(
provider="openrouter",
api_name="nousresearch/hermes-4-70b",
input_price_usd=Decimal("0.00000013"),
output_price_usd=Decimal("0.0000004"),
)
# Rate from openrouter.ai/api/v1/models, which is authoritative for both
# price and availability.
HY3 = ModelConfig(
provider="openrouter",
api_name="tencent/hy3",
input_price_usd=Decimal("0.0000000825"),
output_price_usd=Decimal("0.00000033"),
input_price_usd=Decimal("0.000000132"),
output_price_usd=Decimal("0.000000528"),
)

# ── Z.ai (Model API, OpenAI-compatible) ─────────────────────────────
Expand Down Expand Up @@ -1118,8 +1117,6 @@ class SupportedModel(Enum):
# Nous Research models routed through OpenRouter
"hermes-4-405b": SupportedModel.HERMES_4_405B,
"nousresearch/hermes-4-405b": SupportedModel.HERMES_4_405B,
"hermes-4-70b": SupportedModel.HERMES_4_70B,
"nousresearch/hermes-4-70b": SupportedModel.HERMES_4_70B,
"hy3": SupportedModel.HY3,
"tencent/hy3": SupportedModel.HY3,
"tencent/hy3:floor": SupportedModel.HY3,
Expand Down
4 changes: 2 additions & 2 deletions tee_gateway/test/test_provider_usage_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ class _ProviderCase:
_ProviderCase("OpenAI", "gpt-4.1-nano", "OPENAI_API_KEY"),
_ProviderCase("Anthropic", "claude-haiku-4-5", "ANTHROPIC_API_KEY"),
_ProviderCase("Google", "gemini-3.5-flash-lite", "GOOGLE_API_KEY"),
_ProviderCase("xAI", "grok-4-fast", "XAI_API_KEY"),
_ProviderCase("xAI", "grok-4.3", "XAI_API_KEY"),
_ProviderCase("ByteDance", "deepseek-v4-flash", "ARK_API_KEY"),
_ProviderCase("OpenRouter", "hermes-4-70b", "OPENROUTER_API_KEY"),
_ProviderCase("OpenRouter", "hy3", "OPENROUTER_API_KEY"),
_ProviderCase("Z.ai", "glm-5.2", "ZAI_API_KEY"),
)

Expand Down
28 changes: 15 additions & 13 deletions tests/test_pricing.py
Original file line number Diff line number Diff line change
Expand Up @@ -578,29 +578,30 @@ def test_hermes_4_405b_resolves(self):
self.assertEqual(cfg.input_price_usd, Decimal("0.000001"))
self.assertEqual(cfg.output_price_usd, Decimal("0.000003"))

def test_hermes_4_70b_resolves(self):
cfg = get_model_config("hermes-4-70b")
self.assertEqual(cfg.provider, "openrouter")
self.assertEqual(cfg.api_name, "nousresearch/hermes-4-70b")
self.assertEqual(cfg.input_price_usd, Decimal("0.00000013"))
self.assertEqual(cfg.output_price_usd, Decimal("0.0000004"))
def test_hermes_4_70b_is_gone(self):
"""OpenRouter delisted nousresearch/hermes-4-70b.

It is absent from openrouter.ai/api/v1/models, so every request
returned "404 No endpoints found". Rejecting it here beats forwarding
a request that cannot succeed.
"""
for name in ("hermes-4-70b", "nousresearch/hermes-4-70b"):
with self.subTest(model=name):
with self.assertRaises(ValueError):
get_model_config(name)

def test_openrouter_canonical_hermes_aliases_resolve(self):
self.assertEqual(
get_model_config("nousresearch/hermes-4-405b"),
get_model_config("hermes-4-405b"),
)
self.assertEqual(
get_model_config("nousresearch/hermes-4-70b"),
get_model_config("hermes-4-70b"),
)

def test_hy3_resolves(self):
cfg = get_model_config("hy3")
self.assertEqual(cfg.provider, "openrouter")
self.assertEqual(cfg.api_name, "tencent/hy3")
self.assertEqual(cfg.input_price_usd, Decimal("0.0000000825"))
self.assertEqual(cfg.output_price_usd, Decimal("0.00000033"))
self.assertEqual(cfg.input_price_usd, Decimal("0.000000132"))
self.assertEqual(cfg.output_price_usd, Decimal("0.000000528"))
self.assertEqual(cfg, get_model_config("tencent/hy3"))
self.assertEqual(cfg, get_model_config("tencent/hy3:floor"))

Expand Down Expand Up @@ -986,9 +987,10 @@ def test_deepseek_v4_pro_cost(self):
# ── OpenRouter ─────────────────────────────────────────────────────────

def test_hy3_cost(self):
# 1000*0.000000132 + 500*0.000000528 = 0.000132 + 0.000264 = 0.000396 USD
self.assertEqual(
self._calc("hy3", 1000, 500),
247_500_000_000_000,
396_000_000_000_000,
)

def test_hy4_preview_cost(self):
Expand Down
Loading