Skip to content

fix(acp): recover stale OAuth on long-lived ACP sessions (all hosts)#70465

Open
joelbrilliant wants to merge 2 commits into
NousResearch:mainfrom
joelbrilliant:feat/acp-oauth-stale-token-recovery
Open

fix(acp): recover stale OAuth on long-lived ACP sessions (all hosts)#70465
joelbrilliant wants to merge 2 commits into
NousResearch:mainfrom
joelbrilliant:feat/acp-oauth-stale-token-recovery

Conversation

@joelbrilliant

@joelbrilliant joelbrilliant commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Summary

General ACP reliability fix. Any long-lived ACP host can abort turns after idle with a stale OAuth access token, while Telegram / Discord / gateway / CLI on the same HERMES_HOME keep working.

Typical error:

HTTP 403: {"code":"unauthenticated:bad-credentials",
 "error":"The OAuth2 access token could not be validated."}

Who is affected

Surface Affected?
Any long-lived ACP host (Zed, VS Code ACP client, JetBrains, Buzz, custom hermes acp stdio hosts) Yes — process stays up, token goes stale
Telegram / Discord / gateway No — already pass credential_pool into AIAgent
Short-lived CLI turns Usually no — fresh process re-resolves credentials

Buzz Desktop dogfood is how we found it (owner-only Rocky after ~3h idle). The bug is in Hermes ACP construction and OAuth recovery, not in Buzz.

Root cause

  1. ACP session construction called resolve_runtime_provider but did not pass credential_pool into AIAgent. Gateway/CLI do. Without the pool, _recover_with_credential_pool is a no-op on the ACP path.
  2. xAI (and similar OAuth providers) often return HTTP 403 for a stale access token, not only 401. Singleton refresh only ran on 401, and generic 403 auth did not set should_rotate_credential.

Result: idle ACP → first multimodal or text turn after hours → non-retryable 403 → user thinks they must reauth, even though gateway still works on the same profile.

Fix

  • Forward credential_pool from resolve_runtime_provider in ACP _make_agent (match gateway/CLI)
  • Classify generic 403 auth with should_rotate_credential=True (billing/spend-limit 403s unchanged)
  • Singleton xAI/Codex refresh on 403 when classifier says auth, not only 401

No config migration. Default editor behaviour unchanged when credentials are fresh.

Test plan

Related

ACP sessions omitted credential_pool from resolve_runtime_provider while
gateway/CLI pass it through. After idle, xAI returns HTTP 403
bad-credentials for a stale access token; without the pool the turn
aborted as non-retryable while Telegram/Desktop on the same home kept
working.

- Forward credential_pool into AIAgent from ACP session construction
- Treat generic 403 auth like 401 for should_rotate_credential
- Singleton xAI/Codex refresh also on 403 when classified as auth
@joelbrilliant joelbrilliant changed the title fix(acp): recover stale OAuth on long-lived ACP sessions fix(acp): recover stale OAuth on long-lived ACP sessions (all hosts) Jul 24, 2026
@joelbrilliant

Copy link
Copy Markdown
Contributor Author

Reframed for maintainers: this is not Buzz-specific.

Any long-lived hermes acp host (Zed, VS Code ACP, JetBrains, custom stdio hosts) can hit the same idle → 403 bad-credentials abort while Telegram/gateway on the same home stay healthy. Root cause is ACP omitting credential_pool + 403-only-as-auth recovery; gateway already did the right thing.

Buzz dogfood was the discovery path only.

@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/acp Agent Communication Protocol adapter comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint provider/openai OpenAI / Codex Responses API provider/xai xAI (Grok) area/auth Authentication, OAuth, credential pools sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state labels Jul 24, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Related to #70293: both repair ACP credential-pool handoff, while this patch also changes generic 403 auth classification and the Codex/xAI refresh retry path. The mechanisms overlap but are not redundant.

Generic OpenRouter 403 auth must keep should_rotate_credential=False
(historical behaviour). Enable rotation for xAI/Codex/Nous and explicit
bad-credentials / OAuth2-validation bodies only.
@joelbrilliant

Copy link
Copy Markdown
Contributor Author

Relationship to #70293

Thanks for the triage note. Fully agree these overlap but are not redundant.

Piece #70293 This PR (#70465)
Forward credential_pool into ACP AIAgent yes yes (same intent)
403 bad-credentials / OAuth-shaped auth → rotate+refresh (not only 401) no yes
Classifier: keep generic OpenRouter 403 auth without rotate n/a yes (CI-fixed)

Suggested landing order (happy either way):

  1. Prefer merging fix(acp): forward resolved credential pool #70293 first if maintainers want the minimal pool-handoff alone.
  2. We will rebase this PR onto main after that and drop the duplicated credential_pool line if it is already present, keeping only the 403 recovery path (needed for xAI SuperGrok OAuth, which often returns 403 not 401 for a stale access token).
  3. Or merge this PR as the fuller fix if that is simpler for review.

Dogfood: same HERMES_HOME had Telegram healthy while long-lived ACP aborted after ~3h idle with xAI 403 bad-credentials. Pool handoff alone is necessary; the 403 refresh path is what makes idle ACP recover without restart/reauth for that provider.

No conflict intended with @stefanpieter — happy to reshape this PR however maintainers prefer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/auth Authentication, OAuth, credential pools comp/acp Agent Communication Protocol adapter comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P2 Medium — degraded but workaround exists provider/openai OpenAI / Codex Responses API provider/xai xAI (Grok) sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants