diff --git a/.github/workflows/qwen-autofix.yml b/.github/workflows/qwen-autofix.yml index 514e3824d42..6b5004f45e6 100644 --- a/.github/workflows/qwen-autofix.yml +++ b/.github/workflows/qwen-autofix.yml @@ -108,6 +108,12 @@ env: # Hard cap on automated review-address rounds per PR. After this the bot stops # and leaves the PR for a human. MAX_ROUNDS: '5' + # An auth/access model error (401/402/403, "no access"/"does not exist") + # never self-heals - only a maintainer can fix the key - and every retry + # costs an agent run AND a PR comment. Cap those attempts far below + # MAX_ROUNDS so the actionable "check the model key" message lands in an + # hour instead of a day. Transient (429/5xx) errors keep the full budget. + API_AUTH_MAX_ROUNDS: '3' # Upper bound on review targets emitted per scan (fan-out defense-in-depth; # excess is logged and deferred to the next scan). MAX_TARGETS_PER_SCAN: '10' @@ -2705,7 +2711,7 @@ jobs: if git rev-parse --verify "${BRANCH}" > /dev/null 2>&1; then git diff "origin/main...${BRANCH}" > "${WORKDIR}/pr.diff" || true fi - for f in feedback.md address-summary.md no-action.md failure.md handoff.md resolved-comments.txt pr.diff; do + for f in feedback.md address-summary.md no-action.md failure.md handoff.md agent-api-error agent-api-error-kind resolved-comments.txt pr.diff; do if [[ -f "${WORKDIR}/${f}" ]]; then echo "=============== ${f} ===============" cat "${WORKDIR}/${f}" @@ -2964,6 +2970,30 @@ jobs: for f in failure.md handoff.md address-summary.md no-action.md; do if [[ -s "${WORKDIR}/${f}" ]]; then DETAIL_FILE="${WORKDIR}/${f}"; break; fi done + # run-agent.mjs drops this marker when qwen died on a model-side + # [API Error: 4xx/5xx] (access denied, quota, a 5xx). The agent never + # evaluated the feedback, so this is treated as a retry (sentinel ts, + # no watermark advance) below — a model access/quota blip must not + # strand the PR the way a real evaluated handoff would. + API_ERROR_DETAIL='' + API_ERROR_KIND='' + if [[ -s "${WORKDIR}/agent-api-error" ]]; then + # First line only, comment-opener escaped (agent stdout can echo + # external PR-comment text and the marker regex spans '' + # happily), and capped so a long span can't bloat the headline. + # `cut -c` counts BYTES, so the cap can split a multi-byte + # character - and the classifier deliberately matches CJK renders, + # so a >200-byte Chinese error is a supported input, not a + # hypothetical. iconv -c drops the dangling bytes so the headline + # stays valid UTF-8; it EXITS 1 when it discards one, which under + # this step's `set -eo pipefail` would abort before the marker and + # the gh pr comment - hence the `|| true`, same as the sibling + # publish site below. + API_ERROR_DETAIL="$(head -n 1 "${WORKDIR}/agent-api-error" | sed 's/ sits on another line, while jq scan() matches - // across newlines. Proven end-to-end on a split forged marker. - expect(workflow.split("sed 's/ sits on another line, while jq scan() matches across newlines. + // Proven end-to-end on a split forged marker. + expect(workflow.split("sed 's/'; const sedCmd = workflow.match(/sed 's\/