#!/usr/bin/env python3 """Live verification for the Anthropic models catalogue (cheap; every call logged). 1. GET /v1/models/{id} for live ids + legacy/alias ids -> 200 vs 404 (alias resolution, retired ids) 2. GET /v1/models?limit=2 and ?limit=2&after_id=... -> pagination behaviour 3. POST /v1/messages "Reply with OK." max_tokens=8 on a handful of current models -> LIVE_VERIFIED + usage shape 4. POST /v1/messages/count_tokens on the same models Raw sanitized results: tmp-live/anthropic-models/*.json ; summary: tmp-live/anthropic-models/summary.json """ from __future__ import annotations import json import sys from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parent)) import live # noqa: E402 ROOT = Path(__file__).resolve().parents[1] OUT = ROOT / "tmp-live" / "anthropic-models" LIVE_IDS = ["claude-fable-5-1", "claude-fable-5", "claude-opus-5", "claude-sonnet-5", "claude-opus-4-8", "claude-opus-4-7", "claude-opus-4-6", "claude-sonnet-4-6", "claude-opus-4-5-20251101", "claude-sonnet-4-5-20250929", "claude-haiku-4-5-20251001"] PROBE_IDS = ["claude-3-5-haiku-20241022", "claude-3-7-sonnet-20250219", "claude-sonnet-4-20250514", "claude-opus-4-1-20250805", "claude-haiku-4-5", "claude-sonnet-4-5", "claude-opus-4-5", "claude-3-opus-20240229", "claude-mythos-5", "claude-mythos-5-1", "claude-mythos-preview", "claude-3-5-sonnet-20241022", "claude-3-haiku-20240307"] MSG_MODELS = ["claude-opus-5", "claude-sonnet-5", "claude-fable-5-1", "claude-opus-4-8", "claude-sonnet-4-6"] # $/MTok input,output for cost estimate PRICE = {"claude-opus-5": (5, 25), "claude-sonnet-5": (2, 10), "claude-fable-5-1": (10, 50), "claude-opus-4-8": (5, 25), "claude-sonnet-4-6": (3, 15)} def main() -> None: OUT.mkdir(parents=True, exist_ok=True) summary: dict = {"retrieved_at": live.now(), "get_model": {}, "pagination": {}, "messages": {}, "count_tokens": {}} for mid in LIVE_IDS + PROBE_IDS: st, body, hdrs = live.anthropic_request("GET", f"/v1/models/{mid}", note="retrieve model (catalogue verification)") summary["get_model"][mid] = {"status": st, "resolved_id": body.get("id") if isinstance(body, dict) else None, "body": body, "ratelimit_headers": live.interesting_headers(hdrs)} print(f"GET /v1/models/{mid} -> {st} {body.get('id') if isinstance(body, dict) and 'id' in body else body.get('error', {}).get('message', '')[:100] if isinstance(body, dict) else ''}") st, body, hdrs = live.anthropic_request("GET", "/v1/models?limit=2", note="pagination probe limit=2") summary["pagination"]["page1"] = {"status": st, "body": body, "headers": live.interesting_headers(hdrs)} print(f"GET /v1/models?limit=2 -> {st} ids={[m['id'] for m in body.get('data', [])]} has_more={body.get('has_more')} last_id={body.get('last_id')}") if st == 200 and body.get("last_id"): st2, body2, _ = live.anthropic_request("GET", f"/v1/models?limit=2&after_id={body['last_id']}", note="pagination probe after_id") summary["pagination"]["page2"] = {"status": st2, "body": body2} print(f"GET /v1/models?limit=2&after_id=... -> {st2} ids={[m['id'] for m in body2.get('data', [])]} has_more={body2.get('has_more')}") if st2 == 200 and body2.get("first_id"): st3, body3, _ = live.anthropic_request("GET", f"/v1/models?limit=2&before_id={body2['first_id']}", note="pagination probe before_id") summary["pagination"]["page_before"] = {"status": st3, "body": body3} print(f"GET /v1/models?limit=2&before_id=... -> {st3} ids={[m['id'] for m in body3.get('data', [])]}") st4, body4, _ = live.anthropic_request("GET", "/v1/models?limit=0", note="pagination probe limit=0 (expect 400)") summary["pagination"]["limit0"] = {"status": st4, "body": body4} print(f"GET /v1/models?limit=0 -> {st4} {json.dumps(body4)[:160]}") total_cost = 0.0 for mid in MSG_MODELS: payload = {"model": mid, "max_tokens": 8, "messages": [{"role": "user", "content": "Reply with OK."}]} pi, po = PRICE[mid] est = (20 * pi + 8 * po) / 1e6 st, body, hdrs = live.anthropic_request("POST", "/v1/messages", payload, est_cost_usd=est, note=f"minimal message {mid} (models catalogue LIVE_VERIFIED)") usage = body.get("usage") if isinstance(body, dict) else None if isinstance(usage, dict): est = (usage.get("input_tokens", 0) * pi + usage.get("output_tokens", 0) * po) / 1e6 total_cost += est summary["messages"][mid] = {"status": st, "body": body, "ratelimit_headers": live.interesting_headers(hdrs), "est_cost_usd": round(est, 6)} print(f"POST /v1/messages {mid} -> {st} model={body.get('model') if isinstance(body, dict) else None} stop={body.get('stop_reason') if isinstance(body, dict) else None} usage={json.dumps(usage)[:300] if usage else body}") st, body, hdrs = live.anthropic_request("POST", "/v1/messages/count_tokens", {"model": mid, "messages": payload["messages"]}, note=f"count_tokens {mid}") summary["count_tokens"][mid] = {"status": st, "body": body, "ratelimit_headers": live.interesting_headers(hdrs)} print(f"POST /v1/messages/count_tokens {mid} -> {st} {json.dumps(body)[:200]}") summary["total_est_cost_usd"] = round(total_cost, 6) live.save_sanitized(summary, OUT / "summary.json") print(f"total est cost USD {total_cost:.5f}; summary -> {OUT / 'summary.json'}") if __name__ == "__main__": main()