Skip to content

fix: auto-refresh stale agent token on WebSocket failure - #67

Merged
khaliqgant merged 4 commits into
mainfrom
fix/ws-stale-token-refresh
Mar 13, 2026
Merged

fix: auto-refresh stale agent token on WebSocket failure#67
khaliqgant merged 4 commits into
mainfrom
fix/ws-stale-token-refresh

Conversation

@khaliqgant

@khaliqgant khaliqgant commented Mar 12, 2026

Copy link
Copy Markdown
Member

Summary

  • Fixes persistent WebSocket connection failures in the dashboard caused by externally-rotated agent tokens
  • The dashboard server cached at_live_ tokens in memory and never validated them, so when another process (workflow restart, broker spawn, etc.) called registerOrRotate for the same agent name, the cached token became permanently stale
  • Page refresh didn't help because the server kept returning the same invalid cached token

Changes

Server-side (3 files):

  • relaycast-provider-helpers.ts: Export clearRegistrationCache() to flush the in-process registration promise cache
  • proxy-server.ts: Add clearCachedAgentToken() that clears both inMemoryAgentToken and the registration cache
  • relay-config.ts: Support ?refresh=true query param on GET /api/relay-config to force cache clear + re-registration
  • types.ts: Add clearCachedAgentToken to RouteContext interface

Client-side (1 file):

  • RelayConfigProvider.tsx: Add TokenRefreshMonitor component that watches WebSocket connection status. When it stays in reconnecting for >10s, re-fetches /api/relay-config?refresh=true to get a fresh token, causing RelayProvider to remount with the valid token

Root cause

The @relaycast/react RelayProvider uses an at_live_ agent token for its WebSocket connection. Unlike workspace tokens (rk_live_), agent tokens get rotated when registerOrRotate is called for an existing agent. The dashboard server cached the token in two places (inMemoryAgentToken and registrationCache Map) that were never cleared, so any external rotation left the dashboard permanently broken until the server process restarted.

Test plan

  • Verify dashboard WebSocket connects normally on fresh start
  • Simulate token rotation: call the agent's rotateToken endpoint externally, confirm WS recovers within ~15s
  • Verify page refresh works immediately after the auto-refresh kicks in
  • Confirm no unnecessary token rotations during normal operation (monitor network tab for /api/relay-config?refresh=true calls)

🤖 Generated with Claude Code


Open with Devin

When an external process rotates the dashboard's agent token (via
registerOrRotate or spawn), the cached token becomes invalid but the
dashboard keeps returning it. This causes persistent WebSocket failures
that survive page refresh.

Server: add ?refresh=true param to GET /api/relay-config that clears
both the in-memory token cache and the registration promise cache,
forcing a fresh registerOrRotate call.

Client: add TokenRefreshMonitor that detects when WebSocket stays in
'reconnecting' state for >10s and re-fetches config with refresh=true,
causing RelayProvider to remount with the new valid token.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 5 additional findings.

Open in Devin Review

@khaliqgant
khaliqgant merged commit ca2ab5b into main Mar 13, 2026
1 check passed
@khaliqgant
khaliqgant deleted the fix/ws-stale-token-refresh branch March 13, 2026 10:35
github-actions Bot added a commit that referenced this pull request Mar 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant