From a051bb00d43e53b8dbee21cc4ed865f855517c6d Mon Sep 17 00:00:00 2001 From: Janpeter Visser <30029041+madhura68@users.noreply.github.com> Date: Fri, 15 May 2026 00:43:32 +0200 Subject: [PATCH] fix(worker): TOKEN_EXPIRED-detectie alleen bij non-zero Claude-exit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit run-one-job.ts scant de volledige stream-json output (incl. álle tool-results) op auth-error-patronen, en run-agent.sh grept hetzelfde over het complete run-log — beide zonder de exit-code te checken. Daardoor legt een geslaagde job (exit 0, result.is_error=false) de worker plat zodra z'n output toevallig iets als "401 unauthorized" bevat — bv. wanneer de agent een doc over route-handler-auth leest of een endpoint test. run-agent.sh doet dan touch TOKEN_EXPIRED + sleep infinity en de worker draait pas na een rebuild weer. Fix: detectie gaten op een niet-nul exit. Een echte credential-fout laat 'claude' non-zero exiten, dus echte expiries worden nog steeds gevangen — alleen de false positives op geslaagde runs verdwijnen. Co-Authored-By: Claude Opus 4.7 (1M context) --- bin/run-agent.sh | 8 ++++++-- bin/run-one-job.ts | 20 ++++++++++++++------ 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/bin/run-agent.sh b/bin/run-agent.sh index 52c6f49..6b3dd32 100644 --- a/bin/run-agent.sh +++ b/bin/run-agent.sh @@ -80,8 +80,12 @@ while true; do # Token-expiry detectie: run-one-job.ts retourneert exit 3 wanneer het # bekende auth-error-strings in Claude's output ziet. We checken óók de # log-tekst voor het geval een ander pad het patroon raakt (bv. Prisma- - # connection-error met OAuth-expired in error-body). - if [[ "$exit_code" -eq 3 ]] || grep -qE '(invalid_api_key|authentication.*failed|401.*unauthor|OAuth.*expired)' "${run_log}"; then + # connection-error met OAuth-expired in error-body) — maar alléén bij een + # niet-nul exit. Het run-log bevat de volledige stream-json output (incl. + # tool-results én run-one-job's eigen "TOKEN_EXPIRED detected"-logregel), + # dus een geslaagde job die toevallig "401 unauthorized" in z'n output + # heeft mag de grep-fallback niet triggeren. + if [[ "$exit_code" -eq 3 ]] || { [[ "$exit_code" -ne 0 ]] && grep -qE '(invalid_api_key|authentication.*failed|401.*unauthor|OAuth.*expired)' "${run_log}"; }; then log "AUTH FAILURE detected (exit=$exit_code or pattern in log) — marking TOKEN_EXPIRED" touch "${AGENT_STATE_DIR}/TOKEN_EXPIRED" write_state "$(jq -n \ diff --git a/bin/run-one-job.ts b/bin/run-one-job.ts index 8155fea..f9cc879 100644 --- a/bin/run-one-job.ts +++ b/bin/run-one-job.ts @@ -383,13 +383,21 @@ async function main(): Promise { `duration_ms=${durationMs} wall_clock_seconds=${Math.round(durationMs / 1000)}`, ) - // 10. Token-expiry detection. + // 10. Token-expiry detection — alleen als Claude zelf non-zero eindigde. + // stdoutBuf bevat de volledige stream-json output incl. álle tool-results, + // dus de auth-error-strings kunnen ook agent-werk-content zijn (een doc + // over 401-handling gelezen, een endpoint getest). Een echte credential- + // fout laat 'claude' non-zero exiten; een geslaagde run (exit 0) is per + // definitie geen token-expiry. Zonder deze gate legt zulke content de + // worker onterecht plat (run-agent.sh → TOKEN_EXPIRED marker + sleep). let tokenExpired = false - for (const pat of TOKEN_EXPIRY_PATTERNS) { - if (pat.test(stdoutBuf)) { - tokenExpired = true - log(`TOKEN_EXPIRED detected pattern="${pat.source}" exiting code=3`) - break + if (exitCode !== 0) { + for (const pat of TOKEN_EXPIRY_PATTERNS) { + if (pat.test(stdoutBuf)) { + tokenExpired = true + log(`TOKEN_EXPIRED detected pattern="${pat.source}" exiting code=3`) + break + } } }