feat(M13 T-520a): bin/worker-quota-probe.sh — pre-flight quota-meting

Lichtgewicht /v1/messages-call (1 token max) → parse
anthropic-ratelimit-*-headers → JSON op stdout.

Output: { remaining, limit, pct, reset_at_iso, http_status }
Of: { error, http_status } bij fout.

Worker-loop gebruikt pct in vergelijking met min_quota_pct (uit
mcp__scrum4me__get_worker_settings) om stand-by-modus te bepalen.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Madhura68 2026-05-06 04:28:38 +02:00
parent 4b2241235e
commit e4e0760b1b

70
bin/worker-quota-probe.sh Executable file
View file

@ -0,0 +1,70 @@
#!/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"