chopratejas--headroom
0ef5fcb1c5
Security / Dependency audit (pip-audit) (push) Has been cancelled
Security / CodeQL (javascript-typescript) (push) Has been cancelled
Security / CodeQL (python) (push) Has been cancelled
Security / Secret scan (gitleaks) (push) Has been cancelled
rust / test (ubuntu) (push) Has been cancelled
rust / simulator e2e (macos-latest) (push) Has been cancelled
rust / simulator e2e (ubuntu-latest) (push) Has been cancelled
rust / simulator e2e (windows-latest) (push) Has been cancelled
rust / wheels (aarch64-apple-darwin) (push) Has been cancelled
rust / wheels (x86_64-unknown-linux-gnu) (push) Has been cancelled
rust / wheels (x86_64-apple-darwin) (push) Has been cancelled
rust / audit (push) Has been cancelled
rust / parity (nightly, allowed to fail during Phase 0) (push) Has been cancelled
CI / commitlint (push) Has been skipped
Dev Containers / validate (.devcontainer/devcontainer.json, default) (push) Failing after 0s
Dev Containers / validate (.devcontainer/memory-stack/devcontainer.json, memory-stack) (push) Failing after 0s
Dev Containers / validate-worktree (push) Failing after 0s
CI / changes (push) Failing after 4s
Deploy Documentation / validate (push) Has been skipped
Deploy Documentation / deploy (push) Failing after 1s
Init Native E2E / init-native (ubuntu-latest, claude) (push) Failing after 1s
Init Native E2E / init-native (ubuntu-latest, codex) (push) Failing after 1s
Install Native E2E / install-native (ubuntu-latest) (push) Failing after 1s
OpenCode Plugin / typecheck + build + test (push) Failing after 1s
Init Native E2E / init-native (ubuntu-latest, copilot) (push) Failing after 1s
Release Please / release-please (push) Failing after 1s
Wrap E2E / docker-wrap-e2e (push) Failing after 1s
Wrap Native E2E / wrap-native (ubuntu-latest) (push) Failing after 1s
Init E2E / docker-init-e2e (push) Failing after 4s
Merge Conflicts / merge-conflicts (push) Failing after 4s
CI / lint (push) Has been cancelled
CI / build-wheel (push) Has been cancelled
CI / build-wheel-windows (push) Has been cancelled
CI / prefetch-model (push) Has been cancelled
CI / test-dashboard-ui (push) Has been cancelled
CI / test (1) (push) Has been cancelled
CI / test (2) (push) Has been cancelled
CI / test (3) (push) Has been cancelled
CI / test (4) (push) Has been cancelled
CI / test-extras (push) Has been cancelled
CI / test-agno (push) Has been cancelled
CI / build (push) Has been cancelled
CI / workflow-validation (push) Has been cancelled
CI / docker-native-e2e (push) Has been cancelled
CI / windows-native-wrapper (push) Has been cancelled
CI / macos-native-wrapper (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code-nonroot name:code-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code-slim name:code-slim]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code-slim-nonroot name:code-slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-nonroot name:nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-slim name:slim]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-slim-nonroot name:slim-nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime name:]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code name:code]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code-nonroot name:code-nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code-slim name:code-slim]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code-slim-nonroot name:code-slim-nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-nonroot name:nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-slim name:slim]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-slim-nonroot name:slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime name:]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code name:code]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code-nonroot name:code-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code-slim name:code-slim]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code-slim-nonroot name:code-slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-nonroot name:nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-slim name:slim]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-slim-nonroot name:slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime name:]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code name:code]) (push) Has been cancelled
Docker / promote-latest (push) Has been cancelled
Init Native E2E / init-native (macos-latest, claude) (push) Has been cancelled
Init Native E2E / init-native (macos-latest, codex) (push) Has been cancelled
Init Native E2E / init-native (macos-latest, copilot) (push) Has been cancelled
Install Native E2E / install-native (macos-latest) (push) Has been cancelled
Wrap Native E2E / wrap-native (macos-latest) (push) Has been cancelled
155 行
5.3 KiB
Python
155 行
5.3 KiB
Python
"""Cost tracking for evaluation suite runs.
|
|
|
|
Tracks actual API spend per benchmark, enforces budget limits,
|
|
and estimates remaining cost before running expensive benchmarks.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from dataclasses import dataclass, field
|
|
from typing import Any
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# Pricing per 1M tokens (as of Feb 2026)
|
|
MODEL_PRICING: dict[str, dict[str, float]] = {
|
|
# OpenAI
|
|
"gpt-4o-mini": {"input": 0.15, "output": 0.60},
|
|
"gpt-4o": {"input": 2.50, "output": 10.00},
|
|
"gpt-4o-mini-2024-07-18": {"input": 0.15, "output": 0.60},
|
|
# Anthropic
|
|
"claude-sonnet-4-20250514": {"input": 3.00, "output": 15.00},
|
|
"claude-haiku-3-5-20241022": {"input": 1.00, "output": 5.00},
|
|
"claude-3-5-haiku-20241022": {"input": 1.00, "output": 5.00},
|
|
# Fallback for unknown models
|
|
"_default": {"input": 1.00, "output": 5.00},
|
|
}
|
|
|
|
|
|
@dataclass
|
|
class UsageRecord:
|
|
"""Record of a single API call's token usage."""
|
|
|
|
benchmark: str
|
|
model: str
|
|
input_tokens: int
|
|
output_tokens: int
|
|
cost_usd: float
|
|
|
|
|
|
@dataclass
|
|
class CostTracker:
|
|
"""Track and enforce API spend budget for eval runs.
|
|
|
|
Usage:
|
|
tracker = CostTracker(budget_usd=20.0)
|
|
tracker.record("gsm8k", "gpt-4o-mini", input_tokens=5000, output_tokens=1000)
|
|
if not tracker.check_budget():
|
|
print("Budget exceeded!")
|
|
"""
|
|
|
|
budget_usd: float = 20.0
|
|
records: list[UsageRecord] = field(default_factory=list)
|
|
|
|
@property
|
|
def spent_usd(self) -> float:
|
|
return sum(r.cost_usd for r in self.records)
|
|
|
|
@property
|
|
def remaining_usd(self) -> float:
|
|
return max(0.0, self.budget_usd - self.spent_usd)
|
|
|
|
def _get_pricing(self, model: str) -> dict[str, float]:
|
|
"""Get pricing for a model, falling back to default."""
|
|
return MODEL_PRICING.get(model, MODEL_PRICING["_default"])
|
|
|
|
def _compute_cost(self, model: str, input_tokens: int, output_tokens: int) -> float:
|
|
"""Compute cost in USD for given token counts."""
|
|
pricing = self._get_pricing(model)
|
|
input_cost = (input_tokens / 1_000_000) * pricing["input"]
|
|
output_cost = (output_tokens / 1_000_000) * pricing["output"]
|
|
return input_cost + output_cost
|
|
|
|
def record(
|
|
self, benchmark: str, model: str, input_tokens: int, output_tokens: int
|
|
) -> UsageRecord:
|
|
"""Record token usage from an API call."""
|
|
cost = self._compute_cost(model, input_tokens, output_tokens)
|
|
rec = UsageRecord(
|
|
benchmark=benchmark,
|
|
model=model,
|
|
input_tokens=input_tokens,
|
|
output_tokens=output_tokens,
|
|
cost_usd=cost,
|
|
)
|
|
self.records.append(rec)
|
|
logger.debug(f"Cost: ${cost:.4f} ({benchmark}, {input_tokens} in / {output_tokens} out)")
|
|
return rec
|
|
|
|
def check_budget(self) -> bool:
|
|
"""Return True if within budget."""
|
|
return self.spent_usd < self.budget_usd
|
|
|
|
def estimate_cost(
|
|
self,
|
|
model: str,
|
|
n_samples: int,
|
|
avg_input_tokens: int = 500,
|
|
avg_output_tokens: int = 100,
|
|
multiplier: int = 2, # baseline + headroom = 2x calls
|
|
) -> float:
|
|
"""Estimate cost for a benchmark run before executing it."""
|
|
total_input = n_samples * avg_input_tokens * multiplier
|
|
total_output = n_samples * avg_output_tokens * multiplier
|
|
return self._compute_cost(model, total_input, total_output)
|
|
|
|
def can_afford(
|
|
self,
|
|
model: str,
|
|
n_samples: int,
|
|
avg_input_tokens: int = 500,
|
|
avg_output_tokens: int = 100,
|
|
multiplier: int = 2,
|
|
) -> bool:
|
|
"""Check if we can afford a benchmark run within remaining budget."""
|
|
estimated = self.estimate_cost(
|
|
model, n_samples, avg_input_tokens, avg_output_tokens, multiplier
|
|
)
|
|
return estimated <= self.remaining_usd
|
|
|
|
def summary(self) -> dict[str, Any]:
|
|
"""Return summary of spending."""
|
|
by_benchmark: dict[str, float] = {}
|
|
total_input = 0
|
|
total_output = 0
|
|
for r in self.records:
|
|
by_benchmark[r.benchmark] = by_benchmark.get(r.benchmark, 0) + r.cost_usd
|
|
total_input += r.input_tokens
|
|
total_output += r.output_tokens
|
|
|
|
return {
|
|
"budget_usd": self.budget_usd,
|
|
"spent_usd": round(self.spent_usd, 4),
|
|
"remaining_usd": round(self.remaining_usd, 4),
|
|
"total_input_tokens": total_input,
|
|
"total_output_tokens": total_output,
|
|
"by_benchmark": {k: round(v, 4) for k, v in by_benchmark.items()},
|
|
"n_calls": len(self.records),
|
|
}
|
|
|
|
def print_summary(self) -> None:
|
|
"""Print a formatted cost summary."""
|
|
s = self.summary()
|
|
print(f"\n{'Cost Summary':=^50}")
|
|
print(f" Budget: ${s['budget_usd']:.2f}")
|
|
print(f" Spent: ${s['spent_usd']:.4f}")
|
|
print(f" Remaining: ${s['remaining_usd']:.4f}")
|
|
print(f" API calls: {s['n_calls']}")
|
|
print(f" Tokens: {s['total_input_tokens']:,} in / {s['total_output_tokens']:,} out")
|
|
if s["by_benchmark"]:
|
|
print(f" {'Breakdown:':-^40}")
|
|
for name, cost in sorted(s["by_benchmark"].items(), key=lambda x: -x[1]):
|
|
print(f" {name:<25} ${cost:.4f}")
|
|
print("=" * 50)
|