fix: harden partial 429 success, fallbacks, zh errors
Retry HTTP 429 with backoff; keep models beyond first 3 as fallbacks; degrade agreement when some models fail; force-high risk only if zero usable responses. Clearer zh-CN errors/docs for dogfood uses: ./ rebase + workflow_dispatch re-run.
This commit is contained in:
1 parent
ef13f8806a
commit
c6c2d071fb
10 files changed
+193
-61
No files matched your search
Regular → Executable
+31
-21
@@ -2,6 +2,7 @@
|
||||
# Call one model via provider protocol.
|
||||
# Protocols: openai | openai-completions | openai-responses | anthropic
|
||||
# (openai / openai-compatible → chat completions)
|
||||
# Retries HTTP 429 with exponential backoff (GATEKEEP_HTTP_RETRIES, default 3).
|
||||
# Args: <provider> <model> <protocol> <base_url> <prompt.json> <out.json> <secrets.json>
|
||||
set -euo pipefail
|
||||
|
||||
@@ -21,6 +22,7 @@ if [[ -z "$KEY" ]]; then
|
||||
fi
|
||||
|
||||
MAX_TOKENS="${GATEKEEP_MAX_TOKENS:-4096}"
|
||||
RETRIES="${GATEKEEP_HTTP_RETRIES:-3}"
|
||||
SYSTEM=$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1]))["system"])' "$PROMPT_FILE")
|
||||
USER=$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1]))["user"])' "$PROMPT_FILE")
|
||||
|
||||
@@ -54,13 +56,9 @@ print(json.dumps({
|
||||
}))
|
||||
PY
|
||||
)
|
||||
HTTP_CODE=$(curl -sS -o "$OUT_FILE.raw" -w "%{http_code}" \
|
||||
"${BASE_URL%/}/chat/completions" \
|
||||
-H "Authorization: Bearer $KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "HTTP-Referer: https://github.com/${GITHUB_REPOSITORY:-gatekeep}" \
|
||||
-H "X-Title: Gatekeep" \
|
||||
-d "$BODY")
|
||||
URL="${BASE_URL%/}/chat/completions"
|
||||
EXTRA_HDR=(-H "HTTP-Referer: https://github.com/${GITHUB_REPOSITORY:-gatekeep}" -H "X-Title: Gatekeep")
|
||||
AUTH=(-H "Authorization: Bearer $KEY")
|
||||
EXTRACT=openai
|
||||
elif [[ "$WIRE" == "openai-responses" ]]; then
|
||||
BODY=$(python3 - "$MODEL" "$SYSTEM" "$USER" "$MAX_TOKENS" <<'PY'
|
||||
@@ -77,11 +75,9 @@ print(json.dumps({
|
||||
}))
|
||||
PY
|
||||
)
|
||||
HTTP_CODE=$(curl -sS -o "$OUT_FILE.raw" -w "%{http_code}" \
|
||||
"${BASE_URL%/}/responses" \
|
||||
-H "Authorization: Bearer $KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$BODY")
|
||||
URL="${BASE_URL%/}/responses"
|
||||
EXTRA_HDR=()
|
||||
AUTH=(-H "Authorization: Bearer $KEY")
|
||||
EXTRACT=openai-responses
|
||||
elif [[ "$WIRE" == "anthropic" ]]; then
|
||||
BODY=$(python3 - "$MODEL" "$SYSTEM" "$USER" "$MAX_TOKENS" <<'PY'
|
||||
@@ -96,21 +92,36 @@ print(json.dumps({
|
||||
}))
|
||||
PY
|
||||
)
|
||||
HTTP_CODE=$(curl -sS -o "$OUT_FILE.raw" -w "%{http_code}" \
|
||||
"${BASE_URL%/}/v1/messages" \
|
||||
-H "x-api-key: $KEY" \
|
||||
-H "anthropic-version: 2023-06-01" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$BODY")
|
||||
URL="${BASE_URL%/}/v1/messages"
|
||||
EXTRA_HDR=(-H "anthropic-version: 2023-06-01")
|
||||
AUTH=(-H "x-api-key: $KEY")
|
||||
EXTRACT=anthropic
|
||||
fi
|
||||
|
||||
if [[ "$HTTP_CODE" != "200" ]]; then
|
||||
attempt=0
|
||||
HTTP_CODE="000"
|
||||
while true; do
|
||||
HTTP_CODE=$(curl -sS -o "$OUT_FILE.raw" -w "%{http_code}" \
|
||||
"$URL" \
|
||||
"${AUTH[@]}" \
|
||||
-H "Content-Type: application/json" \
|
||||
"${EXTRA_HDR[@]}" \
|
||||
-d "$BODY" || echo "000")
|
||||
if [[ "$HTTP_CODE" == "200" ]]; then
|
||||
break
|
||||
fi
|
||||
if [[ "$HTTP_CODE" == "429" && "$attempt" -lt "$RETRIES" ]]; then
|
||||
sleep_s=$((2 ** attempt))
|
||||
echo "$LABEL HTTP 429 — retry $((attempt + 1))/${RETRIES} after ${sleep_s}s" >&2
|
||||
sleep "$sleep_s"
|
||||
attempt=$((attempt + 1))
|
||||
continue
|
||||
fi
|
||||
echo "$LABEL failed HTTP $HTTP_CODE" >&2
|
||||
head -c 800 "$OUT_FILE.raw" >&2 || true
|
||||
echo "{\"error\":\"http\",\"model\":\"$MODEL\",\"provider\":\"$PROVIDER\",\"http\":$HTTP_CODE}" > "$OUT_FILE"
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
|
||||
python3 - "$OUT_FILE.raw" "$OUT_FILE" "$MODEL" "$PROVIDER" "$EXTRACT" <<'PY'
|
||||
import json,sys
|
||||
@@ -123,7 +134,6 @@ if kind == "anthropic":
|
||||
if c.get("type") == "text"
|
||||
)
|
||||
elif kind == "openai-responses":
|
||||
# Best-effort extract from Responses API
|
||||
text = raw.get("output_text") or ""
|
||||
if not text:
|
||||
chunks = []
|
||||
|
||||
Reference in new issue
Block a user