"""Model pricing table and cost estimation. Prices are USD per 1,000,000 tokens. The table is a built-in default; a suite may extend or override entries through ``[skill_eval.pricing]`` in its config. Model lookup is a longest-substring match so that dated/suffixed model names (``claude-haiku-4-5-20251001``) still resolve to a base entry (``claude-haiku-4``). """ # USD per 1,000,000 tokens. # GitHub Models prices: https://docs.github.com/en/billing/reference/costs-for-github-models # Anthropic prices: https://www.anthropic.com/pricing DEFAULT_PRICING: dict[str, dict[str, float]] = { # GitHub Models (OpenAI) "gpt-4.1": {"input": 2.00, "output": 8.00}, "gpt-4.1-mini": {"input": 0.40, "output": 1.60}, "gpt-4o-mini": {"input": 0.15, "output": 0.60}, "gpt-4o": {"input": 2.50, "output": 10.00}, # Anthropic "claude-opus-4": {"input": 15.00, "output": 75.00}, "claude-sonnet-4": {"input": 3.00, "output": 15.00}, "claude-haiku-4": {"input": 0.80, "output": 4.00}, "claude-haiku-3": {"input": 0.80, "output": 4.00}, } def find_pricing( model_name: str, pricing: dict[str, dict[str, float]] ) -> dict[str, float] | None: """Return the pricing entry for ``model_name`` using a longest-substring match.""" best_key, best_len = None, 0 for key in pricing: if key in model_name and len(key) > best_len: best_key, best_len = key, len(key) return pricing[best_key] if best_key else None def calculate_cost( model_name: str, input_tokens: int, output_tokens: int, pricing: dict[str, dict[str, float]] | None = None, ) -> float | None: """Return the estimated USD cost, or ``None`` if the model is not in the table.""" table = pricing if pricing is not None else DEFAULT_PRICING entry = find_pricing(model_name, table) if entry is None: return None return round( input_tokens * entry["input"] / 1_000_000 + output_tokens * entry["output"] / 1_000_000, 6, )