← Back to PRs

#8805: [Bug Fix][AI-assisted] Refresh Copilot token before expiry and retry on auth errors

by Arthur742Ramos open 2026-02-04 12:14 View on GitHub →
agents stale
## Summary GitHub Copilot API tokens expire after ~30 minutes. When OpenClaw spawns a long-running subagent using Copilot as the provider, the token expires mid-session with no recovery mechanism, causing 401 auth errors and session failures. Fixes #8808 ## Problem 1. `resolveCopilotApiToken()` exchanges a GitHub token for a Copilot API token once at run start 2. The token is set via `authStorage.setRuntimeApiKey()` (runtime override, not persisted) 3. Unlike OAuth tokens in `auth-profiles.json`, runtime overrides bypass the normal refresh logic 4. Sessions running >30 minutes hit expired tokens with no automatic refresh or retry ## Solution This PR adds: - **Periodic token refresh**: Schedules refresh 5 minutes before token expiry (`COPILOT_REFRESH_MARGIN_MS`) - **Auth error retry**: On 401/auth errors, refreshes token once and retries the attempt - **Per-attempt retry reset**: Uses `authRetryPending` pattern to allow fresh retry after each successful request - **Timer cleanup**: `copilotRefreshCancelled` flag prevents timer leaks on shutdown ## Testing - [x] 3 new unit tests added: - `refreshes copilot token after auth error and retries once` - `allows another auth refresh after a successful retry` - `does not reschedule copilot refresh after shutdown` - [x] All 11 auth rotation tests pass - [x] Build succeeds (`pnpm build`) - [x] Lightly tested locally (token refresh logic verified via mocks) ## AI Disclosure 🤖 - [x] **AI-assisted**: This fix was developed with GitHub Copilot CLI assistance - [x] **Testing level**: Fully tested with unit tests - [x] **Understanding**: I confirm understanding of the code changes The AI helped identify the root cause (runtime token injection bypassing OAuth refresh), designed the solution (proactive refresh + reactive retry), and wrote tests. Code was reviewed for correctness. <!-- greptile_comment --> <h2>Greptile Overview</h2> <h3>Greptile Summary</h3> This PR adds proactive and reactive refresh handling for the `github-copilot` provider inside the embedded PI runner. - In `src/agents/pi-embedded-runner/run.ts`, a `CopilotTokenState` is introduced to track the GitHub token used for Copilot exchange, the Copilot token expiry time, and a scheduled refresh timer. The runner now schedules a refresh ~5 minutes before expiry, retries refresh after failure, and performs a one-time refresh+retry when an auth failure is detected (both for `promptError` and assistant-side auth errors). - In `src/agents/pi-embedded-runner.run-embedded-pi-agent.auth-profile-rotation.test.ts`, new unit tests mock `resolveCopilotApiToken()` and validate: (1) auth-error retry behavior, (2) retry state resets after a successful request, and (3) refresh timers do not reschedule after shutdown. Overall, the change fits into the existing auth-profile rotation loop by treating Copilot’s exchanged API token as a runtime override that needs its own refresh lifecycle. <h3>Confidence Score: 4/5</h3> - This PR is likely safe to merge; changes are localized and covered by new tests, with a few edge cases worth tightening. - Token refresh logic is contained to the Copilot provider path and includes timer cleanup plus retry limiting via `authRetryPending`. Main risks are edge-case loops (near-expiry scheduling) and retry behavior in the presence of invalid GitHub credentials, which could degrade failover behavior rather than break correctness broadly. - src/agents/pi-embedded-runner/run.ts (refresh scheduling and auth-retry conditions) <!-- greptile_other_comments_section --> <sub>(3/5) Reply to the agent's comments like "Can you suggest a fix for this @greptileai?" or ask follow-up questions!</sub> **Context used:** - Context from `dashboard` - CLAUDE.md ([source](https://app.greptile.com/review/custom-context?memory=fd949e91-5c3a-4ab5-90a1-cbe184fd6ce8)) - Context from `dashboard` - AGENTS.md ([source](https://app.greptile.com/review/custom-context?memory=0d0c8278-ef8e-4d6c-ab21-f5527e322f13)) <!-- /greptile_comment -->

Most Similar PRs