mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-29 18:46:59 +00:00
fix: align Gemini billing pricing with provider catalog
This commit is contained in:
parent
ecebff82d2
commit
26dd976fbe
2 changed files with 88 additions and 27 deletions
|
|
@ -518,7 +518,6 @@ _OFFICIAL_DOCS_PRICING: Dict[tuple[str, str], PricingEntry] = {
|
|||
input_cost_per_million=Decimal("1.50"),
|
||||
output_cost_per_million=Decimal("9.00"),
|
||||
cache_read_cost_per_million=Decimal("0.15"),
|
||||
cache_write_cost_per_million=Decimal("1.50"),
|
||||
source="official_docs_snapshot",
|
||||
source_url="https://ai.google.dev/pricing",
|
||||
pricing_version="google-pricing-2026-07-07",
|
||||
|
|
@ -530,7 +529,6 @@ _OFFICIAL_DOCS_PRICING: Dict[tuple[str, str], PricingEntry] = {
|
|||
input_cost_per_million=Decimal("2.00"),
|
||||
output_cost_per_million=Decimal("12.00"),
|
||||
cache_read_cost_per_million=Decimal("0.20"),
|
||||
cache_write_cost_per_million=Decimal("2.00"),
|
||||
source="official_docs_snapshot",
|
||||
source_url="https://ai.google.dev/pricing",
|
||||
pricing_version="google-pricing-2026-07-07",
|
||||
|
|
@ -542,7 +540,28 @@ _OFFICIAL_DOCS_PRICING: Dict[tuple[str, str], PricingEntry] = {
|
|||
input_cost_per_million=Decimal("0.25"),
|
||||
output_cost_per_million=Decimal("1.50"),
|
||||
cache_read_cost_per_million=Decimal("0.025"),
|
||||
cache_write_cost_per_million=Decimal("0.25"),
|
||||
source="official_docs_snapshot",
|
||||
source_url="https://ai.google.dev/pricing",
|
||||
pricing_version="google-pricing-2026-07-07",
|
||||
),
|
||||
(
|
||||
"google",
|
||||
"gemini-3-pro-preview",
|
||||
): PricingEntry(
|
||||
input_cost_per_million=Decimal("2.00"),
|
||||
output_cost_per_million=Decimal("12.00"),
|
||||
cache_read_cost_per_million=Decimal("0.20"),
|
||||
source="official_docs_snapshot",
|
||||
source_url="https://ai.google.dev/pricing",
|
||||
pricing_version="google-pricing-2026-07-07",
|
||||
),
|
||||
(
|
||||
"google",
|
||||
"gemini-3-flash-preview",
|
||||
): PricingEntry(
|
||||
input_cost_per_million=Decimal("0.50"),
|
||||
output_cost_per_million=Decimal("3.00"),
|
||||
cache_read_cost_per_million=Decimal("0.05"),
|
||||
source="official_docs_snapshot",
|
||||
source_url="https://ai.google.dev/pricing",
|
||||
pricing_version="google-pricing-2026-07-07",
|
||||
|
|
@ -554,7 +573,6 @@ _OFFICIAL_DOCS_PRICING: Dict[tuple[str, str], PricingEntry] = {
|
|||
input_cost_per_million=Decimal("1.25"),
|
||||
output_cost_per_million=Decimal("10.00"),
|
||||
cache_read_cost_per_million=Decimal("0.125"),
|
||||
cache_write_cost_per_million=Decimal("1.25"),
|
||||
source="official_docs_snapshot",
|
||||
source_url="https://ai.google.dev/pricing",
|
||||
pricing_version="google-pricing-2026-07-07",
|
||||
|
|
@ -566,7 +584,6 @@ _OFFICIAL_DOCS_PRICING: Dict[tuple[str, str], PricingEntry] = {
|
|||
input_cost_per_million=Decimal("0.15"),
|
||||
output_cost_per_million=Decimal("0.60"),
|
||||
cache_read_cost_per_million=Decimal("0.015"),
|
||||
cache_write_cost_per_million=Decimal("0.15"),
|
||||
source="official_docs_snapshot",
|
||||
source_url="https://ai.google.dev/pricing",
|
||||
pricing_version="google-pricing-2026-07-07",
|
||||
|
|
@ -578,7 +595,6 @@ _OFFICIAL_DOCS_PRICING: Dict[tuple[str, str], PricingEntry] = {
|
|||
input_cost_per_million=Decimal("0.10"),
|
||||
output_cost_per_million=Decimal("0.40"),
|
||||
cache_read_cost_per_million=Decimal("0.01"),
|
||||
cache_write_cost_per_million=Decimal("0.10"),
|
||||
source="official_docs_snapshot",
|
||||
source_url="https://ai.google.dev/pricing",
|
||||
pricing_version="google-pricing-2026-07-07",
|
||||
|
|
@ -920,6 +936,18 @@ for _base_56 in ("gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna"):
|
|||
]
|
||||
del _base_56
|
||||
|
||||
# The direct Gemini provider currently exposes preview IDs for these two
|
||||
# models. Keep the official snapshot keyed by both their documented stable
|
||||
# names and the provider's emitted IDs so a catalog selection is billable.
|
||||
for _alias, _canonical in {
|
||||
"gemini-3.1-pro-preview": "gemini-3.1-pro",
|
||||
"gemini-3.1-flash-lite-preview": "gemini-3.1-flash-lite",
|
||||
}.items():
|
||||
_OFFICIAL_DOCS_PRICING[("google", _alias)] = _OFFICIAL_DOCS_PRICING[
|
||||
("google", _canonical)
|
||||
]
|
||||
del _alias, _canonical
|
||||
|
||||
|
||||
def _to_decimal(value: Any) -> Optional[Decimal]:
|
||||
if value is None:
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ from agent.usage_pricing import (
|
|||
estimate_usage_cost,
|
||||
get_pricing_entry,
|
||||
normalize_usage,
|
||||
resolve_billing_route,
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -638,27 +639,59 @@ def test_deepseek_v4_flash_estimate_usage_cost():
|
|||
assert float(result.amount_usd) == 0.28
|
||||
|
||||
|
||||
def test_gemini_3_5_flash_pricing_resolved():
|
||||
"""Ensure gemini-3.5-flash pricing exists and resolves correctly."""
|
||||
entry = get_pricing_entry("gemini-3.5-flash", provider="google")
|
||||
assert entry is not None
|
||||
assert float(entry.input_cost_per_million) == 1.50
|
||||
assert float(entry.output_cost_per_million) == 9.00
|
||||
assert float(entry.cache_read_cost_per_million) == 0.15
|
||||
assert float(entry.cache_write_cost_per_million) == 1.50
|
||||
def test_gemini_catalog_models_estimate_cached_usage():
|
||||
"""Every direct-Gemini catalog model with official pricing can estimate a
|
||||
session that includes a cache hit, rather than reporting ``unknown``.
|
||||
"""
|
||||
from hermes_cli.models import _PROVIDER_MODELS
|
||||
|
||||
usage = CanonicalUsage(input_tokens=100, output_tokens=100, cache_read_tokens=100)
|
||||
results = [
|
||||
estimate_usage_cost(model, usage, provider="gemini")
|
||||
for model in _PROVIDER_MODELS["gemini"]
|
||||
]
|
||||
|
||||
assert results
|
||||
assert all(result.status == "estimated" for result in results)
|
||||
assert all(result.amount_usd is not None and result.amount_usd > 0 for result in results)
|
||||
|
||||
|
||||
def test_gemini_provider_maps_to_google():
|
||||
"""Ensure using 'gemini' as provider resolves to 'google' pricing."""
|
||||
entry = get_pricing_entry("gemini-3.5-flash", provider="gemini")
|
||||
assert entry is not None
|
||||
assert float(entry.input_cost_per_million) == 1.50
|
||||
|
||||
# Also check base URL matching
|
||||
entry_base = get_pricing_entry(
|
||||
"gemini-3.5-flash",
|
||||
provider="custom",
|
||||
base_url="https://generativelanguage.googleapis.com/v1beta",
|
||||
def test_google_and_vertex_routes_share_official_pricing_snapshot():
|
||||
"""Direct Gemini, Vertex, and Vertex's OpenAI-compatible hostname must
|
||||
all normalize to the Google official-pricing route.
|
||||
"""
|
||||
routes = (
|
||||
resolve_billing_route("model", provider="gemini"),
|
||||
resolve_billing_route("google/model", provider="vertex"),
|
||||
resolve_billing_route(
|
||||
"google/model",
|
||||
provider="custom",
|
||||
base_url="https://aiplatform.googleapis.com/v1/projects/example",
|
||||
),
|
||||
)
|
||||
assert entry_base is not None
|
||||
assert float(entry_base.input_cost_per_million) == 1.50
|
||||
|
||||
assert all(route.provider == "google" for route in routes)
|
||||
assert all(route.billing_mode == "official_docs_snapshot" for route in routes)
|
||||
|
||||
|
||||
def test_vertex_default_model_estimates_cached_usage(monkeypatch):
|
||||
"""The bundled Vertex profile's default auxiliary model must fall back to
|
||||
Google snapshot pricing when the OpenAI-compatible endpoint has no model
|
||||
metadata, including for cache-read accounting.
|
||||
"""
|
||||
from providers import get_provider_profile
|
||||
|
||||
monkeypatch.setattr(
|
||||
"agent.usage_pricing.fetch_endpoint_model_metadata",
|
||||
lambda *_args, **_kwargs: {},
|
||||
)
|
||||
vertex = get_provider_profile("vertex")
|
||||
result = estimate_usage_cost(
|
||||
vertex.default_aux_model,
|
||||
CanonicalUsage(input_tokens=100, output_tokens=100, cache_read_tokens=100),
|
||||
provider=vertex.name,
|
||||
base_url=vertex.base_url,
|
||||
)
|
||||
|
||||
assert result.status == "estimated"
|
||||
assert result.amount_usd is not None and result.amount_usd > 0
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue