"""Pricing — convert token usage into credit cost. Model: 1 credit = $0.0001 (decision 2A). Each model carries an optional `price` field in models.json = USD per 1M OUTPUT tokens. Input is priced at 1/3 of output (the industry-standard ratio). Models without a `price` use a default. Because our upstreams are free (subnet + OR :free + Gemini free-tier), the price we set is pure margin — we publish competitive rates well under OpenAI/Anthropic. """ from __future__ import annotations CRENTS_PER_USD = 10_000 # 1 credit = $0.0001 → $1 = 10,000 credits DEFAULT_PRICE_OUT = 1.0 # USD per 1M output tokens (fallback when model lacks `price`) INPUT_RATIO = 1 / 3 # input tokens cost 1/3 of output tokens def is_free_model(model_name: str) -> bool: """True if the model is billed at ZERO credits (the `free:` prefix tier). These models run on unlimited/free upstreams and are explicitly free for the user — no balance required, no burn. Claude (no prefix) models are still paid. """ return bool(model_name) and model_name.startswith("free:") # client-facing prefix def price_per_1m_out(models: dict, model_name: str) -> float: """Look up a model's published price (USD / 1M output tokens).""" cfg = models.get(model_name) or {} return float(cfg.get("price", DEFAULT_PRICE_OUT)) def cost_credits(models: dict, model_name: str, tok_in: int, tok_out: int) -> int: """Compute the credit cost of one request. `free:` models cost nothing.""" if is_free_model(model_name): # free tier — never charges credits return 0 # totally free: no burn, no balance needed out_price = price_per_1m_out(models, model_name) # USD per 1M output tokens in_price = out_price * INPUT_RATIO # USD per 1M input tokens usd = (tok_in * in_price + tok_out * out_price) / 1_000_000 # total USD credits = round(usd * CRENTS_PER_USD) # convert to integer credits return max(credits, 1) if (tok_in or tok_out) else 0 # ≥1 if any tokens, 0 if none def credits_to_usd(credits: int) -> float: """Convert a credit balance back to USD (for dashboard display).""" return round(credits / CRENTS_PER_USD, 4)