Grok OAuth 'test connection' reused the production GrokTokenProvider
request path, whose eligibility gate rejects any account that is not
currently schedulable (manual switch off, rate limited, overloaded,
temporarily cooled down). Every such test failed before reaching xAI
with the generic 'oauth refresh account state changed', while
Codex/OpenAI account tests read credentials regardless of scheduling
state (#4598).
Add GetAccessTokenForManualTest and use it from the account test
service:
- skips the request-path scheduling eligibility gate so admins can
probe excluded accounts; credential integrity checks (configured
proxy present, refresh token present) still apply
- refreshes expired tokens through the shared OAuthRefreshAPI without
the request-path marker, so the lock protocol and DB re-read keep
working while scheduling state no longer blocks the refresh;
credential rotation for non-active accounts stays blocked inside
RefreshIfNeeded
- falls back to the still-valid current token when a refresh attempt
fails or another worker holds the refresh lock, and otherwise
surfaces the concrete refresh error instead of the generic message
Fixes#4598
Reconcile with #4539 (grok media account model mapping), now on main:
- handler/grok_media.go non-failover error path keeps both changes —
#4539's grokMediaScheduleModel(account, routingModel, nil) schedule
attribution and this branch's IsResponseCommitted guard
- auto-merged sections verified: routing/classify use #4539's routingModel,
video lookup owner-binding and no-failover semantics intact, ForwardGrokMedia
keeps mapping block (skipped for lookup endpoints via RequiresRequestBody),
empty-image failover, and video-status URL rewrite in order
Resolve conflicts with main:
- service/grok_media.go: keep both post-response blocks — #4497's empty
image-output failover (main) runs first for image endpoints, then this
branch's video-status content-URL rewrite; the endpoint conditions are
mutually exclusive
- handler/openai_gateway_credential_failover_loop_test.go: mark the stub
OAuth accounts media-eligible via the grok_media_eligible extra override,
because this branch moved grok media failover coverage to the generation
endpoint, which is now gated by #4540's paid-eligibility probe on main
Resolve conflicts with main:
- handler/grok_media_test.go: keep both new tests (schedule model test from
this branch, eligibility gating tests from #4540)
- service/openai_gateway_grok_test.go: keep both new tests; update the image
cases of the mapping table test to return a non-empty image payload because
#4497 (already on main) now converts empty image responses into an upstream
failover error