"""Claude Code and opencode usage, relayed from llm-cost-dashboard's API. Everything here is read-only. The dashboard stays the owner of the data and the pricing; deck-it only renders it. """ import json import urllib.request from ..module import Module ENDPOINTS = ("/api/claude_limits", "/api/claude_session", "/api/summary") def _fetch_for(base): def fetch(endpoint): with urllib.request.urlopen(base + endpoint, timeout=2) as r: return json.loads(r.read()) return fetch def _opencode(rows) -> dict: """Aggregate /api/summary's per-model rows into opencode's cost and tokens.""" picked = [r for r in rows if isinstance(r, dict) and r.get("program") == "opencode"] models = [ {"provider": r.get("provider") or "", "model": r.get("model") or "", "cost": r.get("total_cost_usd") or 0, "tokens": r.get("tokens") or 0, "calls": r.get("calls") or 0} for r in picked ] models.sort(key=lambda r: r["cost"], reverse=True) return { "cost": round(sum(r["cost"] for r in models), 4), "tokens": sum(r["tokens"] for r in models), "calls": sum(r["calls"] for r in models), "models": models, } def make(cfg: dict) -> Module: base = cfg.get("llm", {}).get("url", "http://127.0.0.1:8420").rstrip("/") fetch = cfg.get("fetch") or _fetch_for(base) def state(): try: data = {ep: fetch(ep) for ep in ENDPOINTS} except (OSError, ValueError): return {"offline": True} limits = data["/api/claude_limits"] if isinstance(limits, dict): latest = limits.get("latest") or {} elif isinstance(limits, list) and limits: latest = limits[-1] else: latest = {} return { "offline": False, "claude": { "context_pct": latest.get("context_pct"), "five_hour_pct": latest.get("five_hour_pct"), "five_hour_resets_at": latest.get("five_hour_resets_at"), "seven_day_pct": latest.get("seven_day_pct"), "seven_day_resets_at": latest.get("seven_day_resets_at"), "extra_used": latest.get("extra_used_credits"), "extra_limit": latest.get("extra_monthly_limit"), "extra_utilization": latest.get("extra_utilization"), "extra_currency": latest.get("extra_currency"), }, "opencode": _opencode(data.get("/api/summary") or []), } return Module(name="llm", title="LLM usage", state=state)