Recognize sign-in failures for every agent and fall through #19

Merged
temeddix merged 2 commits from fix/agent-sign-in-failures into main 2026-10-12 02:51:29 +00:00
Owner

Problem

On lead/memona-home#36 (Actions job 9837), the bot failed with "AI bot failed. > Profile: none · all profiles failed" and never posted the Codex sign-in comment. The staged Codex auth.json held a token the server had revoked. codex login status only reads the local file, so it passed. codex exec then failed with refresh_token_invalidated, "Your session has ended. Please log in again.", token_revoked and 401 Unauthorized. retryInvalidToken only matched invalid_refresh_token, so device login never ran. The failure also wasn't classified as usage exhaustion, so Claude and OpenCode were never tried.

What each CLI emits on rejected credentials (checked against the real CLIs)

  • Codex: exits 1. Its stderr ERROR lines carry refresh_token_invalidated|expired|reused, token_revoked, 401 Unauthorized, "log/sign in again", and invalid_api_key for API keys. Codex also echoes the full prompt and tool output to stderr.
  • Claude Code (CLAUDE_CODE_OAUTH_TOKEN): exits 1 with empty stderr. The stream-json result has is_error: true, api_error_status: 401 and "Failed to authenticate. API Error: 401 OAuth access token is invalid."
  • OpenCode (OpenRouter key): exits 1 with empty stderr. The error appears only as a stdout JSON event {"type":"error","error":{"name":"APIError","data":{"statusCode":401,"message":"User not found."}}}. Before this change the bot only reported "opencode exited with 1".

Changes

  • isCodexAuthFailure matches those auth markers only on Codex's own ERROR lines, and the runner strips the echoed prompt first, so quoted logs in PR comments or tool output can't trigger a device login. A matching failure re-runs logout and device login, which posts the sign-in comment, then retries once.
  • isClaudeAuthFailure classifies is_error results by api_error_status: 401 or by the auth message text.
  • openCodeError reads OpenCode's stdout error events. A 401 or 403 becomes a sign-in failure. Other errors are surfaced as opencode APIError (API error N): message, so OpenRouter 402 and 429 now count as usage exhaustion.
  • A new AgentAuthError is thrown once credentials are rejected and any re-login has been used up. A device login that fails or times out also counts. runProfiles falls through on it just as it does for usage exhaustion, and still throws the last error if every profile fails.
  • The failure comment now lists every profile that was tried, with a fixed label for each, e.g. > Tried: `codex` · `gpt-5.6-terra` (sign-in failed), `claude` · `claude-sonnet-5` (usage exhausted). post.ts accepts only known types and labels from the outcome file, so no raw agent output or secret can reach the comment.
  • Adds a project memory note recording these CLI behaviours.

Tests

Added tests covering the verbatim job 9837 stderr lines, the other Codex refresh-token errors, the ERROR-line anchoring, Claude and OpenRouter auth errors, fall-through with failure recording, and comment sanitization. deno fmt --check ., deno lint ., deno check and deno test --allow-all all pass (58 tests).

Note

The bot still runs Codex first with the revoked login. With this change merged, the bot should post a device-login comment and then fall back to Claude. Until then, the @bot review on this PR may fail the same way.

🤖 Generated with Claude Code

## Problem On lead/memona-home#36 (Actions job 9837), the bot failed with "AI bot failed. > Profile: none · all profiles failed" and never posted the Codex sign-in comment. The staged Codex `auth.json` held a token the server had revoked. `codex login status` only reads the local file, so it passed. `codex exec` then failed with `refresh_token_invalidated`, "Your session has ended. Please log in again.", `token_revoked` and `401 Unauthorized`. `retryInvalidToken` only matched `invalid_refresh_token`, so device login never ran. The failure also wasn't classified as usage exhaustion, so Claude and OpenCode were never tried. ## What each CLI emits on rejected credentials (checked against the real CLIs) - **Codex**: exits 1. Its stderr ERROR lines carry `refresh_token_invalidated|expired|reused`, `token_revoked`, `401 Unauthorized`, "log/sign in again", and `invalid_api_key` for API keys. Codex also echoes the full prompt and tool output to stderr. - **Claude Code** (`CLAUDE_CODE_OAUTH_TOKEN`): exits 1 with empty stderr. The stream-json `result` has `is_error: true`, `api_error_status: 401` and "Failed to authenticate. API Error: 401 OAuth access token is invalid." - **OpenCode** (OpenRouter key): exits 1 with **empty stderr**. The error appears only as a stdout JSON event `{"type":"error","error":{"name":"APIError","data":{"statusCode":401,"message":"User not found."}}}`. Before this change the bot only reported "opencode exited with 1". ## Changes - `isCodexAuthFailure` matches those auth markers only on Codex's own `ERROR` lines, and the runner strips the echoed prompt first, so quoted logs in PR comments or tool output can't trigger a device login. A matching failure re-runs logout and device login, which posts the sign-in comment, then retries once. - `isClaudeAuthFailure` classifies `is_error` results by `api_error_status: 401` or by the auth message text. - `openCodeError` reads OpenCode's stdout error events. A 401 or 403 becomes a sign-in failure. Other errors are surfaced as `opencode APIError (API error N): message`, so OpenRouter 402 and 429 now count as usage exhaustion. - A new `AgentAuthError` is thrown once credentials are rejected and any re-login has been used up. A device login that fails or times out also counts. `runProfiles` falls through on it just as it does for usage exhaustion, and still throws the last error if every profile fails. - The failure comment now lists every profile that was tried, with a fixed label for each, e.g. ``> Tried: `codex` · `gpt-5.6-terra` (sign-in failed), `claude` · `claude-sonnet-5` (usage exhausted)``. `post.ts` accepts only known types and labels from the outcome file, so no raw agent output or secret can reach the comment. - Adds a project memory note recording these CLI behaviours. ## Tests Added tests covering the verbatim job 9837 stderr lines, the other Codex refresh-token errors, the ERROR-line anchoring, Claude and OpenRouter auth errors, fall-through with failure recording, and comment sanitization. `deno fmt --check .`, `deno lint .`, `deno check` and `deno test --allow-all` all pass (58 tests). ## Note The bot still runs Codex first with the revoked login. With this change merged, the bot should post a device-login comment and then fall back to Claude. Until then, the `@bot` review on this PR may fail the same way. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
temeddix added 1 commit 2026-10-12 02:38:43 +00:00
Recognize sign-in failures for every agent and fall through
Agents / agent (pull_request) Has been cancelled
Check / deno (pull_request) Failing after 35s
3565988249
Codex re-runs device login on revoked, expired, or reused sessions and
token_revoked/401 errors, not only invalid_refresh_token. Claude and
OpenCode credential rejections are classified too. Sign-in failures fall
through to the next profile, and the failure comment names each tried
profile with a fixed reason label.
Author
Owner
@bot
temeddix added 1 commit 2026-10-12 02:39:55 +00:00
Format the CLI auth memory note
Check / deno (pull_request) Successful in 39s
c91710a00e
Owner

AI bot failed.

Profile: none · all profiles failed

AI bot failed. > Profile: none · all profiles failed
temeddix merged commit f001a71c61 into main 2026-10-12 02:51:29 +00:00
temeddix deleted branch fix/agent-sign-in-failures 2026-10-12 02:51:29 +00:00
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: commons/bot-agents#19