Skip to content
Closed
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
41 changes: 41 additions & 0 deletions agent/usage_pricing.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,47 @@ class CostResult:
source_url="https://openai.com/index/previewing-gpt-5-6-sol/",
pricing_version="openai-gpt-5.6-2026-07",
),
# ── Anthropic Claude Opus 5 ──────────────────────────────────────────
# Same $5/$25 base pricing as the 4.6-4.8 line. Fast-mode variant is a
# separate model ID with 2x premium. Dated snapshot 20260723 shares
# base pricing.
# Source: https://platform.claude.com/docs/en/about-claude/pricing
(
"anthropic",
"claude-opus-5",
): PricingEntry(
input_cost_per_million=Decimal("5.00"),
output_cost_per_million=Decimal("25.00"),
cache_read_cost_per_million=Decimal("0.50"),
cache_write_cost_per_million=Decimal("6.25"),
source="official_docs_snapshot",
source_url="https://platform.claude.com/docs/en/about-claude/pricing",
pricing_version="anthropic-pricing-2026-07",
),
(
"anthropic",
"claude-opus-5-20260723",
): PricingEntry(
input_cost_per_million=Decimal("5.00"),
output_cost_per_million=Decimal("25.00"),
cache_read_cost_per_million=Decimal("0.50"),
cache_write_cost_per_million=Decimal("6.25"),
source="official_docs_snapshot",
source_url="https://platform.claude.com/docs/en/about-claude/pricing",
pricing_version="anthropic-pricing-2026-07",
),
(
"anthropic",
"claude-opus-5-fast",
): PricingEntry(
input_cost_per_million=Decimal("10.00"),
output_cost_per_million=Decimal("50.00"),
cache_read_cost_per_million=Decimal("1.00"),
cache_write_cost_per_million=Decimal("12.50"),
source="official_docs_snapshot",
source_url="https://openrouter.ai/anthropic/claude-opus-5-fast",
pricing_version="anthropic-pricing-2026-07",
),
# ── Anthropic Claude 4.8 ─────────────────────────────────────────────
# Same $5/$25 base pricing as 4.6/4.7. Fast-mode variant is a separate
# model ID with 2x premium (vs the 6x premium on older Opus generations).
Expand Down
1 change: 1 addition & 0 deletions hermes_cli/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,7 @@ def _xai_curated_models() -> list[str]:
],
"anthropic": [
"claude-fable-5",
"claude-opus-5",
"claude-sonnet-5",
"claude-opus-4-8",
"claude-opus-4-7",
Expand Down
22 changes: 22 additions & 0 deletions tests/hermes_cli/test_anthropic_picker_curated.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,28 @@ def test_anthropic_curated_alias_survives_when_live_omits_it():
assert result[:len(curated)] == list(curated)


def test_anthropic_curated_opus_5_listed_for_oauth_subscriptions():
"""Opus 5 stays in the picker when the live models endpoint 401s.

Subscription OAuth tokens are rejected by Anthropic's platform-API
/v1/models endpoint, so Claude Pro/Max users always fall back to the
curated list — it must carry the current flagship (claude-opus-5),
mirroring OPENROUTER_MODELS / opencode-zen which already list it.
"""
curated = M._PROVIDER_MODELS["anthropic"]
assert "claude-opus-5" in curated

with patch.object(M, "_fetch_anthropic_models", return_value=None):
result = M.provider_model_ids("anthropic")

assert "claude-opus-5" in result
# And when live succeeds, curated-first merge keeps it too.
live = ["claude-opus-4-8", "claude-sonnet-4-6"]
with patch.object(M, "_fetch_anthropic_models", return_value=live):
merged = M.provider_model_ids("anthropic")
assert "claude-opus-5" in merged


def test_anthropic_merge_dedupes_overlap_and_appends_live_only():
"""Models in both lists appear once; live-only models are appended."""
live = [
Expand Down