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>
70 lines
3 KiB
Bash
Executable file
70 lines
3 KiB
Bash
Executable file
#!/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"
|