#!/usr/bin/env bash # worker-quota-probe.sh — pre-flight Anthropic rate-limit-quota meting. # # Doet een lichtgewicht /v1/messages-call (1 token max) en parsed de # `anthropic-ratelimit-*-tokens`-headers. Output is JSON op stdout. # # Output (success): # {"remaining": 9982000, "limit": 10000000, "pct": 99, "reset_at_iso": "..."} # # Output (fail): # {"error": "...", "http_status": NNN} # # Exit-codes: 0 success, 1 op fout. De worker-loop gebruikt de pct + reset # om te beslissen of-ie wait_for_job mag aanroepen (gate via min_quota_pct # uit get_worker_settings). # # Gebruikt env-var ANTHROPIC_API_KEY of CLAUDE_CODE_OAUTH_TOKEN. OAuth-tokens # worden door de Anthropic API herkend als Bearer; de header-set is dezelfde. set -uo pipefail KEY="${ANTHROPIC_API_KEY:-${CLAUDE_CODE_OAUTH_TOKEN:-}}" if [[ -z "$KEY" ]]; then echo '{"error":"no ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN set"}' exit 1 fi HDR_FILE=$(mktemp /tmp/quota-probe.XXXXXX.headers) trap 'rm -f "$HDR_FILE"' EXIT # Minimale call: claude-haiku-4-5 met 1 max_tokens en een single-char input. # Kost ~1 outputtoken; doel is alleen de rate-limit-headers binnen te halen. HTTP_STATUS=$(curl -sS -o /dev/null \ -D "$HDR_FILE" \ -w '%{http_code}' \ -H "Authorization: Bearer ${KEY}" \ -H "anthropic-version: 2023-06-01" \ -H "content-type: application/json" \ -d '{"model":"claude-haiku-4-5","max_tokens":1,"messages":[{"role":"user","content":"."}]}' \ https://api.anthropic.com/v1/messages 2>/dev/null || echo "000") # Parse rate-limit headers (case-insensitive grep). REMAINING=$(grep -i '^anthropic-ratelimit-output-tokens-remaining:' "$HDR_FILE" 2>/dev/null | awk '{print $2}' | tr -d '\r') LIMIT=$(grep -i '^anthropic-ratelimit-output-tokens-limit:' "$HDR_FILE" 2>/dev/null | awk '{print $2}' | tr -d '\r') RESET=$(grep -i '^anthropic-ratelimit-output-tokens-reset:' "$HDR_FILE" 2>/dev/null | awk '{print $2}' | tr -d '\r') # Fallback: sommige plans gebruiken `requests` ipv `tokens` voor de hoofdgrens. if [[ -z "$REMAINING" ]]; then REMAINING=$(grep -i '^anthropic-ratelimit-requests-remaining:' "$HDR_FILE" 2>/dev/null | awk '{print $2}' | tr -d '\r') LIMIT=$(grep -i '^anthropic-ratelimit-requests-limit:' "$HDR_FILE" 2>/dev/null | awk '{print $2}' | tr -d '\r') RESET=$(grep -i '^anthropic-ratelimit-requests-reset:' "$HDR_FILE" 2>/dev/null | awk '{print $2}' | tr -d '\r') fi if [[ -z "$REMAINING" || -z "$LIMIT" ]]; then printf '{"error":"no rate-limit headers in response","http_status":%s}\n' "$HTTP_STATUS" exit 1 fi # Pct als integer (rounded). Bij limit=0 zou je delen door nul — bescherm. if [[ "$LIMIT" == "0" ]]; then PCT=0 else PCT=$(awk -v r="$REMAINING" -v l="$LIMIT" 'BEGIN { printf("%d", (r/l)*100) }') fi # Reset-time is al ISO-8601 in de header bij Anthropic; geef ongewijzigd door. RESET_ESCAPED="${RESET:-}" printf '{"remaining":%s,"limit":%s,"pct":%s,"reset_at_iso":"%s","http_status":%s}\n' \ "$REMAINING" "$LIMIT" "$PCT" "$RESET_ESCAPED" "$HTTP_STATUS"