diff --git a/assets/pr-screenshots/main-reauth-cancel-retryable.png b/assets/pr-screenshots/main-reauth-cancel-retryable.png new file mode 100644 index 0000000000..306725d842 Binary files /dev/null and b/assets/pr-screenshots/main-reauth-cancel-retryable.png differ diff --git a/docs-site/src/content/docs/fr/guides/codex-integration.md b/docs-site/src/content/docs/fr/guides/codex-integration.md index 8fff31edaf..dd1d5f97dd 100644 --- a/docs-site/src/content/docs/fr/guides/codex-integration.md +++ b/docs-site/src/content/docs/fr/guides/codex-integration.md @@ -424,3 +424,7 @@ Une transition de fournisseur peut renvoyer `history_paginated_requires_native_w Lors du retour au mode de remplacement de l’URL racine, OpenCodex conserve la définition `[model_providers.opencodex]` existante avant de valider la configuration, même si la vérification préalable de l’historique réussit. Les anciennes conversations `opencodex` peuvent ainsi toujours retrouver leur fournisseur si Codex migre l’historique après cette validation ou pendant le démarrage du traitement en arrière-plan. Les nouvelles conversations utilisent le fournisseur racine sélectionné ; la restauration explicite conserve ses contrôles de suppression distincts. Ne réécrivez pas un historique paginé actif ni une ligne de conversation pour forcer une migration. Fermez la conversation avant toute récupération et signalez l’erreur exacte et les versions sans publier de données privées. Une sauvegarde ou le succès d’un script ne prouve pas le rétablissement de l’affichage : vérifiez la conversation après réouverture de Codex. + +## Annulation de la réauthentification du compte principal + +Lors de l’annulation de la réauthentification du compte principal par code d’appareil, un échec temporaire de DELETE, une erreur réseau ou une réponse dont le statut est inconnu ou non terminal conserve le flux actif et l’indication d’échec de l’annulation afin de permettre une nouvelle tentative. L’interrogation périodique du statut continue normalement pour détecter une connexion qui aboutit entre-temps. Si un échec d’annulation permettant une nouvelle tentative coïncide avec une réponse GET de statut HTTP hors 2xx alors que le flux est `pending` ou `committing`, l’ordre d’arrivée des réponses ne change rien : l’annulation peut être retentée sur le même flux, avec le dernier code d’appareil, la dernière URL de vérification et la dernière phase fournis par le serveur. L’échec HTTP de GET arrête toujours l’interrogation périodique, mais l’annulation reste possible sans lancer un second POST de connexion. Une réponse terminale `failed` libère le flux et affiche la raison d’échec normalisée ; seul le statut `succeeded` signale une connexion réussie. Une réponse confirmant `cancelled` libère le flux et permet de lancer une nouvelle connexion par code d’appareil. Une réponse HTTP 404 définitive avec le code `unknown_flow` libère également l’identifiant du flux expiré pour permettre une nouvelle connexion par code d’appareil, sans signaler une connexion réussie ni une annulation confirmée. Les réponses POST, GET ou DELETE tardives d’un ancien flux ne peuvent ni modifier le nouveau flux ni signaler une connexion réussie pour celui-ci. diff --git a/docs-site/src/content/docs/guides/codex-integration.md b/docs-site/src/content/docs/guides/codex-integration.md index 65e1201acc..0b73309af8 100644 --- a/docs-site/src/content/docs/guides/codex-integration.md +++ b/docs-site/src/content/docs/guides/codex-integration.md @@ -815,6 +815,10 @@ If the new OAuth credential's authenticated usage lookup confirms an exhausted 5 Background revalidation is separate and off by default. It requires Token Guardian, the `openai` provider's `proactive` refresh policy, and `tokenGuardian.codexWarmupEnabled`. It skips accounts awaiting deferred registration validation. +### Cancelling main-account device reauthentication + +When cancelling main-account device reauthentication, a temporary DELETE or network failure, or a response with an unknown or nonterminal status, keeps the active flow and the cancellation-failure indication so cancellation can be retried. Status polling normally continues so a login that completes can still be detected. If a retryable cancellation failure overlaps a non-2xx GET status response while the flow is `pending` or `committing`, either response order preserves cancellation retry on that same flow, with its last server-provided device code, verification URL, and phase. The GET HTTP failure still stops polling, but cancellation can be retried without starting a second login POST. A terminal `failed` response releases the flow and displays the normalized failure reason; only `succeeded` reports login success. A confirmed `cancelled` response releases the flow so a new device login can be started. A definitive HTTP 404 response with code `unknown_flow` also releases the expired flow ID so a new device login can be started, but does not report a successful login or confirmed cancellation. Late POST, GET, or DELETE responses from an earlier flow cannot change the new flow or report login success for it. + ### Why an account stopped serving requests When an account leaves pool selection, the reason travels with the decision instead of being recomputed for display, so a surface can never report an account healthy while routing is dropping it. `GET /api/codex-auth/accounts` carries `reauthReason` next to `needsReauth` on each account: `missing_credential` for a credential that was never stored, `refresh_failed` for a credential refresh that keeps failing, and `quota_unauthorized` when the usage lookup itself was rejected. diff --git a/docs-site/src/content/docs/ja/guides/codex-integration.md b/docs-site/src/content/docs/ja/guides/codex-integration.md index 4f6afdb37e..56c69f388e 100644 --- a/docs-site/src/content/docs/ja/guides/codex-integration.md +++ b/docs-site/src/content/docs/ja/guides/codex-integration.md @@ -286,3 +286,7 @@ opencodex が管理対象 [バックグラウンドサービス](/reference/cli/ ルート URL 上書き方式に戻すとき、履歴の事前確認が成功していても、OpenCodex は設定を確定する前に既存の `[model_providers.opencodex]` 定義を保持します。確定後やバックグラウンドの履歴処理開始中に Codex が履歴形式を移行しても、以前の `opencodex` 会話はプロバイダーを引き続き解決できます。新しい会話は選択されたルートプロバイダーを使い、明示的な復元には従来の個別の削除チェックが適用されます。 会話を移行しようとして使用中のページ分割履歴やスレッド行を書き換えないでください。復元前に対象の会話を閉じ、個人の履歴を公開せず正確なエラーとバージョンを報告してください。バックアップやスクリプトの成功だけでは表示の復元は証明されません。再度開いた Codex で確認してください。 + +## メインアカウントの再認証のキャンセル + +メインアカウントのデバイスコードによる再認証をキャンセルする際、DELETE リクエストの一時的な失敗、ネットワークエラー、または不明もしくは非終端のステータスを持つ応答が発生した場合は、実行中のフローとキャンセル失敗の表示を維持し、キャンセルを再試行できるようにします。通常はステータスのポーリングも続き、ログインが完了した場合に検出できます。フローが `pending` または `committing` のときに、再試行可能なキャンセル失敗と GET ステータス取得の 2xx 以外の HTTP 応答が重なった場合は、応答の到着順にかかわらず、サーバーから最後に取得したデバイスコード、確認 URL、フェーズを保持または復元し、同じフローのキャンセルを再試行できます。GET の HTTP 失敗でポーリングは停止しますが、2 回目のログイン POST を送らずにキャンセルを再試行できます。終端ステータス `failed` の応答ではフローを解放し、正規化された失敗理由を表示します。ログイン成功として扱うのは `succeeded` の場合だけです。`cancelled` が確認された応答ではフローを解放し、新しいデバイスコードログインを開始できるようにします。HTTP 404 と `unknown_flow` コードによる確定的な応答でも、期限切れのフロー ID を解放して新しいデバイスコードログインを開始できるようにしますが、ログイン成功やキャンセル確定とは表示しません。以前のフローから遅れて届いた POST、GET、DELETE の応答が、新しいフローを変更したり、そのログインを成功と報告したりすることはありません。 diff --git a/docs-site/src/content/docs/ko/guides/codex-integration.md b/docs-site/src/content/docs/ko/guides/codex-integration.md index 0d92b524e5..f1de9ec20a 100644 --- a/docs-site/src/content/docs/ko/guides/codex-integration.md +++ b/docs-site/src/content/docs/ko/guides/codex-integration.md @@ -390,3 +390,7 @@ opencodex가 managed [background service](/reference/cli/#ocx-service)로 실행 루트 URL 재정의 방식으로 돌아갈 때 OpenCodex는 기록 사전 점검이 통과하더라도 기존 `[model_providers.opencodex]` 정의를 설정 적용 전에 유지합니다. 설정 적용 후나 백그라운드 기록 작업 시작 중에 Codex가 기록 형식을 전환해도 이전 `opencodex` 대화가 제공자를 계속 찾을 수 있습니다. 새 대화는 선택된 루트 제공자를 사용하며, 명시적 복원에는 기존의 별도 제거 검사가 적용됩니다. 대화를 강제로 이전하려고 실행 중인 페이지 분할 대화 원본이나 스레드 행을 고치지 마세요. 복구 전에 해당 대화를 닫은 뒤, 개인 대화 내용을 올리지 말고 정확한 오류와 버전을 보고하세요. 백업이나 스크립트 성공만으로 표시 복구가 증명되지는 않으므로 Codex를 다시 열어 확인하세요. + +## 메인 계정 재인증 취소 + +메인 계정의 기기 코드 재인증을 취소할 때 DELETE 요청의 일시적 실패, 네트워크 오류, 알 수 없거나 아직 종료되지 않은 상태의 응답이 발생하면 진행 중인 흐름과 취소 실패 표시를 유지하여 취소를 다시 시도할 수 있게 합니다. 일반적으로는 상태 조회도 계속하므로 로그인이 완료되면 이를 확인할 수 있습니다. 흐름이 `pending` 또는 `committing`일 때 재시도 가능한 취소 실패와 GET 상태 조회의 2xx 이외 HTTP 응답이 겹치면, 응답 도착 순서와 관계없이 서버가 마지막으로 제공한 기기 코드·확인 URL·진행 단계를 유지하거나 복원하여 같은 흐름의 취소를 다시 시도할 수 있게 합니다. GET의 HTTP 실패는 상태 조회를 종료하지만, 두 번째 로그인 POST를 보내지 않고 취소를 다시 시도할 수 있습니다. 종료 상태인 `failed` 응답은 흐름을 해제하고 정규화된 실패 사유를 표시하며, `succeeded` 응답만 로그인 성공을 알립니다. `cancelled`로 확인된 응답은 흐름을 해제하여 새 기기 코드 로그인을 시작할 수 있게 합니다. HTTP 404와 `unknown_flow` 코드가 명확하게 반환된 경우에도 만료된 흐름 ID를 해제하여 새 기기 코드 로그인을 시작할 수 있게 하지만, 로그인 성공이나 취소 확정으로 표시하지 않습니다. 이전 흐름에서 늦게 도착한 POST·GET·DELETE 응답은 새 흐름을 변경하거나 새 흐름의 로그인이 성공했다고 알릴 수 없습니다. diff --git a/docs-site/src/content/docs/ru/guides/codex-integration.md b/docs-site/src/content/docs/ru/guides/codex-integration.md index 1394091fe9..4f31843480 100644 --- a/docs-site/src/content/docs/ru/guides/codex-integration.md +++ b/docs-site/src/content/docs/ru/guides/codex-integration.md @@ -418,3 +418,7 @@ ocx restore back # point plain Codex at the running proxy again При возврате к режиму переопределения корневого URL OpenCodex сохраняет существующее определение `[model_providers.opencodex]` до фиксации конфигурации, даже если предварительная проверка истории успешна. Поэтому старые разговоры `opencodex` сохраняют доступ к своему провайдеру, если Codex преобразует историю после фиксации или во время запуска фоновой обработки. Новые разговоры используют выбранный корневой провайдер; явное восстановление по-прежнему выполняет отдельные проверки удаления. Не переписывайте активную постраничную историю или строку треда, чтобы самостоятельно перенести разговоры. Закройте разговор перед восстановлением и сообщите точную ошибку и версии без публикации личной истории. Наличие резервной копии или успешный скрипт не доказывает восстановление отображения: проверьте разговор после повторного открытия Codex. + +## Отмена повторной аутентификации основного аккаунта + +При отмене повторной аутентификации основного аккаунта по коду устройства временный сбой DELETE, сетевая ошибка или ответ с неизвестным либо нетерминальным статусом сохраняет активный процесс и индикацию ошибки отмены, чтобы отмену можно было повторить. Обычно опрос статуса продолжается, позволяя обнаружить завершившийся вход. Если при состоянии `pending` или `committing` ошибка отмены, допускающая повторную попытку, совпадает с HTTP-ответом GET вне диапазона 2xx, порядок получения ответов не влияет на возможность повторить отмену того же процесса: сохраняются или восстанавливаются последние полученные от сервера код устройства, URL подтверждения и состояние. HTTP-ошибка GET по-прежнему останавливает опрос, но отмену можно повторить без второго POST для запуска входа. Терминальный ответ `failed` освобождает процесс и показывает нормализованную причину ошибки; только `succeeded` сообщает об успешном входе. Подтверждённый ответ `cancelled` освобождает процесс, позволяя начать новый вход по коду устройства. Однозначный ответ HTTP 404 с кодом `unknown_flow` также освобождает идентификатор истёкшего процесса и позволяет начать новый вход по коду устройства, но не сообщает об успешном входе или подтверждённой отмене. Запоздавшие ответы POST, GET или DELETE от предыдущего процесса не могут изменить новый процесс или сообщить об успешном входе в нём. diff --git a/docs-site/src/content/docs/tr/guides/codex-integration.md b/docs-site/src/content/docs/tr/guides/codex-integration.md index 17a8630c21..e1ce40af77 100644 --- a/docs-site/src/content/docs/tr/guides/codex-integration.md +++ b/docs-site/src/content/docs/tr/guides/codex-integration.md @@ -475,3 +475,7 @@ Etkilenen geçmiş deposu sayfalamayı destekliyorsa sağlayıcı değişimi `hi Kök URL geçersiz kılma biçimine dönülürken OpenCodex, geçmiş ön kontrolü başarılı olsa bile yapılandırmayı kaydetmeden önce mevcut `[model_providers.opencodex]` tanımını korur. Böylece Codex, kayıttan sonra veya arka plan geçmiş işlemi başlarken geçmiş biçimini değiştirirse eski `opencodex` konuşmaları sağlayıcılarını bulmaya devam eder. Yeni konuşmalar seçili kök sağlayıcıyı kullanır; açıkça istenen geri yükleme, mevcut ayrı kaldırma kontrollerini korur. Konuşmaları kendiniz taşımak için etkin sayfalanmış geçmişi veya iş parçacığı satırını yeniden yazmayın. Kurtarmadan önce konuşmayı kapatın ve özel geçmişi yayımlamadan tam hatayı ve sürümleri bildirin. Yedek veya başarılı betik görüntünün düzeldiğini kanıtlamaz; Codex’i yeniden açıp konuşmayı kontrol edin. + +## Ana hesabın yeniden kimlik doğrulamasını iptal etme + +Ana hesabın cihaz koduyla yeniden kimlik doğrulaması iptal edilirken geçici bir DELETE hatası, ağ hatası ya da bilinmeyen veya sonlanmamış bir durum içeren yanıt alınırsa etkin akış ve iptal hatası göstergesi korunur; böylece iptal yeniden denenebilir. Tamamlanan bir girişin algılanabilmesi için durum sorgulaması normalde devam eder. Akış `pending` veya `committing` durumundayken yeniden denenebilir bir iptal hatası ile GET durum sorgusunun 2xx dışı HTTP yanıtı çakışırsa yanıtların geliş sırasından bağımsız olarak aynı akışın iptali yeniden denenebilir; sunucudan alınan son cihaz kodu, doğrulama URL’si ve aşama korunur veya geri yüklenir. GET HTTP hatası durum sorgulamasını yine durdurur, ancak ikinci bir giriş POST isteği başlatılmadan iptal yeniden denenebilir. Son durum olan `failed` yanıtı akışı serbest bırakır ve normalleştirilmiş hata nedenini gösterir; başarılı girişi yalnızca `succeeded` bildirir. Onaylanmış `cancelled` yanıtı akışı serbest bırakarak cihaz koduyla yeni bir giriş başlatılmasını sağlar. `unknown_flow` koduyla gelen kesin bir HTTP 404 yanıtı da süresi dolmuş akış kimliğini serbest bırakarak cihaz koduyla yeni bir giriş başlatılmasını sağlar, ancak girişin başarılı olduğunu veya iptalin onaylandığını bildirmez. Önceki bir akıştan geç gelen POST, GET veya DELETE yanıtları yeni akışı değiştiremez veya yeni akış için başarılı giriş bildiremez. diff --git a/docs-site/src/content/docs/zh-cn/guides/codex-integration.md b/docs-site/src/content/docs/zh-cn/guides/codex-integration.md index 13612608e9..4643248dfe 100644 --- a/docs-site/src/content/docs/zh-cn/guides/codex-integration.md +++ b/docs-site/src/content/docs/zh-cn/guides/codex-integration.md @@ -361,3 +361,7 @@ ocx restore back # point plain Codex at the running proxy again 返回根 URL 覆盖模式时,即使历史预检通过,OpenCodex 也会在提交配置前保留已有的 `[model_providers.opencodex]` 定义。这样,即使 Codex 在提交后或后台历史任务启动时迁移历史格式,旧的 `opencodex` 对话仍能找到其提供商。新对话继续使用所选的根提供商;显式恢复仍执行原有的独立删除检查。 不要改写正在使用的分页历史文件或线程行来自行迁移这些会话。恢复前关闭相关会话,并只报告准确的错误和版本,不要公开私人历史。备份或脚本成功并不能证明显示已恢复;重新打开 Codex 后检查会话。 + +## 取消主账号重新认证 + +取消主账号的设备代码重新认证时,如果 DELETE 请求暂时失败、发生网络错误,或响应状态未知或尚未结束,系统会保留当前流程和取消失败提示,以便重试取消。通常状态轮询会继续,因此仍能检测到登录完成。如果流程处于 `pending` 或 `committing` 状态时,可重试的取消失败与 GET 状态查询的非 2xx HTTP 响应同时发生,无论响应到达顺序如何,系统都会保留或恢复服务器最后提供的设备代码、验证 URL 和阶段,使同一流程仍可重试取消。GET 的 HTTP 失败仍会停止轮询,但无需发送第二次登录 POST 即可重试取消。终止状态为 `failed` 的响应会释放流程并显示规范化的失败原因,只有 `succeeded` 才表示登录成功。确认状态为 `cancelled` 的响应会释放流程,以便开始新的设备代码登录。明确返回 HTTP 404 且代码为 `unknown_flow` 的响应也会释放已过期的流程 ID,以便开始新的设备代码登录,但不会显示登录成功或已确认取消。先前流程中延迟到达的 POST、GET 或 DELETE 响应不能改变新流程,也不能将新流程报告为登录成功。 diff --git a/docs-site/src/content/docs/zh-tw/guides/codex-integration.md b/docs-site/src/content/docs/zh-tw/guides/codex-integration.md index f7bfefac13..274ae98459 100644 --- a/docs-site/src/content/docs/zh-tw/guides/codex-integration.md +++ b/docs-site/src/content/docs/zh-tw/guides/codex-integration.md @@ -368,3 +368,7 @@ ocx restore back # 讓普通 Codex 再次指向仍在執行的 proxy 返回根 URL 覆寫模式時,即使歷史預檢通過,OpenCodex 也會在提交設定前保留既有的 `[model_providers.opencodex]` 定義。如此一來,即使 Codex 在提交後或背景歷史工作啟動時遷移歷史格式,舊的 `opencodex` 對話仍能找到其提供者。新對話繼續使用所選的根提供者;明確要求的還原仍執行原有的獨立刪除檢查。 請勿改寫使用中的分頁歷史檔案或執行緒列來自行遷移這些對話。復原前關閉相關對話,只回報確切錯誤與版本,不要公開私人歷史。備份或指令碼成功不能證明顯示已復原;重新開啟 Codex 後確認對話。 + +## 取消主帳號重新驗證 + +取消主帳號的裝置代碼重新驗證時,如果 DELETE 請求暫時失敗、發生網路錯誤,或回應狀態未知或尚未結束,系統會保留目前的流程和取消失敗提示,以便重試取消。通常狀態輪詢會繼續,因此仍能偵測到登入完成。如果流程處於 `pending` 或 `committing` 狀態時,可重試的取消失敗與 GET 狀態查詢的非 2xx HTTP 回應同時發生,無論回應抵達順序如何,系統都會保留或還原伺服器最後提供的裝置代碼、驗證 URL 和階段,讓同一流程仍可重試取消。GET 的 HTTP 失敗仍會停止輪詢,但無須傳送第二次登入 POST 即可重試取消。終止狀態為 `failed` 的回應會釋放流程並顯示正規化的失敗原因,只有 `succeeded` 才表示登入成功。確認狀態為 `cancelled` 的回應會釋放流程,以便開始新的裝置代碼登入。明確回傳 HTTP 404 且代碼為 `unknown_flow` 的回應也會釋放已過期的流程 ID,以便開始新的裝置代碼登入,但不會顯示登入成功或已確認取消。先前流程中延遲抵達的 POST、GET 或 DELETE 回應不能改變新流程,也不能將新流程回報為登入成功。 diff --git a/gui/.react-doctor-ignores.md b/gui/.react-doctor-ignores.md index 8dc3301953..f5770a0f6b 100644 --- a/gui/.react-doctor-ignores.md +++ b/gui/.react-doctor-ignores.md @@ -17,3 +17,13 @@ Re-enable a rule when the matching architecture debt is paid down. | `rerender-state-only-in-handlers` | Dirty/modal id state is used for control flow outside JSX text. | | `prefer-use-effect-event` | Optional React 19 polish; deferred to avoid mixed patterns mid-cleanup. | | `js-combine-iterations` | Readability preferred over micro one-pass rewrites on small lists. | + +## Local response-body exceptions + +`use-main-device-reauth.ts` suppresses `no-fetch-response-used-without-status-check` +only at its three POST/GET/DELETE fetch sites. This API returns failure codes in JSON, +and DELETE needs the HTTP 404 `unknown_flow` body to distinguish an expired flow. +Each path checks HTTP status and flow ownership before interpreting the DTO as a +successful result. Parsing first also allows a late body to be discarded after the +ownership check. `main-device-reauth-ownership.test.tsx` covers non-2xx success-shaped +bodies, delayed replies, once-only completion, and cancellation retry ownership. diff --git a/gui/src/components/codex-account-pool-main-card.tsx b/gui/src/components/codex-account-pool-main-card.tsx index e1439c1439..25af1eb49f 100644 --- a/gui/src/components/codex-account-pool-main-card.tsx +++ b/gui/src/components/codex-account-pool-main-card.tsx @@ -192,7 +192,7 @@ export function CodexAccountPoolMainCard({ {showReauth ?

{t("codexAuth.mainTokenExpired")}

- {mainReauth && (mainReauth.state.phase === "idle" || mainReauth.state.phase === "failed") && ( + {mainReauth && (mainReauth.state.phase === "idle" || mainReauth.state.phase === "failed" || mainReauth.state.phase === "cancelled") && ( <>