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
The in-place update ran entirely inside c.Request.Context(). Browsers and
reverse proxies commonly abort long-idle requests (axios global timeout
30s, nginx proxy_read_timeout 60s by default), which canceled the request
context mid-download and killed every slow update with
'download failed: context canceled' while the version stayed unchanged.
Users behind slow GitHub links saw the update button fail at a wall-clock
ceiling (~60s) on every attempt (#4504).
- Run PerformUpdate and RollbackToVersion on a context detached from the
request (context.WithoutCancel) and bounded by a 15-minute deadline so
the 10-minute GitHub download client owns its own timeout. A client
disconnect no longer aborts the binary swap; retries then hit the
system operation lock or report 'Already up to date'.
- Raise the frontend timeout for the update/rollback calls from the
global 30s axios default to 15 minutes so the browser can actually
wait for the result.
Fixes#4504
The Codex models manifest path returned upstream 401s straight to the
client without feeding them into the account state machinery. A revoked
or invalidated OAuth account therefore stayed active and schedulable,
kept being selected for subsequent /models requests, and produced
repeated 502s until an admin ran a manual connection test (#4544).
- Route ChatGPT-backend manifest 401s through the shared upstream-error
handling: token cache invalidation, temp-unschedulable cooldown for
refreshable OAuth accounts, permanent disable for
token_revoked/token_invalidated, plus the runtime scheduling block.
- Treat ChatGPT-backend manifest 401s as failover-eligible so the
current /models request can switch to a healthy account instead of
returning 502. Custom API key upstream 401s keep the existing
no-failover, no-disable behavior since their /models auth is not
authoritative for the account.
- Skip Agent Identity accounts: their 401s can be task-scoped and have
a dedicated recovery flow.
- Attach the selected account to the ops error-log context so /models
failures record the account_id.
Fixes#4544
Co-authored-by: Cursor <cursoragent@cursor.com>
Route first-turn pre-response transport, HTTP, and SSE failures through the existing account failover path without replaying later turns. Require a real Responses terminal event and preserve platform-specific OpenAI/Grok error side effects.
ProviderSet 提供了 NewPromptAdminHandler,也绑定了 PromptEngine,却没有为
PromptAdminService 绑定实现,导致 go generate ./cmd/server 直接失败:
no provider found for securityaudit.PromptAdminService
needed by *securityaudit.PromptAdminHandler
*PromptService 本就实现了该接口的全部方法,wire_gen.go 也一直是手工维护到位的
(补上绑定后重新生成的结果与现有文件逐字节一致),只是生成这条路被堵死了,
后续任何依赖改动都无法再靠 go generate 同步。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VHreE5pzCkSYz7J45fmd2Y
Use *string for AnthropicResponse.StopReason so streaming message_start
serializes as JSON null instead of "", matching official Anthropic wire
format and avoiding strict client turn-finalization failures.
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