From eb5ff6c582d694db96e94e5d0a58ed5dbc6843f3 Mon Sep 17 00:00:00 2001 From: Robin Bially <7304732+RobinBially@users.noreply.github.com> Date: Mon, 7 Sep 2026 09:57:05 +0200 Subject: [PATCH 1/9] feat(gui): add opt-in Codex Desktop sign-in toggle [skip ci] (cherry picked from commit 0f21769f346e64c2c6b2a03ff8d09b3deaab9562) Co-authored-by: RobinBially <7304732+RobinBially@users.noreply.github.com> --- .../content/docs/guides/codex-integration.md | 9 ++ docs/pr-assets/codex-desktop-opt-in.jpg | Bin 0 -> 29051 bytes gui/src/i18n/de.ts | 2 + gui/src/i18n/en.ts | 2 + gui/src/i18n/fr.ts | 2 + gui/src/i18n/ja.ts | 2 + gui/src/i18n/ko.ts | 2 + gui/src/i18n/ru.ts | 2 + gui/src/i18n/tr.ts | 2 + gui/src/i18n/zh-TW.ts | 2 + gui/src/i18n/zh.ts | 2 + gui/src/pages/dashboard-overview-sections.tsx | 28 ++++++- gui/src/pages/dashboard-shared.ts | 2 + gui/src/pages/use-dashboard-data.ts | 23 +++-- gui/tests/vision-sidecar-dashboard.test.tsx | 79 +++++++++++++++++- tests/codex-integration/codex-inject.test.ts | 4 +- 16 files changed, 146 insertions(+), 17 deletions(-) create mode 100644 docs/pr-assets/codex-desktop-opt-in.jpg diff --git a/docs-site/src/content/docs/guides/codex-integration.md b/docs-site/src/content/docs/guides/codex-integration.md index 7d66e72c3f..ff2df04fdd 100644 --- a/docs-site/src/content/docs/guides/codex-integration.md +++ b/docs-site/src/content/docs/guides/codex-integration.md @@ -215,6 +215,15 @@ HTTP/SSE. ### Authless Codex Desktop (opt-in) +In **Dashboard → Overview**, **Open Codex without signing in** controls this existing +opt-in preference. The switch defaults to **off** when the setting is absent or false; +an existing explicit `codexDesktopAuthless: true` stays enabled. The dashboard saves +the preference and runs a full sync. Restart Codex Desktop after changing it. +If synchronization fails, the saved preference remains and the dashboard shows the error; +retry **Sync** before restarting. Account-gated Desktop features may be unavailable +when enabled. Upstream credentials, local eligibility, remote admission authentication +and user-owned gateway settings retain their existing requirements. + Codex Desktop shows its ChatGPT login screen whenever the active provider requires OpenAI auth. If your OpenCodex setup never uses ChatGPT credentials (routed providers only, or a blocked `chatgpt.com`), you can opt out of that gate: diff --git a/docs/pr-assets/codex-desktop-opt-in.jpg b/docs/pr-assets/codex-desktop-opt-in.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d06203e7113cc54e87b1272e272d8f943c5b4805 GIT binary patch literal 29051 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 literal 0 HcmV?d00001 diff --git a/gui/src/i18n/de.ts b/gui/src/i18n/de.ts index 5faab4b356..495104bd42 100644 --- a/gui/src/i18n/de.ts +++ b/gui/src/i18n/de.ts @@ -299,6 +299,8 @@ export const de: Record = { "models.staleBanner": "Codex zeigt eine ältere Modellliste als dieser Katalog. Starte Codex neu, um sie neu zu laden.", "dash.codexAutoStart": "opencodex mit Codex starten", "dash.codexAutoStartHint": "Erlaubt einem installierten Launcher-Shim, ocx ensure auszuführen. Diese Einstellung installiert keinen Neustartschutz; prüfe den effektiven Zustand unter Startsicherheit.", + "dash.codexDesktopAuthless": "Codex ohne Anmeldung öffnen", + "dash.codexDesktopAuthlessHint": "Standardmäßig aus. Überspringt die separate Desktop-Anmeldung bei geeigneten lokalen Verbindungen. Zugangsdaten für den Anbieter bleiben erforderlich. Codex nach einer Änderung neu starten. Kontogebundene Desktop-Funktionen können fehlen.", "dash.searchModel": "Such-Sidecar-Modell", "dash.searchModelHint": "Modell für web_search bei nicht über OpenAI gerouteten Modellen. Erfordert ChatGPT-Login.", "dash.searchReasoning": "Such-Reasoning-Aufwand", diff --git a/gui/src/i18n/en.ts b/gui/src/i18n/en.ts index c71208942f..22a3807858 100644 --- a/gui/src/i18n/en.ts +++ b/gui/src/i18n/en.ts @@ -311,6 +311,8 @@ export const en = { "models.staleBanner": "Codex is showing an older model list than this catalog. Restart Codex to reload it.", "dash.codexAutoStart": "Start opencodex with Codex", "dash.codexAutoStartHint": "Allows an installed launcher shim to run ocx ensure. This setting does not install restart protection; check Startup safety for the effective state.", + "dash.codexDesktopAuthless": "Open Codex without signing in", + "dash.codexDesktopAuthlessHint": "Off by default. Skip the separate Desktop sign-in for eligible local connections. Upstream credentials are still required. Restart Codex after changing this setting. Account-gated Desktop features may be unavailable.", "dash.searchModel": "Search sidecar model", "dash.searchModelHint": "Model used for web_search on non-OpenAI routed models. Requires ChatGPT login.", "dash.searchReasoning": "Search reasoning effort", diff --git a/gui/src/i18n/fr.ts b/gui/src/i18n/fr.ts index e1b3519ef1..9f0f265173 100644 --- a/gui/src/i18n/fr.ts +++ b/gui/src/i18n/fr.ts @@ -301,6 +301,8 @@ export const fr: Record = { "models.staleBanner": "Codex affiche une liste de modèles plus ancienne que ce catalogue. Redémarrez Codex pour la recharger.", "dash.codexAutoStart": "Démarrer opencodex avec Codex", "dash.codexAutoStartHint": "Permet à un mécanisme de lancement installé d’exécuter ocx ensure. Ce réglage n’installe pas de protection au redémarrage ; consultez Sécurité du démarrage pour connaître l’état effectif.", + "dash.codexDesktopAuthless": "Ouvrir Codex sans se connecter", + "dash.codexDesktopAuthlessHint": "Désactivé par défaut. Ignore la connexion Desktop séparée pour les connexions locales admissibles. Les identifiants du fournisseur restent nécessaires. Redémarrez Codex après toute modification. Certaines fonctions Desktop liées au compte peuvent être indisponibles.", "dash.searchModel": "Modèle auxiliaire de recherche", "dash.searchModelHint": "Modèle utilisé pour web_search sur les modèles routés autres qu’OpenAI. Nécessite une connexion à ChatGPT.", "dash.searchReasoning": "Effort de raisonnement pour la recherche", diff --git a/gui/src/i18n/ja.ts b/gui/src/i18n/ja.ts index cf94831583..55a6fe2495 100644 --- a/gui/src/i18n/ja.ts +++ b/gui/src/i18n/ja.ts @@ -308,6 +308,8 @@ export const ja: Record = { "models.staleBanner": "Codex はこのカタログより古いモデル一覧を表示しています。Codex を再起動すると読み直されます。", "dash.codexAutoStart": "Codex と一緒に opencodex を起動", "dash.codexAutoStartHint": "インストール済み launcher shim に ocx ensure の実行を許可します。この設定だけでは再起動保護はインストールされません。起動安全性で実際の状態を確認してください。", + "dash.codexDesktopAuthless": "ログインせずに Codex を開く", + "dash.codexDesktopAuthlessHint": "既定ではオフです。対象のローカル接続で Desktop の個別ログインを省略します。上流プロバイダーの認証情報は引き続き必要です。変更後は Codex を再起動してください。アカウントに依存する Desktop 機能が利用できない場合があります。", "dash.searchModel": "検索サイドカーモデル", "dash.searchModelHint": "非 OpenAI ルーティングモデルで web_search に使うモデル。ChatGPT ログインが必要です。", "dash.searchReasoning": "検索の推論負荷", diff --git a/gui/src/i18n/ko.ts b/gui/src/i18n/ko.ts index c1959482b7..19285b150e 100644 --- a/gui/src/i18n/ko.ts +++ b/gui/src/i18n/ko.ts @@ -303,6 +303,8 @@ export const ko: Record = { "models.staleBanner": "Codex가 이 카탈로그보다 오래된 모델 목록을 보여주고 있습니다. Codex를 재시작하면 새로 읽습니다.", "dash.codexAutoStart": "Codex 실행 시 opencodex 시작", "dash.codexAutoStartHint": "설치된 launcher shim이 ocx ensure를 실행하도록 허용합니다. 이 설정은 재부팅 보호를 설치하지 않으므로 시작 안전성에서 실제 상태를 확인하세요.", + "dash.codexDesktopAuthless": "로그인 없이 Codex 열기", + "dash.codexDesktopAuthlessHint": "기본값은 꺼짐입니다. 지원되는 로컬 연결에서 별도의 Desktop 로그인을 건너뜁니다. 업스트림 인증 정보는 여전히 필요합니다. 변경 후 Codex를 다시 시작하세요. 계정에 연결된 Desktop 기능을 사용하지 못할 수 있습니다.", "dash.searchModel": "서치 사이드카 모델", "dash.searchModelHint": "비-OpenAI 라우팅 모델의 web_search에 사용되는 모델입니다. ChatGPT 로그인 필요.", "dash.searchReasoning": "서치 추론 강도", diff --git a/gui/src/i18n/ru.ts b/gui/src/i18n/ru.ts index 0109f5ebdc..87704912ac 100644 --- a/gui/src/i18n/ru.ts +++ b/gui/src/i18n/ru.ts @@ -308,6 +308,8 @@ export const ru: Record = { "models.staleBanner": "Codex показывает список моделей старее этого каталога. Перезапустите Codex, чтобы перечитать его.", "dash.codexAutoStart": "Запускать opencodex вместе с Codex", "dash.codexAutoStartHint": "Разрешает установленному launcher shim выполнять ocx ensure. Эта настройка не устанавливает защиту перезапуска; проверьте фактическое состояние в разделе безопасности запуска.", + "dash.codexDesktopAuthless": "Открывать Codex без входа", + "dash.codexDesktopAuthlessHint": "По умолчанию выключено. Пропускает отдельный вход в Desktop для допустимых локальных подключений. Учётные данные провайдера по-прежнему нужны. После изменения перезапустите Codex. Функции Desktop, связанные с аккаунтом, могут быть недоступны.", "dash.searchModel": "Модель сайдкара поиска", "dash.searchModelHint": "Модель, используемая для web_search на маршрутизируемых моделях, отличных от OpenAI. Требуется вход в аккаунт ChatGPT.", "dash.searchReasoning": "Уровень рассуждений для поиска", diff --git a/gui/src/i18n/tr.ts b/gui/src/i18n/tr.ts index fa8b8e9c25..807eeae32b 100644 --- a/gui/src/i18n/tr.ts +++ b/gui/src/i18n/tr.ts @@ -309,6 +309,8 @@ export const tr: Record = { "models.staleBanner": "Codex, bu katalogdan daha eski bir model listesi gösteriyor. Yeniden okumak için Codex'i yeniden başlatın.", "dash.codexAutoStart": "opencodex'i Codex ile başlat", "dash.codexAutoStartHint": "Yüklü bir shim'in ocx ensure çalıştırmasına izin verir. Arka plan servisi veya yeniden başlatma koruması kurmaz; sistem durumu için Başlatma Güvenliği'ne bakın.", + "dash.codexDesktopAuthless": "Codex’i oturum açmadan başlat", + "dash.codexDesktopAuthlessHint": "Varsayılan olarak kapalıdır. Uygun yerel bağlantılarda ayrı Desktop oturum açma adımını atlar. Sağlayıcı kimlik bilgileri yine gereklidir. Değişiklikten sonra Codex’i yeniden başlatın. Hesaba bağlı Desktop özellikleri kullanılamayabilir.", "dash.searchModel": "Arama yan araç modeli", "dash.searchModelHint": "OpenAI dışı yönlendirilen modellerde web_search için kullanılan model. ChatGPT girişi gerektirir.", "dash.searchReasoning": "Arama akıl yürütme çabası", diff --git a/gui/src/i18n/zh-TW.ts b/gui/src/i18n/zh-TW.ts index 3bc246543a..62e1f07110 100644 --- a/gui/src/i18n/zh-TW.ts +++ b/gui/src/i18n/zh-TW.ts @@ -200,6 +200,8 @@ export const zhTW: Record = { "models.staleBanner": "Codex 顯示的模型清單比目前的目錄舊。重新啟動 Codex 即可重新讀取。", "dash.codexAutoStart": "隨 Codex 啟動 opencodex", "dash.codexAutoStartHint": "允許已安裝的 launcher shim 執行 ocx ensure。此設定不會安裝重新啟動保護;請在啟動安全中檢查實際狀態。", + "dash.codexDesktopAuthless": "無需登入即可開啟 Codex", + "dash.codexDesktopAuthlessHint": "預設關閉。為符合條件的本機連線略過獨立的 Desktop 登入。仍需上游供應商憑證。變更後請重新啟動 Codex。依賴帳戶的 Desktop 功能可能無法使用。", "dash.searchModel": "搜尋附屬模型", "dash.searchModelHint": "用於非 OpenAI 路由模型的 web_search 的模型。需要 ChatGPT 登入。", "dash.searchReasoning": "搜尋推理強度", diff --git a/gui/src/i18n/zh.ts b/gui/src/i18n/zh.ts index b10c48688d..9946914426 100644 --- a/gui/src/i18n/zh.ts +++ b/gui/src/i18n/zh.ts @@ -303,6 +303,8 @@ export const zh: Record = { "models.staleBanner": "Codex 显示的模型列表比当前目录旧。重启 Codex 即可重新读取。", "dash.codexAutoStart": "随 Codex 启动 opencodex", "dash.codexAutoStartHint": "允许已安装的 launcher shim 运行 ocx ensure。此设置不会安装重启保护;请在启动安全中检查实际状态。", + "dash.codexDesktopAuthless": "无需登录即可打开 Codex", + "dash.codexDesktopAuthlessHint": "默认关闭。为符合条件的本地连接跳过单独的 Desktop 登录。仍需上游提供商凭据。更改后请重启 Codex。依赖账户的 Desktop 功能可能不可用。", "dash.searchModel": "搜索附属模型", "dash.searchModelHint": "用于非 OpenAI 路由模型的 web_search 的模型。需要 ChatGPT 登录。", "dash.searchReasoning": "搜索推理强度", diff --git a/gui/src/pages/dashboard-overview-sections.tsx b/gui/src/pages/dashboard-overview-sections.tsx index 8da531f97c..6606c4f560 100644 --- a/gui/src/pages/dashboard-overview-sections.tsx +++ b/gui/src/pages/dashboard-overview-sections.tsx @@ -163,7 +163,7 @@ export function DashboardInjectionPanel({ d }: { apiBase: string; d: Dash }) { export function DashboardMaintenancePanel({ d }: { d: Dash }) { const { - t, runSync, syncing, updateTriggerRef, openUpdateDialog, updateLoading, updateOpen, + t, runSync, syncing, settingsSaving, updateTriggerRef, openUpdateDialog, updateLoading, updateOpen, syncResult, syncError, updateJob, reconnecting, clearSyncFeedback, } = d; const syncHoldsWarning = !!syncResult && ( @@ -211,7 +211,7 @@ export function DashboardMaintenancePanel({ d }: { d: Dash }) {
{t("dash.syncModelsHint")}
-
+
+
+
+
{t("dash.codexDesktopAuthless")}
+
{t("dash.codexDesktopAuthlessHint")}
+ {settings?.catalogRefreshPending &&
{t("codexAuth.catalogRefreshPending")}
} +
+ +
+
+
{/* Both sidecar cards wear the DashboardInjectionPanel shell: the PANEL is the flex row, copy left, controls right. */} diff --git a/gui/src/pages/dashboard-shared.ts b/gui/src/pages/dashboard-shared.ts index 0793a7def2..d240510286 100644 --- a/gui/src/pages/dashboard-shared.ts +++ b/gui/src/pages/dashboard-shared.ts @@ -48,6 +48,8 @@ export interface ProviderInfo { name: string; adapter: string; baseUrl: string; export interface ModelInfo { id: string; provider: string; namespaced: string; owned_by?: string; reasoningEfforts?: string[] } export interface SettingsData { codexAutoStart: boolean; + codexDesktopAuthless?: boolean; + catalogRefreshPending?: boolean; /** Whether a login may open a browser on the machine running the proxy. */ oauthOpenBrowser?: boolean; port: number; diff --git a/gui/src/pages/use-dashboard-data.ts b/gui/src/pages/use-dashboard-data.ts index 6f84950ce1..6da776ea18 100644 --- a/gui/src/pages/use-dashboard-data.ts +++ b/gui/src/pages/use-dashboard-data.ts @@ -607,23 +607,24 @@ export function useDashboardData(apiBase: string) { finally { setInjectionSaving(false); } }; - const toggleCodexAutoStart = async () => { - if (!settings || settingsSaving) return; - const next = !settings.codexAutoStart; + const toggleCodexSetting = async (key: "codexAutoStart" | "codexDesktopAuthless") => { + if (!settings || settingsSaving || syncing) return; + const next = !(settings[key] ?? (key === "codexAutoStart")); setSettingsSaving(true); settingsMutationInFlightRef.current = true; - setSettings({ ...settings, codexAutoStart: next }); + setSettings({ ...settings, [key]: next }); try { const res = await fetch(`${apiBase}/api/settings`, { method: "PUT", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ codexAutoStart: next }), + body: JSON.stringify({ [key]: next }), }); - const data = await requireJson<{ codexAutoStart: boolean; startupHealth?: SettingsData["startupHealth"] }>(res, "save failed"); + const data = await requireJson(res, "save failed"); settingsMutationEpochRef.current += 1; - setSettings(prev => prev ? { ...prev, codexAutoStart: data.codexAutoStart, startupHealth: data.startupHealth ?? prev.startupHealth } : prev); + setSettings(prev => prev ? { ...prev, [key]: data[key], catalogRefreshPending: key === "codexDesktopAuthless" ? data.catalogRefreshPending : prev.catalogRefreshPending, startupHealth: data.startupHealth ?? prev.startupHealth } : prev); + if (key === "codexDesktopAuthless") await runSync(); } catch { - setSettings(prev => prev ? { ...prev, codexAutoStart: !next } : prev); + setSettings(prev => prev ? { ...prev, [key]: !next } : prev); setError(true); } finally { settingsMutationInFlightRef.current = false; @@ -631,6 +632,9 @@ export function useDashboardData(apiBase: string) { } }; + const toggleCodexAutoStart = () => toggleCodexSetting("codexAutoStart"); + const toggleCodexDesktopAuthless = () => toggleCodexSetting("codexDesktopAuthless"); + // Clears the sync result/error in this hook. The dashboard toast owns its own dismissal // timer but must publish the dismissal here: syncResult/syncError live above the dashboard // tabs, so a component-local flag alone would let a stale result remount as a fresh toast @@ -649,6 +653,7 @@ export function useDashboardData(apiBase: string) { const res = await fetch(`${apiBase}/api/sync`, { method: "POST" }); const data = await requireJson(res, "sync failed"); setSyncResult(data); + setSettings(prev => prev ? { ...prev, catalogRefreshPending: false } : prev); if (data.projectConfigGrouped) setProjectConfigWarnings(data.projectConfigGrouped); } catch (err) { setSyncError(err instanceof Error ? err.message : String(err)); @@ -789,7 +794,7 @@ export function useDashboardData(apiBase: string) { effortCapHelpTriggerRef, updateTriggerRef, maHelpTriggerRef, shadowCallHelpTriggerRef, effortCapHelpDialogRef, updateDialogRef, maHelpDialogRef, shadowCallHelpDialogRef, filteredGroups, sidecarModels, visionModels, - saveSidecar, saveShadowCall, switchMaMode, toggleCodexAutoStart, runSync, clearSyncFeedback, + saveSidecar, saveShadowCall, switchMaMode, toggleCodexAutoStart, toggleCodexDesktopAuthless, runSync, clearSyncFeedback, fetchUpdateCheck, closeUpdateDialog, openUpdateDialog, changeUpdateChannel, runUpdate, }; } diff --git a/gui/tests/vision-sidecar-dashboard.test.tsx b/gui/tests/vision-sidecar-dashboard.test.tsx index dc762de58f..994a409126 100644 --- a/gui/tests/vision-sidecar-dashboard.test.tsx +++ b/gui/tests/vision-sidecar-dashboard.test.tsx @@ -12,7 +12,7 @@ import { LanguageProvider } from "../src/i18n/provider"; import { DashboardSidecarPanels } from "../src/pages/dashboard-overview-sections"; import type { SidecarData, SidecarPatch } from "../src/pages/dashboard-shared"; import { mergeSidecarSetting } from "../src/pages/dashboard-shared"; -import type { useDashboardData } from "../src/pages/use-dashboard-data"; +import { useDashboardData } from "../src/pages/use-dashboard-data"; const globals = ["document", "window", "navigator", "IS_REACT_ACT_ENVIRONMENT"] as const; let previousGlobals: Record<(typeof globals)[number], PropertyDescriptor | undefined>; @@ -382,4 +382,79 @@ test("model and reasoning saves still omit enabled, limit, and timeout", async ( expect(patches).toHaveLength(2); expect(patches[1]).toEqual({ vision: { reasoning: "high" } }); assertVisionControlFieldsOmitted(patches[1]!); -}); \ No newline at end of file +}); + +test("Desktop login switch defaults off, preserves explicit opt-in, and disables while saving", async () => { + const { d } = harness(); + let clicks = 0; + d.toggleCodexDesktopAuthless = async () => { clicks += 1; }; + d.settings = { codexAutoStart: true, port: 10100, hostname: "127.0.0.1" }; + await mount(d); + const toggle = () => host.querySelector(`button[aria-label="${en["dash.codexDesktopAuthless"]}"]`)!; + expect(toggle().getAttribute("aria-pressed")).toBe("false"); + d.settings.codexDesktopAuthless = true; + await mount(d); + expect(toggle().getAttribute("aria-pressed")).toBe("true"); + await act(async () => { toggle().click(); }); + expect(clicks).toBe(1); + d.settings.codexDesktopAuthless = false; + d.settings.catalogRefreshPending = true; + d.settingsSaving = true; + await mount(d); + expect(toggle().getAttribute("aria-pressed")).toBe("false"); + expect(toggle().disabled).toBe(true); + expect(host.textContent).toContain(en["codexAuth.catalogRefreshPending"]); +}); + + +test.each([undefined, false, true])("Desktop login preference %s persists before full sync; sync failure keeps the saved preference", async (initial) => { + const originalFetch = globalThis.fetch; + const writes: Array<{ path: string; body: unknown }> = []; + let latest: Dash | undefined; + let saved = initial; + const apiBase = `/authless-test-${String(initial)}`; + globalThis.fetch = (async (input: RequestInfo | URL, init?: RequestInit) => { + const path = String(input); + if (init?.method === "PUT") { + const body = JSON.parse(String(init.body)); + writes.push({ path, body }); + if (body.codexDesktopAuthless !== undefined) { + saved = body.codexDesktopAuthless; + return Response.json({ codexDesktopAuthless: saved, catalogRefreshPending: true }); + } + return Response.json({ codexAutoStart: body.codexAutoStart, catalogRefreshPending: false }); + } + if (path.endsWith("/api/sync")) { + writes.push({ path, body: null }); + return Response.json({ error: "sync unavailable" }, { status: 503 }); + } + if (path.endsWith("/api/settings")) { + return Response.json({ codexAutoStart: true, codexDesktopAuthless: saved, port: 10100, hostname: "127.0.0.1" }); + } + return Response.json({}, { status: 503 }); + }) as typeof fetch; + function Harness() { latest = useDashboardData(apiBase); return null; } + try { + const { createRoot } = await import("react-dom/client"); + await act(async () => { + root = createRoot(host); + root.render(); + }); + expect(latest?.settings?.codexDesktopAuthless).toBe(initial); + await act(async () => { await latest!.toggleCodexDesktopAuthless(); }); + expect(writes).toEqual([ + { path: `${apiBase}/api/settings`, body: { codexDesktopAuthless: !initial } }, + { path: `${apiBase}/api/sync`, body: null }, + ]); + expect(latest?.settings?.codexDesktopAuthless).toBe(!initial); + expect(latest?.syncError).toBe("sync unavailable"); + expect(latest?.settings?.catalogRefreshPending).toBe(true); + await act(async () => { await latest!.toggleCodexAutoStart(); }); + expect(latest?.settings?.codexAutoStart).toBe(false); + expect(latest?.settings?.catalogRefreshPending).toBe(true); + } finally { + await act(async () => { root?.unmount(); }); + root = null; + globalThis.fetch = originalFetch; + } +}); diff --git a/tests/codex-integration/codex-inject.test.ts b/tests/codex-integration/codex-inject.test.ts index 84ac5f67b6..b6be3c2f69 100644 --- a/tests/codex-integration/codex-inject.test.ts +++ b/tests/codex-integration/codex-inject.test.ts @@ -31,8 +31,8 @@ describe("Codex config injection", () => { }); describe("authless Codex Desktop opt-in (#1107)", () => { - test("default target on loopback stays Design B and byte-identical", () => { - const target = standaloneCodexRoutingTarget(10100, {}); + test.each([undefined, false])("disabled preference %s on loopback stays Design B and byte-identical", (codexDesktopAuthless) => { + const target = standaloneCodexRoutingTarget(10100, { codexDesktopAuthless }); expect(target.desktopAuthless).toBeUndefined(); expect(buildProfileFile(target, null)).toBe(buildProfileFile(10100, null)); expect(buildProviderTableBlock(target)).toContain("requires_openai_auth = true"); From c1f96f0a5af6bf98e663d287eeffaabcdb0d0028 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 18:25:44 +0900 Subject: [PATCH 2/9] fix(gui): retain pending Desktop preference when sync is skipped [skip ci] Co-authored-by: RobinBially <7304732+RobinBially@users.noreply.github.com> --- gui/src/i18n/de.ts | 4 +-- gui/src/i18n/en.ts | 4 +-- gui/src/i18n/fr.ts | 4 +-- gui/src/i18n/ja.ts | 4 +-- gui/src/i18n/ko.ts | 4 +-- gui/src/i18n/ru.ts | 4 +-- gui/src/i18n/tr.ts | 4 +-- gui/src/i18n/zh-TW.ts | 4 +-- gui/src/i18n/zh.ts | 4 +-- gui/src/pages/dashboard-shared.ts | 1 + gui/src/pages/use-dashboard-data.ts | 4 ++- gui/tests/vision-sidecar-dashboard.test.tsx | 27 +++++++++++++++++++++ 12 files changed, 49 insertions(+), 19 deletions(-) diff --git a/gui/src/i18n/de.ts b/gui/src/i18n/de.ts index 495104bd42..74533a04d3 100644 --- a/gui/src/i18n/de.ts +++ b/gui/src/i18n/de.ts @@ -299,8 +299,6 @@ export const de: Record = { "models.staleBanner": "Codex zeigt eine ältere Modellliste als dieser Katalog. Starte Codex neu, um sie neu zu laden.", "dash.codexAutoStart": "opencodex mit Codex starten", "dash.codexAutoStartHint": "Erlaubt einem installierten Launcher-Shim, ocx ensure auszuführen. Diese Einstellung installiert keinen Neustartschutz; prüfe den effektiven Zustand unter Startsicherheit.", - "dash.codexDesktopAuthless": "Codex ohne Anmeldung öffnen", - "dash.codexDesktopAuthlessHint": "Standardmäßig aus. Überspringt die separate Desktop-Anmeldung bei geeigneten lokalen Verbindungen. Zugangsdaten für den Anbieter bleiben erforderlich. Codex nach einer Änderung neu starten. Kontogebundene Desktop-Funktionen können fehlen.", "dash.searchModel": "Such-Sidecar-Modell", "dash.searchModelHint": "Modell für web_search bei nicht über OpenAI gerouteten Modellen. Erfordert ChatGPT-Login.", "dash.searchReasoning": "Such-Reasoning-Aufwand", @@ -2471,6 +2469,8 @@ export const de: Record = { "dash.visionTimeout": "Timeout", "dash.visionTimeoutInvalid": "Geben Sie eine ganze Zahl von {min} bis {max} Millisekunden ein.", "dash.visionAdvancedPopover": "Erweiterte Vision-Einstellungen", + "dash.codexDesktopAuthless": "Codex ohne Anmeldung öffnen", + "dash.codexDesktopAuthlessHint": "Standardmäßig aus. Überspringt die separate Desktop-Anmeldung bei geeigneten lokalen Verbindungen. Zugangsdaten für den Anbieter bleiben erforderlich. Codex nach einer Änderung neu starten. Kontogebundene Desktop-Funktionen können fehlen.", "models.newPolicyGlobal": "Neue Modelle zunächst deaktivieren", "models.newPolicyProvider": "Richtlinie für neue Modelle", "models.newPolicy_inherit": "Übernehmen", "models.newPolicy_off": "Aus", "models.newPolicy_on": "An", "models.newBadge": "NEU", "models.newCount": "{count} neu, aus", "models.aliases": "Aliase", diff --git a/gui/src/i18n/en.ts b/gui/src/i18n/en.ts index 22a3807858..2197dcb735 100644 --- a/gui/src/i18n/en.ts +++ b/gui/src/i18n/en.ts @@ -311,8 +311,6 @@ export const en = { "models.staleBanner": "Codex is showing an older model list than this catalog. Restart Codex to reload it.", "dash.codexAutoStart": "Start opencodex with Codex", "dash.codexAutoStartHint": "Allows an installed launcher shim to run ocx ensure. This setting does not install restart protection; check Startup safety for the effective state.", - "dash.codexDesktopAuthless": "Open Codex without signing in", - "dash.codexDesktopAuthlessHint": "Off by default. Skip the separate Desktop sign-in for eligible local connections. Upstream credentials are still required. Restart Codex after changing this setting. Account-gated Desktop features may be unavailable.", "dash.searchModel": "Search sidecar model", "dash.searchModelHint": "Model used for web_search on non-OpenAI routed models. Requires ChatGPT login.", "dash.searchReasoning": "Search reasoning effort", @@ -577,6 +575,8 @@ export const en = { "models.keepNativeOnV1Hint": "ChatGPT encrypts v2 child tasks only when a ChatGPT-native parent stays on v2, so Grok and Claude cannot read them. Turn this on to keep Sol/Terra on v1 and avoid that encryption. Routed parents keep v2.", "models.v2Help": "Controls the multi-agent surface for all models.\n\nv1: Classic single-thread agent. Every model uses the v1 collab surface.\nbase: Upstream defaults — sol/terra use v2, luna uses v1, others follow the codex feature flag.\nv2: Multi-thread agent with spawn_agent. Every model uses the v2 collab surface.\n\nOn v2, Keep ChatGPT on v1 leaves Sol/Terra on the v1 surface so they can still spawn Grok or Claude. ChatGPT encrypts v2 child tasks; routed models cannot read them. Routed parents stay on v2.\n\nChanges apply to new sessions.", "dash.multiAgent": "Sub-agent", + "dash.codexDesktopAuthless": "Open Codex without signing in", + "dash.codexDesktopAuthlessHint": "Off by default. Skip the separate Desktop sign-in for eligible local connections. Upstream credentials are still required. Restart Codex after changing this setting. Account-gated Desktop features may be unavailable.", "models.v2Conflict": "[agents] max_threads is set — codex will refuse to start; remove it from config.toml", "models.v2Applied": "Sub-agent mode updated — applies to new sessions (restart the Codex app to refresh the picker)", "models.v2ThreadsLabel": "Max threads", diff --git a/gui/src/i18n/fr.ts b/gui/src/i18n/fr.ts index 9f0f265173..cca4b70347 100644 --- a/gui/src/i18n/fr.ts +++ b/gui/src/i18n/fr.ts @@ -301,8 +301,6 @@ export const fr: Record = { "models.staleBanner": "Codex affiche une liste de modèles plus ancienne que ce catalogue. Redémarrez Codex pour la recharger.", "dash.codexAutoStart": "Démarrer opencodex avec Codex", "dash.codexAutoStartHint": "Permet à un mécanisme de lancement installé d’exécuter ocx ensure. Ce réglage n’installe pas de protection au redémarrage ; consultez Sécurité du démarrage pour connaître l’état effectif.", - "dash.codexDesktopAuthless": "Ouvrir Codex sans se connecter", - "dash.codexDesktopAuthlessHint": "Désactivé par défaut. Ignore la connexion Desktop séparée pour les connexions locales admissibles. Les identifiants du fournisseur restent nécessaires. Redémarrez Codex après toute modification. Certaines fonctions Desktop liées au compte peuvent être indisponibles.", "dash.searchModel": "Modèle auxiliaire de recherche", "dash.searchModelHint": "Modèle utilisé pour web_search sur les modèles routés autres qu’OpenAI. Nécessite une connexion à ChatGPT.", "dash.searchReasoning": "Effort de raisonnement pour la recherche", @@ -562,6 +560,8 @@ export const fr: Record = { "models.keepNativeOnV1Hint": "ChatGPT chiffre les tâches enfants v2 uniquement lorsqu’un parent natif ChatGPT reste sur v2, de sorte que Grok et Claude ne peuvent pas les lire. Activez cette option pour garder Sol/Terra sur v1 et éviter ce chiffrement. Les parents routés restent sur v2.", "models.v2Help": "Contrôle l’interface multi-agent pour tous les modèles.\n\nv1 : agent classique à fil unique. Tous les modèles utilisent l’interface collab v1.\nbase : valeurs par défaut en amont — sol/terra utilisent v2, luna utilise v1 et les autres suivent l’indicateur de fonctionnalité codex.\nv2 : agent multifil avec spawn_agent. Tous les modèles utilisent l’interface collab v2.\n\nEn v2, « Garder ChatGPT sur v1 » laisse Sol/Terra sur l’interface v1 afin qu’ils puissent encore lancer Grok ou Claude. ChatGPT chiffre les tâches enfants v2 ; les modèles routés ne peuvent pas les lire. Les parents routés restent sur v2.\n\nLes modifications s’appliquent aux nouvelles sessions.", "dash.multiAgent": "Sous-agent", + "dash.codexDesktopAuthless": "Ouvrir Codex sans se connecter", + "dash.codexDesktopAuthlessHint": "Désactivé par défaut. Ignore la connexion Desktop séparée pour les connexions locales admissibles. Les identifiants du fournisseur restent nécessaires. Redémarrez Codex après toute modification. Certaines fonctions Desktop liées au compte peuvent être indisponibles.", "models.v2Conflict": "[agents] max_threads est défini — codex refusera de démarrer ; supprimez-le de config.toml", "models.v2Applied": "Mode sous-agent mis à jour — s’applique aux nouvelles sessions (redémarrez l’application Codex pour actualiser le sélecteur)", "models.v2ThreadsLabel": "Nombre maximal de fils", diff --git a/gui/src/i18n/ja.ts b/gui/src/i18n/ja.ts index 55a6fe2495..97aa85a6fb 100644 --- a/gui/src/i18n/ja.ts +++ b/gui/src/i18n/ja.ts @@ -308,8 +308,6 @@ export const ja: Record = { "models.staleBanner": "Codex はこのカタログより古いモデル一覧を表示しています。Codex を再起動すると読み直されます。", "dash.codexAutoStart": "Codex と一緒に opencodex を起動", "dash.codexAutoStartHint": "インストール済み launcher shim に ocx ensure の実行を許可します。この設定だけでは再起動保護はインストールされません。起動安全性で実際の状態を確認してください。", - "dash.codexDesktopAuthless": "ログインせずに Codex を開く", - "dash.codexDesktopAuthlessHint": "既定ではオフです。対象のローカル接続で Desktop の個別ログインを省略します。上流プロバイダーの認証情報は引き続き必要です。変更後は Codex を再起動してください。アカウントに依存する Desktop 機能が利用できない場合があります。", "dash.searchModel": "検索サイドカーモデル", "dash.searchModelHint": "非 OpenAI ルーティングモデルで web_search に使うモデル。ChatGPT ログインが必要です。", "dash.searchReasoning": "検索の推論負荷", @@ -2492,6 +2490,8 @@ export const ja: Record = { "dash.visionTimeout": "タイムアウト", "dash.visionTimeoutInvalid": "{min} から {max} ミリ秒の整数を入力してください。", "dash.visionAdvancedPopover": "詳細なビジョン設定", + "dash.codexDesktopAuthless": "ログインせずに Codex を開く", + "dash.codexDesktopAuthlessHint": "既定ではオフです。対象のローカル接続で Desktop の個別ログインを省略します。上流プロバイダーの認証情報は引き続き必要です。変更後は Codex を再起動してください。アカウントに依存する Desktop 機能が利用できない場合があります。", "models.newPolicyGlobal": "新しいモデルを無効で追加", "models.newPolicyProvider": "新しいモデルのポリシー", "models.newPolicy_inherit": "継承", "models.newPolicy_off": "オフ", "models.newPolicy_on": "オン", "models.newBadge": "新着", "models.newCount": "新着 {count} 件、オフ", "models.aliases": "エイリアス", diff --git a/gui/src/i18n/ko.ts b/gui/src/i18n/ko.ts index 19285b150e..4e66544528 100644 --- a/gui/src/i18n/ko.ts +++ b/gui/src/i18n/ko.ts @@ -303,8 +303,6 @@ export const ko: Record = { "models.staleBanner": "Codex가 이 카탈로그보다 오래된 모델 목록을 보여주고 있습니다. Codex를 재시작하면 새로 읽습니다.", "dash.codexAutoStart": "Codex 실행 시 opencodex 시작", "dash.codexAutoStartHint": "설치된 launcher shim이 ocx ensure를 실행하도록 허용합니다. 이 설정은 재부팅 보호를 설치하지 않으므로 시작 안전성에서 실제 상태를 확인하세요.", - "dash.codexDesktopAuthless": "로그인 없이 Codex 열기", - "dash.codexDesktopAuthlessHint": "기본값은 꺼짐입니다. 지원되는 로컬 연결에서 별도의 Desktop 로그인을 건너뜁니다. 업스트림 인증 정보는 여전히 필요합니다. 변경 후 Codex를 다시 시작하세요. 계정에 연결된 Desktop 기능을 사용하지 못할 수 있습니다.", "dash.searchModel": "서치 사이드카 모델", "dash.searchModelHint": "비-OpenAI 라우팅 모델의 web_search에 사용되는 모델입니다. ChatGPT 로그인 필요.", "dash.searchReasoning": "서치 추론 강도", @@ -2493,6 +2491,8 @@ export const ko: Record = { "dash.visionTimeout": "제한 시간", "dash.visionTimeoutInvalid": "{min}에서 {max} 밀리초 사이의 정수를 입력하세요.", "dash.visionAdvancedPopover": "고급 비전 설정", + "dash.codexDesktopAuthless": "로그인 없이 Codex 열기", + "dash.codexDesktopAuthlessHint": "기본값은 꺼짐입니다. 지원되는 로컬 연결에서 별도의 Desktop 로그인을 건너뜁니다. 업스트림 인증 정보는 여전히 필요합니다. 변경 후 Codex를 다시 시작하세요. 계정에 연결된 Desktop 기능을 사용하지 못할 수 있습니다.", "models.newPolicyGlobal": "새 모델을 비활성화 상태로 추가", "models.newPolicyProvider": "새 모델 정책", "models.newPolicy_inherit": "상속", "models.newPolicy_off": "끔", "models.newPolicy_on": "켬", "models.newBadge": "신규", "models.newCount": "신규 {count}개, 꺼짐", "models.aliases": "별칭", diff --git a/gui/src/i18n/ru.ts b/gui/src/i18n/ru.ts index 87704912ac..e7f199a06a 100644 --- a/gui/src/i18n/ru.ts +++ b/gui/src/i18n/ru.ts @@ -308,8 +308,6 @@ export const ru: Record = { "models.staleBanner": "Codex показывает список моделей старее этого каталога. Перезапустите Codex, чтобы перечитать его.", "dash.codexAutoStart": "Запускать opencodex вместе с Codex", "dash.codexAutoStartHint": "Разрешает установленному launcher shim выполнять ocx ensure. Эта настройка не устанавливает защиту перезапуска; проверьте фактическое состояние в разделе безопасности запуска.", - "dash.codexDesktopAuthless": "Открывать Codex без входа", - "dash.codexDesktopAuthlessHint": "По умолчанию выключено. Пропускает отдельный вход в Desktop для допустимых локальных подключений. Учётные данные провайдера по-прежнему нужны. После изменения перезапустите Codex. Функции Desktop, связанные с аккаунтом, могут быть недоступны.", "dash.searchModel": "Модель сайдкара поиска", "dash.searchModelHint": "Модель, используемая для web_search на маршрутизируемых моделях, отличных от OpenAI. Требуется вход в аккаунт ChatGPT.", "dash.searchReasoning": "Уровень рассуждений для поиска", @@ -2494,6 +2492,8 @@ export const ru: Record = { "dash.visionTimeout": "Таймаут", "dash.visionTimeoutInvalid": "Введите целое число от {min} до {max} миллисекунд.", "dash.visionAdvancedPopover": "Дополнительные настройки изображений", + "dash.codexDesktopAuthless": "Открывать Codex без входа", + "dash.codexDesktopAuthlessHint": "По умолчанию выключено. Пропускает отдельный вход в Desktop для допустимых локальных подключений. Учётные данные провайдера по-прежнему нужны. После изменения перезапустите Codex. Функции Desktop, связанные с аккаунтом, могут быть недоступны.", "models.newPolicyGlobal": "Добавлять новые модели выключенными", "models.newPolicyProvider": "Политика новых моделей", "models.newPolicy_inherit": "Наследовать", "models.newPolicy_off": "Выкл.", "models.newPolicy_on": "Вкл.", "models.newBadge": "НОВАЯ", "models.newCount": "Новых: {count}, выкл.", "models.aliases": "Псевдонимы", diff --git a/gui/src/i18n/tr.ts b/gui/src/i18n/tr.ts index 807eeae32b..8c8f9ff802 100644 --- a/gui/src/i18n/tr.ts +++ b/gui/src/i18n/tr.ts @@ -309,8 +309,6 @@ export const tr: Record = { "models.staleBanner": "Codex, bu katalogdan daha eski bir model listesi gösteriyor. Yeniden okumak için Codex'i yeniden başlatın.", "dash.codexAutoStart": "opencodex'i Codex ile başlat", "dash.codexAutoStartHint": "Yüklü bir shim'in ocx ensure çalıştırmasına izin verir. Arka plan servisi veya yeniden başlatma koruması kurmaz; sistem durumu için Başlatma Güvenliği'ne bakın.", - "dash.codexDesktopAuthless": "Codex’i oturum açmadan başlat", - "dash.codexDesktopAuthlessHint": "Varsayılan olarak kapalıdır. Uygun yerel bağlantılarda ayrı Desktop oturum açma adımını atlar. Sağlayıcı kimlik bilgileri yine gereklidir. Değişiklikten sonra Codex’i yeniden başlatın. Hesaba bağlı Desktop özellikleri kullanılamayabilir.", "dash.searchModel": "Arama yan araç modeli", "dash.searchModelHint": "OpenAI dışı yönlendirilen modellerde web_search için kullanılan model. ChatGPT girişi gerektirir.", "dash.searchReasoning": "Arama akıl yürütme çabası", @@ -2494,6 +2492,8 @@ export const tr: Record = { "dash.visionTimeout": "Zaman aşımı", "dash.visionTimeoutInvalid": "{min} ile {max} milisaniye arasında bir tam sayı girin.", "dash.visionAdvancedPopover": "Gelişmiş görsel ayarları", + "dash.codexDesktopAuthless": "Codex’i oturum açmadan başlat", + "dash.codexDesktopAuthlessHint": "Varsayılan olarak kapalıdır. Uygun yerel bağlantılarda ayrı Desktop oturum açma adımını atlar. Sağlayıcı kimlik bilgileri yine gereklidir. Değişiklikten sonra Codex’i yeniden başlatın. Hesaba bağlı Desktop özellikleri kullanılamayabilir.", "models.newPolicyGlobal": "Yeni modeller devre dışı başlasın", "models.newPolicyProvider": "Yeni model ilkesi", "models.newPolicy_inherit": "Devral", "models.newPolicy_off": "Kapalı", "models.newPolicy_on": "Açık", "models.newBadge": "YENİ", "models.newCount": "{count} yeni, kapalı", "models.aliases": "Takma adlar", diff --git a/gui/src/i18n/zh-TW.ts b/gui/src/i18n/zh-TW.ts index 62e1f07110..eeec289911 100644 --- a/gui/src/i18n/zh-TW.ts +++ b/gui/src/i18n/zh-TW.ts @@ -200,8 +200,6 @@ export const zhTW: Record = { "models.staleBanner": "Codex 顯示的模型清單比目前的目錄舊。重新啟動 Codex 即可重新讀取。", "dash.codexAutoStart": "隨 Codex 啟動 opencodex", "dash.codexAutoStartHint": "允許已安裝的 launcher shim 執行 ocx ensure。此設定不會安裝重新啟動保護;請在啟動安全中檢查實際狀態。", - "dash.codexDesktopAuthless": "無需登入即可開啟 Codex", - "dash.codexDesktopAuthlessHint": "預設關閉。為符合條件的本機連線略過獨立的 Desktop 登入。仍需上游供應商憑證。變更後請重新啟動 Codex。依賴帳戶的 Desktop 功能可能無法使用。", "dash.searchModel": "搜尋附屬模型", "dash.searchModelHint": "用於非 OpenAI 路由模型的 web_search 的模型。需要 ChatGPT 登入。", "dash.searchReasoning": "搜尋推理強度", @@ -2456,6 +2454,8 @@ export const zhTW: Record = { "dash.visionTimeout": "逾時", "dash.visionTimeoutInvalid": "請輸入 {min} 到 {max} 毫秒之間的整數。", "dash.visionAdvancedPopover": "進階視覺設定", + "dash.codexDesktopAuthless": "無需登入即可開啟 Codex", + "dash.codexDesktopAuthlessHint": "預設關閉。為符合條件的本機連線略過獨立的 Desktop 登入。仍需上游供應商憑證。變更後請重新啟動 Codex。依賴帳戶的 Desktop 功能可能無法使用。", "models.newPolicyGlobal": "新模型預設停用", "models.newPolicyProvider": "新模型策略", "models.newPolicy_inherit": "繼承", "models.newPolicy_off": "關閉", "models.newPolicy_on": "開啟", "models.newBadge": "新增", "models.newCount": "{count} 個新增,已關閉", "models.aliases": "別名", diff --git a/gui/src/i18n/zh.ts b/gui/src/i18n/zh.ts index 9946914426..a62e9b2d6b 100644 --- a/gui/src/i18n/zh.ts +++ b/gui/src/i18n/zh.ts @@ -303,8 +303,6 @@ export const zh: Record = { "models.staleBanner": "Codex 显示的模型列表比当前目录旧。重启 Codex 即可重新读取。", "dash.codexAutoStart": "随 Codex 启动 opencodex", "dash.codexAutoStartHint": "允许已安装的 launcher shim 运行 ocx ensure。此设置不会安装重启保护;请在启动安全中检查实际状态。", - "dash.codexDesktopAuthless": "无需登录即可打开 Codex", - "dash.codexDesktopAuthlessHint": "默认关闭。为符合条件的本地连接跳过单独的 Desktop 登录。仍需上游提供商凭据。更改后请重启 Codex。依赖账户的 Desktop 功能可能不可用。", "dash.searchModel": "搜索附属模型", "dash.searchModelHint": "用于非 OpenAI 路由模型的 web_search 的模型。需要 ChatGPT 登录。", "dash.searchReasoning": "搜索推理强度", @@ -2492,6 +2490,8 @@ export const zh: Record = { "dash.visionTimeout": "超时", "dash.visionTimeoutInvalid": "请输入 {min} 到 {max} 毫秒之间的整数。", "dash.visionAdvancedPopover": "高级视觉设置", + "dash.codexDesktopAuthless": "无需登录即可打开 Codex", + "dash.codexDesktopAuthlessHint": "默认关闭。为符合条件的本地连接跳过单独的 Desktop 登录。仍需上游提供商凭据。更改后请重启 Codex。依赖账户的 Desktop 功能可能不可用。", "models.newPolicyGlobal": "新模型默认停用", "models.newPolicyProvider": "新模型策略", "models.newPolicy_inherit": "继承", "models.newPolicy_off": "关闭", "models.newPolicy_on": "开启", "models.newBadge": "新增", "models.newCount": "{count} 个新增,已关闭", "models.aliases": "别名", diff --git a/gui/src/pages/dashboard-shared.ts b/gui/src/pages/dashboard-shared.ts index d240510286..b6914586b6 100644 --- a/gui/src/pages/dashboard-shared.ts +++ b/gui/src/pages/dashboard-shared.ts @@ -128,6 +128,7 @@ export type Installer = "npm" | "bun" | "source"; export type UpdateJobStatus = "running" | "restarting" | "succeeded" | "failed"; export interface SyncResult { ok: boolean; + status?: "applied" | "skipped" | "catalog-only" | "refused"; added: number; catalogPath: string | null; catalogExists: boolean; diff --git a/gui/src/pages/use-dashboard-data.ts b/gui/src/pages/use-dashboard-data.ts index 6da776ea18..e87e6494bd 100644 --- a/gui/src/pages/use-dashboard-data.ts +++ b/gui/src/pages/use-dashboard-data.ts @@ -653,7 +653,9 @@ export function useDashboardData(apiBase: string) { const res = await fetch(`${apiBase}/api/sync`, { method: "POST" }); const data = await requireJson(res, "sync failed"); setSyncResult(data); - setSettings(prev => prev ? { ...prev, catalogRefreshPending: false } : prev); + if (data.ok && data.status === "applied") { + setSettings(prev => prev ? { ...prev, catalogRefreshPending: false } : prev); + } if (data.projectConfigGrouped) setProjectConfigWarnings(data.projectConfigGrouped); } catch (err) { setSyncError(err instanceof Error ? err.message : String(err)); diff --git a/gui/tests/vision-sidecar-dashboard.test.tsx b/gui/tests/vision-sidecar-dashboard.test.tsx index 994a409126..386196cc77 100644 --- a/gui/tests/vision-sidecar-dashboard.test.tsx +++ b/gui/tests/vision-sidecar-dashboard.test.tsx @@ -458,3 +458,30 @@ test.each([undefined, false, true])("Desktop login preference %s persists before globalThis.fetch = originalFetch; } }); + + +test.each(["skipped", "catalog-only", "applied"])("Desktop preference pending state follows %s sync application evidence", async (syncStatus) => { + const originalFetch = globalThis.fetch; + let latest: Dash | undefined; + const apiBase = `/authless-sync-${syncStatus}`; + globalThis.fetch = (async (input: RequestInfo | URL, init?: RequestInit) => { + const path = String(input); + if (init?.method === "PUT") return Response.json({ codexDesktopAuthless: true, catalogRefreshPending: true }); + if (path.endsWith("/api/sync")) return Response.json({ ok: true, status: syncStatus, message: syncStatus }); + if (path.endsWith("/api/settings")) return Response.json({ codexAutoStart: true, codexDesktopAuthless: false, port: 10100, hostname: "127.0.0.1" }); + return Response.json({}, { status: 503 }); + }) as typeof fetch; + function Harness() { latest = useDashboardData(apiBase); return null; } + try { + const { createRoot } = await import("react-dom/client"); + await act(async () => { root = createRoot(host); root.render(); }); + await act(async () => { await latest!.toggleCodexDesktopAuthless(); }); + expect(latest?.settings?.codexDesktopAuthless).toBe(true); + expect(latest?.settings?.catalogRefreshPending).toBe(syncStatus !== "applied"); + expect(latest?.syncResult?.status).toBe(syncStatus); + } finally { + await act(async () => { root?.unmount(); }); + root = null; + globalThis.fetch = originalFetch; + } +}); From 734d41c528039a29b4002d455405afacfecf922c Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 18:31:54 +0900 Subject: [PATCH 3/9] fix(gui): retain unapplied Desktop status across settings polls [skip ci] Co-authored-by: RobinBially <7304732+RobinBially@users.noreply.github.com> --- gui/src/pages/use-dashboard-data.ts | 7 ++++++- gui/tests/vision-sidecar-dashboard.test.tsx | 9 +++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/gui/src/pages/use-dashboard-data.ts b/gui/src/pages/use-dashboard-data.ts index e87e6494bd..8634e7caa8 100644 --- a/gui/src/pages/use-dashboard-data.ts +++ b/gui/src/pages/use-dashboard-data.ts @@ -361,7 +361,12 @@ export function useDashboardData(apiBase: string) { useEffect(() => { const data = settingsPoll.data; if (!data) return; - if (data.settings !== undefined) setSettings(data.settings); + if (data.settings !== undefined) { + const next = data.settings; + // GET settings does not report application receipts. Keep a saved preference's + // pending indication until an affirmative sync result clears it. + setSettings(prev => ({ ...next, catalogRefreshPending: prev?.catalogRefreshPending === true || next.catalogRefreshPending })); + } // Latest-wins: only seed from settings when no newer dedicated probe has committed // while this settings poll was in flight. Always merge against the live ref. if ( diff --git a/gui/tests/vision-sidecar-dashboard.test.tsx b/gui/tests/vision-sidecar-dashboard.test.tsx index 386196cc77..738ed866e6 100644 --- a/gui/tests/vision-sidecar-dashboard.test.tsx +++ b/gui/tests/vision-sidecar-dashboard.test.tsx @@ -13,6 +13,7 @@ import { DashboardSidecarPanels } from "../src/pages/dashboard-overview-sections import type { SidecarData, SidecarPatch } from "../src/pages/dashboard-shared"; import { mergeSidecarSetting } from "../src/pages/dashboard-shared"; import { useDashboardData } from "../src/pages/use-dashboard-data"; +import { setClientResourceData } from "../src/client-resource"; const globals = ["document", "window", "navigator", "IS_REACT_ACT_ENVIRONMENT"] as const; let previousGlobals: Record<(typeof globals)[number], PropertyDescriptor | undefined>; @@ -479,6 +480,14 @@ test.each(["skipped", "catalog-only", "applied"])("Desktop preference pending st expect(latest?.settings?.codexDesktopAuthless).toBe(true); expect(latest?.settings?.catalogRefreshPending).toBe(syncStatus !== "applied"); expect(latest?.syncResult?.status).toBe(syncStatus); + // A fresh settings poll has no application receipt and cannot erase pending. + await act(async () => { + setClientResourceData(`dashboard-settings:${apiBase}`, { + settings: { codexAutoStart: true, codexDesktopAuthless: true, port: 10100, hostname: "127.0.0.1" }, + }); + }); + expect(latest?.settings?.codexDesktopAuthless).toBe(true); + expect(latest?.settings?.catalogRefreshPending === true).toBe(syncStatus !== "applied"); } finally { await act(async () => { root?.unmount(); }); root = null; From abbdb227f385443228656c8440282187cb5dec75 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 19:07:56 +0900 Subject: [PATCH 4/9] docs: translate code-mode host rules; docs handoff from lane E [skip ci] --- devlog/_plan/260907_lane_c/040_desktop.md | 4 ++++ docs-site/src/content/docs/fr/guides/codex-integration.md | 8 ++++++++ docs-site/src/content/docs/ja/guides/codex-integration.md | 8 ++++++++ docs-site/src/content/docs/ko/guides/codex-integration.md | 7 +++++++ docs-site/src/content/docs/ru/guides/codex-integration.md | 8 ++++++++ docs-site/src/content/docs/tr/guides/codex-integration.md | 8 ++++++++ .../src/content/docs/zh-cn/guides/codex-integration.md | 6 ++++++ .../src/content/docs/zh-tw/guides/codex-integration.md | 6 ++++++ 8 files changed, 55 insertions(+) diff --git a/devlog/_plan/260907_lane_c/040_desktop.md b/devlog/_plan/260907_lane_c/040_desktop.md index ad7fb60177..4eb4ebffd5 100644 --- a/devlog/_plan/260907_lane_c/040_desktop.md +++ b/devlog/_plan/260907_lane_c/040_desktop.md @@ -402,3 +402,7 @@ index 84ac5f67b..b6be3c2f6 100644 ``` Audit amendment: clear catalogRefreshPending only if sync status is affirmative success, not HTTP 200 skipped. Add skipped/no-write regression. + +## Lane E documentation handoff + +After run 34106956362 reported a GUI lint failure, include the separately prepared code-mode host-rule translations in the seven fr/ja/ko/ru/tr/zh-cn/zh-tw Codex integration guides. The patch adds 51 documentation lines matching the existing English paragraph; it does not modify runtime code or provider guides. Apply on the Desktop layer, record `docs handoff from lane E` and `[skip ci]` in its own commit, then cascade the fallback layer and dispatch the top CI again. Local documentation install/build remains NOT RUN. 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 02ffa8a211..a351adeae5 100644 --- a/docs-site/src/content/docs/fr/guides/codex-integration.md +++ b/docs-site/src/content/docs/fr/guides/codex-integration.md @@ -233,6 +233,14 @@ opencodex encode cette déclaration et son historique sous forme d'outil de fonc cycle de vie diffusé de l'appel de fonction en `custom_tool_call` avant que Codex ne le reçoive. Le routage natif par transfert OpenAI et l'outil personnalisé `apply_patch`, qui est pris en charge, restent inchangés. +Avant le premier appel, les tours routés en mode code reçoivent aussi les règles de l'hôte pour les +outils auxiliaires imbriqués : `tools.apply_patch` prend une seule chaîne qui commence et se termine +par les lignes de marqueur de patch seules, sans habillage ; l'isolate ne dispose pas de `import`, +et les commandes longues sont interrogées via `write_stdin`. Lorsqu'un résultat exec en mode code +sur le chemin natif Responses routé, Kiro ou Cursor contient encore l'un des messages d'échec de +l'hôte, opencodex ajoute une indication d'une ligne qui nomme la règle. Cette modification ne +réécrit ni le code du modèle ni le texte de son patch. + Le fournisseur sélectionné doit prendre en charge les appels de fonctions ou d'outils. Un fournisseur purement textuel dépourvu de cette prise en charge ne peut pas utiliser `exec`, Browser ni Computer Use. Les lignes OpenAI natives conservent leur mode d'outil en amont. 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 d1d977b35c..46c33320f2 100644 --- a/docs-site/src/content/docs/ja/guides/codex-integration.md +++ b/docs-site/src/content/docs/ja/guides/codex-integration.md @@ -147,6 +147,14 @@ Codex の `exec` custom-tool grammar を受け付けない key-auth Responses pr `custom_tool_call` へ復元します。ネイティブ OpenAI の forward routing と、対応済みの `apply_patch` custom tool は 変更されません。 +ルーティングされた code-mode のターンには、最初の呼び出し前に、ネストされたヘルパーに関する +ホストの規則も伝えられます。`tools.apply_patch` は、装飾を付けないパッチマーカー行で始まり、 +同様のマーカー行で終わる単一の文字列を受け取ります。isolate では `import` を使用できず、 +長時間実行されるコマンドは `write_stdin` でポーリングします。ネイティブのルーティング済み Responses、 +Kiro、または Cursor の経路で、code-mode の exec 結果にホストの失敗メッセージがまだ含まれている場合、 +opencodex は該当する規則を示す 1 行のヒントを追加します。この変更でモデルのコードやパッチのテキストを +書き換えることはありません。 + 選択した provider は function/tool calling をサポートしている必要があります。tool call に対応しない text-only provider では `exec`、Browser、Computer Use は使用できません。ネイティブ OpenAI の項目は上流の tool mode を そのまま維持します。 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 44551de837..1f324adaf2 100644 --- a/docs-site/src/content/docs/ko/guides/codex-integration.md +++ b/docs-site/src/content/docs/ko/guides/codex-integration.md @@ -149,6 +149,13 @@ history를 업스트림 function tool로 인코딩한 다음 스트리밍된 fun `custom_tool_call`로 복원합니다. 네이티브 OpenAI forward routing과 지원되는 `apply_patch` custom tool은 변경되지 않습니다. +라우팅된 code-mode 턴에는 첫 호출 전에 중첩 helper에 대한 호스트 규칙도 전달됩니다. +`tools.apply_patch`는 별도 장식 없이 패치 마커만 있는 줄로 시작하고 끝나는 하나의 문자열을 받습니다. +isolate에서는 `import`를 사용할 수 없으며, 오래 실행되는 명령은 `write_stdin`으로 폴링합니다. +네이티브 라우팅 Responses, Kiro 또는 Cursor 경로의 code-mode exec 결과에 호스트의 실패 메시지 중 +하나가 여전히 포함되어 있으면, opencodex는 해당 규칙을 명시하는 한 줄짜리 힌트를 덧붙입니다. +이 변경은 모델의 코드나 패치 텍스트를 다시 작성하지 않습니다. + 선택한 provider는 function/tool calling을 지원해야 합니다. tool call을 지원하지 않는 text-only provider에서는 `exec`, Browser 또는 Computer Use를 사용할 수 없습니다. 네이티브 OpenAI 항목은 업스트림 tool mode를 그대로 유지합니다. 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 9707a3ea44..23581e56f6 100644 --- a/docs-site/src/content/docs/ru/guides/codex-integration.md +++ b/docs-site/src/content/docs/ru/guides/codex-integration.md @@ -224,6 +224,14 @@ opencodex кодирует объявление и историю как functio потоковый lifecycle function call в `custom_tool_call` до передачи в Codex. Нативная forward- маршрутизация OpenAI и поддерживаемый custom tool `apply_patch` остаются без изменений. +Перед первым вызовом маршрутизируемые ходы в code-mode также получают правила хоста для вложенных +вспомогательных инструментов: `tools.apply_patch` принимает одну строку, которая начинается и +заканчивается отдельными строками маркеров патча без дополнительного оформления; в isolate нет +`import`, а длительные команды опрашиваются через `write_stdin`. Если результат exec в code-mode +на нативном маршрутизируемом пути Responses, Kiro или Cursor всё ещё содержит одно из сообщений +хоста об ошибке, opencodex добавляет однострочную подсказку с указанием правила. Это изменение +не переписывает код модели или текст её патча. + Выбранный provider должен поддерживать function/tool calling. Text-only provider без tool calls не может использовать `exec`, Browser или Computer Use. Нативные записи OpenAI сохраняют свой upstream tool mode без изменений. 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 02fae0f468..d13af52274 100644 --- a/docs-site/src/content/docs/tr/guides/codex-integration.md +++ b/docs-site/src/content/docs/tr/guides/codex-integration.md @@ -262,6 +262,14 @@ fonksiyon aracı olarak kodlar, ardından akışlı fonksiyon çağrısı yaşam Codex görmeden önce `custom_tool_call`'a geri yükler. Yerel OpenAI iletme yönlendirmesi ve desteklenen `apply_patch` özel aracı değişmeden kalır. +Yönlendirilen code-mode turlarına, ilk çağrıdan önce iç içe geçmiş yardımcılar için geçerli olan +ana makine kuralları da bildirilir: `tools.apply_patch`, yalnızca yama işaretçilerinden oluşan +satırlarla başlayan ve biten tek bir dize alır; isolate içinde `import` yoktur ve uzun süren +komutlar `write_stdin` üzerinden yoklanır. Yerel yönlendirilmiş Responses, Kiro veya Cursor yolundaki +bir code-mode exec sonucu hâlâ ana makinenin hata mesajlarından birini içeriyorsa opencodex, +ilgili kuralı belirten tek satırlık bir ipucu ekler. Bu değişiklik modelin kodunu veya yama metnini +yeniden yazmaz. + Seçilen sağlayıcı fonksiyon/araç çağrısını desteklemelidir. Araç çağrısı desteği olmayan salt metin bir sağlayıcı `exec`, Tarayıcı veya Bilgisayar Kullanımını kullanamaz. Yerel OpenAI satırları yukarı akış araç modunu değiştirmeden tutar. 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 552c0c3f53..0c3df0c0e2 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 @@ -196,6 +196,12 @@ Codex 显示的模型来自一个磁盘上的 catalog(默认是 `$CODEX_HOME/o 历史记录编码成上游 function tool,再在 Codex 收到结果前,把流式 function-call lifecycle 还原成 `custom_tool_call`。原生 OpenAI forward routing 和已支持的 `apply_patch` custom tool 保持不变。 +路由的 code-mode 轮次还会在首次调用前收到宿主对嵌套辅助工具的规则:`tools.apply_patch` +接收一个字符串,首尾必须是没有额外包装的独立补丁标记行;isolate 中没有 `import`,长时间运行的 +命令通过 `write_stdin` 轮询。如果原生路由 Responses、Kiro 或 Cursor 路径上的 code-mode exec +结果仍包含宿主的某条失败消息,opencodex 会追加一行提示,指出对应规则。此变更不会重写模型的 +代码或补丁文本。 + 所选 provider 必须支持 function/tool calling。不支持 tool call 的 text-only provider 无法使用 `exec`、 Browser 或 Computer Use。原生 OpenAI 条目会保持其上游 tool mode 不变。 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 f371457be9..44ee5bbb3b 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 @@ -201,6 +201,12 @@ metadata,使用 Codex 的 `low | medium | high | xhigh | max | ultra` 檔位 歷史編碼成上游 function tool,再於 Codex 看見前將串流 function-call lifecycle 還原成 `custom_tool_call`。原生 OpenAI forward 路由與受支援的 `apply_patch` custom tool 維持不變。 +路由的 code-mode 回合也會在首次呼叫前收到主機對巢狀輔助工具的規則:`tools.apply_patch` +接收一個字串,開頭與結尾必須是沒有額外包裝的獨立補丁標記行;isolate 中沒有 `import`,長時間執行的 +命令透過 `write_stdin` 輪詢。如果原生路由 Responses、Kiro 或 Cursor 路徑上的 code-mode exec +結果仍包含主機的某則失敗訊息,opencodex 會附加一行提示,指出對應規則。這項變更不會重寫模型的 +程式碼或補丁文字。 + 所選 provider 必須支援 function/tool calling。不支援 tool call 的純文字 provider 無法使用 `exec`、 Browser 或 Computer Use。原生 OpenAI 列保留上游 tool mode 不變。 From 451fbffb02407cd73e9cf62bff6c40ad09ba3e12 Mon Sep 17 00:00:00 2001 From: x3M3x Date: Wed, 2 Sep 2026 03:42:09 +0400 Subject: [PATCH 5/9] feat gui: expose subagent fallback settings [skip ci] (cherry picked from commit b0d86fa3be8aec324974dc4471d5a98b35102459) Co-authored-by: x3M3x <98298256+x3M3x@users.noreply.github.com> --- .../SubagentDelegationSection.tsx | 33 ++++++++++++ .../SubagentsWorkspace.tsx | 14 +++++ gui/src/i18n/de.ts | 6 +++ gui/src/i18n/en.ts | 6 +++ gui/src/i18n/fr.ts | 6 +++ gui/src/i18n/ja.ts | 6 +++ gui/src/i18n/ko.ts | 6 +++ gui/src/i18n/ru.ts | 6 +++ gui/src/i18n/tr.ts | 6 +++ gui/src/i18n/zh-TW.ts | 6 +++ gui/src/i18n/zh.ts | 6 +++ gui/src/pages/Subagents.tsx | 53 ++++++++++++++++--- 12 files changed, 147 insertions(+), 7 deletions(-) diff --git a/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx b/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx index 46c0447a7c..7c3b0e9425 100644 --- a/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx +++ b/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx @@ -28,6 +28,13 @@ export interface SubagentDelegationSectionProps { onUltraModeSave: (patch: UltraModePatch) => void; ultraLoadFailed: boolean; onUltraModeRetry: () => void; + fallback: string[]; + fallbackPollMs: number; + fallbackBusy: boolean; + availableModels: string[]; + onFallbackChange: (models: string[]) => void; + onFallbackPollMsChange: (pollMs: number) => void; + onFallbackSave: () => void; } export default function SubagentDelegationSection({ @@ -44,6 +51,7 @@ export default function SubagentDelegationSection({ onUltraModeSave, ultraLoadFailed, onUltraModeRetry, + fallback, fallbackPollMs, fallbackBusy, availableModels, onFallbackChange, onFallbackPollMsChange, onFallbackSave, }: SubagentDelegationSectionProps) { const t = useT(); // A present empty/whitespace hint is an upstream override that suppresses the @@ -97,6 +105,31 @@ export default function SubagentDelegationSection({
+
+
+
{t("sub.fallbackLabel")}
+
{t("sub.fallbackHint")}
+
+
+ {fallback.map((modelName, index) => ( +
+ {index + 1}. {modelName} + + + +
+ ))} + + + +
+
+
{t("dash.syncCodexSubagentDefaults")}
diff --git a/gui/src/components/subagents-workspace/SubagentsWorkspace.tsx b/gui/src/components/subagents-workspace/SubagentsWorkspace.tsx index a22bd2a305..30b722b2bf 100644 --- a/gui/src/components/subagents-workspace/SubagentsWorkspace.tsx +++ b/gui/src/components/subagents-workspace/SubagentsWorkspace.tsx @@ -37,6 +37,12 @@ export interface SubagentsWorkspaceProps { onToggle: (m: string) => void; onMove: (i: number, dir: -1 | 1) => void; onSave: () => void; + fallback: string[]; + fallbackPollMs: number; + fallbackBusy: boolean; + onFallbackChange: (models: string[]) => void; + onFallbackPollMsChange: (pollMs: number) => void; + onFallbackSave: () => void; delegation: { model: string; effort: string; @@ -63,6 +69,7 @@ export default function SubagentsWorkspace({ onToggle, onMove, onSave, + fallback, fallbackPollMs, fallbackBusy, onFallbackChange, onFallbackPollMsChange, onFallbackSave, delegation, }: SubagentsWorkspaceProps) { const t = useT(); @@ -237,6 +244,13 @@ export default function SubagentsWorkspace({ onUltraModeSave={delegation.onUltraModeSave} ultraLoadFailed={delegation.ultraLoadFailed} onUltraModeRetry={delegation.onUltraModeRetry} + fallback={fallback} + fallbackPollMs={fallbackPollMs} + fallbackBusy={fallbackBusy} + availableModels={available} + onFallbackChange={onFallbackChange} + onFallbackPollMsChange={onFallbackPollMsChange} + onFallbackSave={onFallbackSave} />
diff --git a/gui/src/i18n/de.ts b/gui/src/i18n/de.ts index 74533a04d3..8985d342a0 100644 --- a/gui/src/i18n/de.ts +++ b/gui/src/i18n/de.ts @@ -686,6 +686,12 @@ export const de: Record = { "sub.ultraModeLoadFail": "Ultra-Modus-Einstellungen konnten nicht geladen werden — läuft der Proxy?", "sub.ultraModeSaveFail": "Ultra-Modus-Einstellungen konnten nicht gespeichert werden", "sub.ultraModeSaved": "Ultra-Modus gespeichert. Gilt für neue Codex-Sitzungen.", + "sub.fallbackLabel": "Fallback-Kette für Sub-Agenten", + "sub.fallbackHint": "Geordnete Modelle, die versucht werden, wenn ein Sub-Agent-Modell nicht verfügbar ist oder fehlschlägt.", + "sub.fallbackAdd": "Fallback-Modell hinzufügen…", + "sub.fallbackPoll": "Intervall der Verfügbarkeitsprüfung", + "sub.fallbackSaved": "Fallback-Einstellungen für Sub-Agenten gespeichert.", + "sub.fallbackSaveFailed": "Fallback-Einstellungen konnten nicht gespeichert werden", "logs.title": "Anfrage-Protokolle", "logs.tabLogs": "Protokolle", "logs.tabDebug": "Diagnose", diff --git a/gui/src/i18n/en.ts b/gui/src/i18n/en.ts index 2197dcb735..a33c195e82 100644 --- a/gui/src/i18n/en.ts +++ b/gui/src/i18n/en.ts @@ -329,6 +329,12 @@ export const en = { "dash.visionTimeout": "Timeout", "dash.visionTimeoutInvalid": "Enter an integer from {min} to {max} milliseconds.", "dash.visionAdvancedPopover": "Advanced vision settings", + "sub.fallbackLabel": "Sub-agent fallback chain", + "sub.fallbackHint": "Ordered models tried when a sub-agent model is unavailable or fails.", + "sub.fallbackAdd": "Add fallback model…", + "sub.fallbackPoll": "Availability check interval", + "sub.fallbackSaved": "Sub-agent fallback settings saved.", + "sub.fallbackSaveFailed": "Failed to save fallback settings", "dash.shadowCallIntercept": "Shadow Call Intercept", "dash.shadowCallInterceptHint": "Intercepts Codex App's background helper calls ({models}) for title generation and commit messages and redirects them to your chosen model.", "dash.shadowCallWarning": "⚠ When enabled, ALL requests for {models} will be replaced with the selected model.", diff --git a/gui/src/i18n/fr.ts b/gui/src/i18n/fr.ts index cca4b70347..fa32925c02 100644 --- a/gui/src/i18n/fr.ts +++ b/gui/src/i18n/fr.ts @@ -319,6 +319,12 @@ export const fr: Record = { "dash.visionTimeout": "Délai d’expiration", "dash.visionTimeoutInvalid": "Saisissez un entier compris entre {min} et {max} millisecondes.", "dash.visionAdvancedPopover": "Paramètres de vision avancés", + "sub.fallbackLabel": "Chaîne de secours des sous-agents", + "sub.fallbackHint": "Modèles essayés dans l’ordre lorsqu’un modèle de sous-agent est indisponible ou échoue.", + "sub.fallbackAdd": "Ajouter un modèle de secours…", + "sub.fallbackPoll": "Intervalle de vérification de disponibilité", + "sub.fallbackSaved": "Paramètres de secours des sous-agents enregistrés.", + "sub.fallbackSaveFailed": "Échec de l’enregistrement des paramètres de secours", "dash.shadowCallIntercept": "Interception des appels fantômes", "dash.shadowCallInterceptHint": "Intercepte les appels auxiliaires en arrière-plan de l’application Codex ({models}) pour générer les titres et les messages de commit, puis les redirige vers le modèle choisi.", "dash.shadowCallWarning": "⚠ Lorsque cette option est activée, TOUTES les requêtes destinées à {models} sont remplacées par le modèle sélectionné.", diff --git a/gui/src/i18n/ja.ts b/gui/src/i18n/ja.ts index 97aa85a6fb..81cd40bca9 100644 --- a/gui/src/i18n/ja.ts +++ b/gui/src/i18n/ja.ts @@ -646,6 +646,12 @@ export const ja: Record = { "sub.ultraModeLoadFail": "ウルトラモード設定を読み込めませんでした — プロキシは実行中ですか?", "sub.ultraModeSaveFail": "ウルトラモード設定の保存に失敗しました", "sub.ultraModeSaved": "ウルトラモードを保存しました。新しい Codex セッションから適用されます。", + "sub.fallbackLabel": "サブエージェントのフォールバックチェーン", + "sub.fallbackHint": "サブエージェントモデルが利用できないか失敗した場合に順番に試すモデルです。", + "sub.fallbackAdd": "フォールバックモデルを追加…", + "sub.fallbackPoll": "利用可能性チェック間隔", + "sub.fallbackSaved": "サブエージェントのフォールバック設定を保存しました。", + "sub.fallbackSaveFailed": "フォールバック設定の保存に失敗しました", // logs "logs.title": "リクエストログ", diff --git a/gui/src/i18n/ko.ts b/gui/src/i18n/ko.ts index 4e66544528..35a726e6ba 100644 --- a/gui/src/i18n/ko.ts +++ b/gui/src/i18n/ko.ts @@ -703,6 +703,12 @@ export const ko: Record = { "sub.ultraModeLoadFail": "울트라 모드 설정을 불러오지 못했습니다 — 프록시가 실행 중인가요?", "sub.ultraModeSaveFail": "울트라 모드 설정 저장에 실패했습니다", "sub.ultraModeSaved": "울트라 모드가 저장되었습니다. 새 Codex 세션부터 적용됩니다.", + "sub.fallbackLabel": "서브에이전트 폴백 체인", + "sub.fallbackHint": "서브에이전트 모델을 사용할 수 없거나 실패할 때 순서대로 시도할 모델입니다.", + "sub.fallbackAdd": "폴백 모델 추가…", + "sub.fallbackPoll": "가용성 확인 간격", + "sub.fallbackSaved": "서브에이전트 폴백 설정을 저장했습니다.", + "sub.fallbackSaveFailed": "폴백 설정을 저장하지 못했습니다", // logs "logs.title": "요청 로그", diff --git a/gui/src/i18n/ru.ts b/gui/src/i18n/ru.ts index e7f199a06a..a7cc5f72e8 100644 --- a/gui/src/i18n/ru.ts +++ b/gui/src/i18n/ru.ts @@ -701,6 +701,12 @@ export const ru: Record = { "sub.ultraModeLoadFail": "Не удалось загрузить настройки ультра-режима — работает ли прокси?", "sub.ultraModeSaveFail": "Не удалось сохранить настройки ультра-режима", "sub.ultraModeSaved": "Ультра-режим сохранён. Применяется к новым сеансам Codex.", + "sub.fallbackLabel": "Цепочка резервных моделей субагента", + "sub.fallbackHint": "Модели, которые последовательно пробуются, если модель субагента недоступна или завершается ошибкой.", + "sub.fallbackAdd": "Добавить резервную модель…", + "sub.fallbackPoll": "Интервал проверки доступности", + "sub.fallbackSaved": "Настройки резервных моделей субагента сохранены.", + "sub.fallbackSaveFailed": "Не удалось сохранить настройки резервных моделей", // logs "logs.title": "Журнал запросов", diff --git a/gui/src/i18n/tr.ts b/gui/src/i18n/tr.ts index 8c8f9ff802..5c0ade9077 100644 --- a/gui/src/i18n/tr.ts +++ b/gui/src/i18n/tr.ts @@ -708,6 +708,12 @@ export const tr: Record = { "sub.ultraModeLoadFail": "Ultra modu ayarları yüklenemedi — proxy çalışıyor mu?", "sub.ultraModeSaveFail": "Ultra modu ayarları kaydedilemedi", "sub.ultraModeSaved": "Ultra modu kaydedildi. Yeni Codex oturumlarına uygulanır.", + "sub.fallbackLabel": "Alt ajan yedek zinciri", + "sub.fallbackHint": "Alt ajan modeli kullanılamadığında veya başarısız olduğunda sırayla denenecek modeller.", + "sub.fallbackAdd": "Yedek model ekle…", + "sub.fallbackPoll": "Kullanılabilirlik kontrol aralığı", + "sub.fallbackSaved": "Alt ajan yedek ayarları kaydedildi.", + "sub.fallbackSaveFailed": "Yedek ayarlar kaydedilemedi", // logs "logs.title": "İstek Günlükleri", diff --git a/gui/src/i18n/zh-TW.ts b/gui/src/i18n/zh-TW.ts index eeec289911..cae0175057 100644 --- a/gui/src/i18n/zh-TW.ts +++ b/gui/src/i18n/zh-TW.ts @@ -555,6 +555,12 @@ export const zhTW: Record = { "sub.ultraModeLoadFail": "無法載入超級模式設定 — 代理是否在執行?", "sub.ultraModeSaveFail": "儲存超級模式設定失敗", "sub.ultraModeSaved": "超級模式已儲存。適用於新的 Codex 會話。", + "sub.fallbackLabel": "子代理備援鏈", + "sub.fallbackHint": "子代理模型無法使用或失敗時,依序嘗試的模型。", + "sub.fallbackAdd": "新增備援模型…", + "sub.fallbackPoll": "可用性檢查間隔", + "sub.fallbackSaved": "子代理備援設定已儲存。", + "sub.fallbackSaveFailed": "備援設定儲存失敗", "logs.title": "請求日誌", "logs.tabLogs": "日誌", "logs.tabDebug": "除錯", diff --git a/gui/src/i18n/zh.ts b/gui/src/i18n/zh.ts index a62e9b2d6b..ce44edc693 100644 --- a/gui/src/i18n/zh.ts +++ b/gui/src/i18n/zh.ts @@ -696,6 +696,12 @@ export const zh: Record = { "sub.ultraModeLoadFail": "无法加载超级模式设置 — 代理是否在运行?", "sub.ultraModeSaveFail": "保存超级模式设置失败", "sub.ultraModeSaved": "超级模式已保存。适用于新的 Codex 会话。", + "sub.fallbackLabel": "子代理回退链", + "sub.fallbackHint": "子代理模型不可用或失败时按顺序尝试的模型。", + "sub.fallbackAdd": "添加回退模型…", + "sub.fallbackPoll": "可用性检查间隔", + "sub.fallbackSaved": "子代理回退设置已保存。", + "sub.fallbackSaveFailed": "保存回退设置失败", // logs "logs.title": "请求日志", diff --git a/gui/src/pages/Subagents.tsx b/gui/src/pages/Subagents.tsx index 6b54d39ffd..299c9306fe 100644 --- a/gui/src/pages/Subagents.tsx +++ b/gui/src/pages/Subagents.tsx @@ -8,7 +8,7 @@ import { useDataSurface } from "../data-surface"; import { DataSurfaceSkeleton } from "../components/data-surface"; import { useSubagentDelegation, type UltraModePatch, type UltraModeState } from "./use-subagent-delegation"; -type CachedSubagents = { available: string[]; chosen: string[] }; +type CachedSubagents = { available: string[]; chosen: string[]; fallback: string[]; pollMs: number }; function seedSubagents(cacheKey: string): CachedSubagents | null { return readSessionListCache(cacheKey); @@ -19,6 +19,9 @@ export default function Subagents({ apiBase }: { apiBase: string }) { const cacheKey = `ocx.subagents.v1:${apiBase}`; const cached = seedSubagents(cacheKey); const [chosen, setChosen] = useState(() => cached?.chosen ?? []); + const [fallback, setFallback] = useState(() => cached?.fallback ?? []); + const [fallbackPollMs, setFallbackPollMs] = useState(() => cached?.pollMs ?? 60000); + const [fallbackBusy, setFallbackBusy] = useState(false); const [status, setStatus] = useState(""); const [ok, setOk] = useState(false); const [busy, setBusy] = useState(false); @@ -117,16 +120,24 @@ export default function Subagents({ apiBase }: { apiBase: string }) { const loadSubagents = useCallback(async (signal?: AbortSignal): Promise => { // The resource layer's deadline abort must reach the wire — a signal dropped // here is a store that can only settle by race timeout. - const res = await fetch(`${apiBase}/api/subagent-models`, { signal }); - const response = await readJsonOrThrow<{ available?: string[]; chosen?: string[] }>(res, t("sub.loadFail")); - if (!response) throw new Error(t("sub.loadFail")); - const available = response.available ?? []; + const [rosterRes, fallbackRes] = await Promise.all([ + fetch(`${apiBase}/api/subagent-models`, { signal }), + fetch(`${apiBase}/api/subagent-model-fallback`, { signal }), + ]); + const response = await readJsonOrThrow<{ available?: string[]; chosen?: string[] }>(rosterRes, t("sub.loadFail")); + const fallbackResponse = await readJsonOrThrow<{ available?: string[]; models?: string[]; pollMs?: number }>(fallbackRes, t("sub.loadFail")); + if (!response || !fallbackResponse) throw new Error(t("sub.loadFail")); + const available = response.available ?? fallbackResponse.available ?? []; const availableSet = new Set(available); const next = { available, chosen: (response.chosen ?? []).filter(model => availableSet.has(model)), + fallback: (fallbackResponse.models ?? []).filter(model => availableSet.has(model)), + pollMs: fallbackResponse.pollMs ?? 60000, }; setChosen(next.chosen); + setFallback(next.fallback); + setFallbackPollMs(next.pollMs); writeSessionListCache(cacheKey, next); return next; }, [apiBase, cacheKey, t]); @@ -174,7 +185,7 @@ export default function Subagents({ apiBase }: { apiBase: string }) { const d = await readJsonOrThrow<{ applied?: string[] }>(r, t("sub.saveFailed")); const applied = d?.applied ?? chosen; if (d?.applied) setChosen(d.applied); - writeSessionListCache(cacheKey, { available, chosen: applied }); + writeSessionListCache(cacheKey, { available, chosen: applied, fallback, pollMs: fallbackPollMs }); setOk(true); setStatus(t("sub.saved", { n: applied.length, cmd: "ocx sync" })); } catch (error) { @@ -186,6 +197,28 @@ export default function Subagents({ apiBase }: { apiBase: string }) { } }; + const saveFallback = async () => { + if (fallbackBusy) return; + setFallbackBusy(true); + try { + const r = await fetch(`${apiBase}/api/subagent-model-fallback`, { + method: "PUT", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ models: fallback, pollMs: fallbackPollMs }), + }); + const d = await readJsonOrThrow<{ models?: string[]; pollMs?: number }>(r, t("sub.fallbackSaveFailed")); + if (d?.models) setFallback(d.models); + if (d?.pollMs) setFallbackPollMs(d.pollMs); + setOk(true); + setStatus(t("sub.fallbackSaved")); + } catch (error) { + setOk(false); + setStatus(error instanceof Error && error.message ? error.message : t("sub.networkError")); + } finally { + setFallbackBusy(false); + } + }; + // The skeleton owns the live region while this resource has no content yet. if (state.showSkeleton && !snapshot) { return ; @@ -214,7 +247,13 @@ export default function Subagents({ apiBase }: { apiBase: string }) { busy={busy} onToggle={toggle} onMove={move} - onSave={() => { void save(); }} + onSave={() => { void save(); }} + fallback={fallback} + fallbackPollMs={fallbackPollMs} + fallbackBusy={fallbackBusy} + onFallbackChange={setFallback} + onFallbackPollMsChange={setFallbackPollMs} + onFallbackSave={() => { void saveFallback(); }} delegation={{ model: delegation.model, effort: delegation.effort, From 2b14053ff625e1750583269829bbbecf0a100b6c Mon Sep 17 00:00:00 2001 From: x3M3x Date: Wed, 2 Sep 2026 09:49:07 +0400 Subject: [PATCH 6/9] docs: add subagent fallback settings screenshot [skip ci] (cherry picked from commit aba57a074941b7cdae3074eca9a0256d0621eb22) Co-authored-by: x3M3x <98298256+x3M3x@users.noreply.github.com> --- .../subagent-fallback-settings.png | Bin 0 -> 215189 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs-site/public/pr-screenshots/subagent-fallback-settings.png diff --git a/docs-site/public/pr-screenshots/subagent-fallback-settings.png b/docs-site/public/pr-screenshots/subagent-fallback-settings.png new file mode 100644 index 0000000000000000000000000000000000000000..04f72f140cd0d904d63ff72f9da7e0a0300e1a5e GIT binary patch literal 215189 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

UR?jC!(*%I%`utfvcyOR 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 Date: Mon, 7 Sep 2026 18:30:58 +0900 Subject: [PATCH 7/9] fix(gui): preserve fallback choices and explain native-parent V2 compatibility [skip ci] Co-authored-by: x3M3x <98298256+x3M3x@users.noreply.github.com> --- .../content/docs/guides/codex-integration.md | 7 + .../SubagentDelegationSection.tsx | 53 ++- gui/src/i18n/de.ts | 18 +- gui/src/i18n/en.ts | 18 +- gui/src/i18n/fr.ts | 18 +- gui/src/i18n/ja.ts | 18 +- gui/src/i18n/ko.ts | 6 + gui/src/i18n/ru.ts | 18 +- gui/src/i18n/tr.ts | 6 + gui/src/i18n/zh-TW.ts | 18 +- gui/src/i18n/zh.ts | 18 +- gui/src/pages/Subagents.tsx | 29 +- gui/src/pages/use-subagent-delegation.ts | 2 + gui/src/styles-subagents-workspace.css | 13 + gui/tests/multi-agent-guidance.test.tsx | 9 +- gui/tests/subagents-fallback.test.tsx | 422 ++++++++++++++++++ 16 files changed, 613 insertions(+), 60 deletions(-) create mode 100644 gui/tests/subagents-fallback.test.tsx diff --git a/docs-site/src/content/docs/guides/codex-integration.md b/docs-site/src/content/docs/guides/codex-integration.md index ff2df04fdd..f5592c0a72 100644 --- a/docs-site/src/content/docs/guides/codex-integration.md +++ b/docs-site/src/content/docs/guides/codex-integration.md @@ -586,3 +586,10 @@ ocx restore back # point plain Codex at the running proxy again When opencodex runs as a managed [background service](/reference/cli/#ocx-service), it sets `OCX_SERVICE=1` so a service-driven restart does **not** thrash the Codex config — only an explicit `ocx stop` / `ocx service stop` restores native Codex. + + +### Sub-agent fallback and V2 compatibility + +In **Subagents → Delegation settings**, edit the ordered fallback chain and its availability polling interval (5000–600000 ms), then save it separately from the featured roster. A configured target that is no longer advertised remains in the chain until you remove it. The roster and fallback chain are separate settings; this editor does not make the roster replace the fallback policy. + +When a routed preferred model may receive V2 work from a native ChatGPT parent, the panel explains the upstream encrypted-task limitation. Readable tasks from routed parents are unaffected. The guidance uses `/api/v2` mode and native V1 pin state; the current API does not expose recovery activation or request-specific eligibility, so the panel reports those as unknown. V1/plaintext-compatible delegation remains an alternative. Experimental V2 recovery, where eligible and explicitly enabled, adds quota usage, latency, backend dependence and possible fidelity loss; it does not repair the upstream protocol. See [sub-agent surfaces](/guides/sub-agent-surface/) and [the upstream limitation](https://github.com/lidge-jun/opencodex/issues/92). diff --git a/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx b/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx index 7c3b0e9425..dbbbd99948 100644 --- a/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx +++ b/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx @@ -8,7 +8,7 @@ */ import { useState } from "react"; import { Select, Tooltip } from "../../ui"; -import { IconInfo } from "../../icons"; +import { IconArrowDown, IconArrowUp, IconInfo, IconX } from "../../icons"; import { useT, type TKey } from "../../i18n/shared"; import { formatNamespacedModelId } from "../../provider-icons"; import type { DelegationPatch, DelegationModelOption } from "../../pages/use-subagent-delegation"; @@ -58,6 +58,19 @@ export default function SubagentDelegationSection({ // Proactive message, so it must render as OFF (and the toggle can install the // preset). Only a nonblank hint is "on". const ultraOn = (ultraMode.hintText ?? "").trim().length > 0; + const routedPreferred = available.some(option => option.namespaced === model + && !(option.provider === "openai" && option.namespaced === option.model)); + const nativeMayUseV2 = ultraMode.enabled || (ultraMode.multiAgentMode !== "v1" + && !(ultraMode.multiAgentMode === "v2" && ultraMode.keepNativeChatGptOnV1)); + const showV2Compatibility = !ultraLoadFailed && ultraMode.loaded === true && routedPreferred && nativeMayUseV2; + const validPollMs = Number.isInteger(fallbackPollMs) && fallbackPollMs >= 5000 && fallbackPollMs <= 600000; + const moveFallback = (index: number, direction: -1 | 1) => { + const next = [...fallback]; + const target = index + direction; + if (fallbackBusy || target < 0 || target >= next.length) return; + [next[index], next[target]] = [next[target], next[index]]; + onFallbackChange(next); + }; return (

@@ -105,6 +118,17 @@ export default function SubagentDelegationSection({
+ {showV2Compatibility && ( +
+
+
{t("sub.v2Compatibility.title")}
+

{t("sub.v2Compatibility.risk")}

+

{t("sub.v2Compatibility.recoveryUnknown")}

+ {t("sub.v2Compatibility.details")} +
+
+ )} +
{t("sub.fallbackLabel")}
@@ -112,21 +136,26 @@ export default function SubagentDelegationSection({
{fallback.map((modelName, index) => ( -
- {index + 1}. {modelName} - - - +
+ {index + 1}. {modelName} + {!availableModels.includes(modelName) && {t("sub.fallbackUnavailable")}} + + + + + +
))} - + onFallbackPollMsChange(Number(e.target.value) || 60000)} disabled={fallbackBusy} /> ms + onFallbackPollMsChange(Number(e.target.value))} disabled={fallbackBusy} aria-invalid={!validPollMs} /> ms - + {!validPollMs &&
{t("sub.fallbackPollInvalid")}
} +
diff --git a/gui/src/i18n/de.ts b/gui/src/i18n/de.ts index 8985d342a0..4145cb8032 100644 --- a/gui/src/i18n/de.ts +++ b/gui/src/i18n/de.ts @@ -686,12 +686,6 @@ export const de: Record = { "sub.ultraModeLoadFail": "Ultra-Modus-Einstellungen konnten nicht geladen werden — läuft der Proxy?", "sub.ultraModeSaveFail": "Ultra-Modus-Einstellungen konnten nicht gespeichert werden", "sub.ultraModeSaved": "Ultra-Modus gespeichert. Gilt für neue Codex-Sitzungen.", - "sub.fallbackLabel": "Fallback-Kette für Sub-Agenten", - "sub.fallbackHint": "Geordnete Modelle, die versucht werden, wenn ein Sub-Agent-Modell nicht verfügbar ist oder fehlschlägt.", - "sub.fallbackAdd": "Fallback-Modell hinzufügen…", - "sub.fallbackPoll": "Intervall der Verfügbarkeitsprüfung", - "sub.fallbackSaved": "Fallback-Einstellungen für Sub-Agenten gespeichert.", - "sub.fallbackSaveFailed": "Fallback-Einstellungen konnten nicht gespeichert werden", "logs.title": "Anfrage-Protokolle", "logs.tabLogs": "Protokolle", "logs.tabDebug": "Diagnose", @@ -2414,6 +2408,18 @@ export const de: Record = { "sub.sections": "Subagent-Abschnitte", "sub.delegation.model": "Zuerst aufgerufenes Modell", "sub.delegation.modelHint": "Das Modell, zu dem Codex zuerst greift, wenn es Arbeit übergibt. Oben steht, wen es überhaupt aufrufen darf; hier wählst du den Ersten davon.", + "sub.fallbackLabel": "Fallback-Kette für Sub-Agenten", + "sub.fallbackHint": "Geordnete Modelle, die versucht werden, wenn ein Sub-Agent-Modell nicht verfügbar ist oder fehlschlägt.", + "sub.fallbackAdd": "Fallback-Modell hinzufügen…", + "sub.fallbackPoll": "Intervall der Verfügbarkeitsprüfung", + "sub.fallbackSaved": "Fallback-Einstellungen für Sub-Agenten gespeichert.", + "sub.fallbackSaveFailed": "Fallback-Einstellungen konnten nicht gespeichert werden", + "sub.fallbackUnavailable": "Derzeit nicht gelistet; bleibt in der Kette.", + "sub.fallbackPollInvalid": "Eine ganze Zahl von 5000 bis 600000 ms eingeben.", + "sub.v2Compatibility.title": "V2-Kompatibilität nativer Eltern", + "sub.v2Compatibility.risk": "Delegiert ein nativer ChatGPT-Elternagent über V2 an dieses geroutete Modell, kann die Aufgabe verschlüsselt sein und vor der Ausführung scheitern. Lesbare Aufgaben gerouteter Eltern sind nicht betroffen.", + "sub.v2Compatibility.recoveryUnknown": "Dieser Server meldet weder Aktivierung noch Eignung der Wiederherstellung. V1/Klartext verwenden oder experimentelle V2-Wiederherstellung nur bei Eignung aktivieren. Sie kostet Kontingent und Latenz, hängt vom Backend ab und kann Wiedergabetreue verlieren; das Upstream-Protokoll bleibt unverändert.", + "sub.v2Compatibility.details": "Details zur Kompatibilität", "dash.syncModelsHint": "Schreibt Codex' Modellkatalog anhand deiner verbundenen Provider neu.", "dash.syncRun": "Jetzt synchronisieren", "lab.title": "Kompatibilitäts-Labor", diff --git a/gui/src/i18n/en.ts b/gui/src/i18n/en.ts index a33c195e82..2a31ec7947 100644 --- a/gui/src/i18n/en.ts +++ b/gui/src/i18n/en.ts @@ -329,12 +329,6 @@ export const en = { "dash.visionTimeout": "Timeout", "dash.visionTimeoutInvalid": "Enter an integer from {min} to {max} milliseconds.", "dash.visionAdvancedPopover": "Advanced vision settings", - "sub.fallbackLabel": "Sub-agent fallback chain", - "sub.fallbackHint": "Ordered models tried when a sub-agent model is unavailable or fails.", - "sub.fallbackAdd": "Add fallback model…", - "sub.fallbackPoll": "Availability check interval", - "sub.fallbackSaved": "Sub-agent fallback settings saved.", - "sub.fallbackSaveFailed": "Failed to save fallback settings", "dash.shadowCallIntercept": "Shadow Call Intercept", "dash.shadowCallInterceptHint": "Intercepts Codex App's background helper calls ({models}) for title generation and commit messages and redirects them to your chosen model.", "dash.shadowCallWarning": "⚠ When enabled, ALL requests for {models} will be replaced with the selected model.", @@ -725,6 +719,18 @@ export const en = { "sub.workspace.selectModel": "Select a model", "sub.workspace.selectModelDesc": "Pick a model from the list to see details and feature it for spawn_agent.", "sub.workspace.selector": "Public selector", + "sub.fallbackLabel": "Sub-agent fallback chain", + "sub.fallbackHint": "Ordered models tried when a sub-agent model is unavailable or fails.", + "sub.fallbackAdd": "Add fallback model…", + "sub.fallbackPoll": "Availability check interval", + "sub.fallbackSaved": "Sub-agent fallback settings saved.", + "sub.fallbackSaveFailed": "Failed to save fallback settings", + "sub.fallbackUnavailable": "Not currently advertised; kept in the chain.", + "sub.fallbackPollInvalid": "Enter an integer from 5000 to 600000 ms.", + "sub.v2Compatibility.title": "Native-parent V2 compatibility", + "sub.v2Compatibility.risk": "If a native ChatGPT parent delegates to this routed model using V2, its task may be encrypted and fail before execution. Readable tasks from routed parents are unaffected.", + "sub.v2Compatibility.recoveryUnknown": "Recovery enabled/eligibility state is not exposed by this server. Use V1/plaintext-compatible delegation, or enable experimental V2 recovery only if eligible. Recovery adds quota, latency, backend dependence and possible fidelity loss; it does not fix the upstream protocol.", + "sub.v2Compatibility.details": "Compatibility details", // logs "logs.title": "Request Logs", diff --git a/gui/src/i18n/fr.ts b/gui/src/i18n/fr.ts index fa32925c02..753982c1bf 100644 --- a/gui/src/i18n/fr.ts +++ b/gui/src/i18n/fr.ts @@ -319,12 +319,6 @@ export const fr: Record = { "dash.visionTimeout": "Délai d’expiration", "dash.visionTimeoutInvalid": "Saisissez un entier compris entre {min} et {max} millisecondes.", "dash.visionAdvancedPopover": "Paramètres de vision avancés", - "sub.fallbackLabel": "Chaîne de secours des sous-agents", - "sub.fallbackHint": "Modèles essayés dans l’ordre lorsqu’un modèle de sous-agent est indisponible ou échoue.", - "sub.fallbackAdd": "Ajouter un modèle de secours…", - "sub.fallbackPoll": "Intervalle de vérification de disponibilité", - "sub.fallbackSaved": "Paramètres de secours des sous-agents enregistrés.", - "sub.fallbackSaveFailed": "Échec de l’enregistrement des paramètres de secours", "dash.shadowCallIntercept": "Interception des appels fantômes", "dash.shadowCallInterceptHint": "Intercepte les appels auxiliaires en arrière-plan de l’application Codex ({models}) pour générer les titres et les messages de commit, puis les redirige vers le modèle choisi.", "dash.shadowCallWarning": "⚠ Lorsque cette option est activée, TOUTES les requêtes destinées à {models} sont remplacées par le modèle sélectionné.", @@ -708,6 +702,18 @@ export const fr: Record = { "sub.workspace.selectModel": "Sélectionner un modèle", "sub.workspace.selectModelDesc": "Choisissez un modèle dans la liste pour afficher ses détails et le mettre à la une pour spawn_agent.", "sub.workspace.selector": "Sélecteur public", + "sub.fallbackLabel": "Chaîne de secours des sous-agents", + "sub.fallbackHint": "Modèles essayés dans l’ordre lorsqu’un modèle de sous-agent est indisponible ou échoue.", + "sub.fallbackAdd": "Ajouter un modèle de secours…", + "sub.fallbackPoll": "Intervalle de vérification de disponibilité", + "sub.fallbackSaved": "Paramètres de secours des sous-agents enregistrés.", + "sub.fallbackSaveFailed": "Échec de l’enregistrement des paramètres de secours", + "sub.fallbackUnavailable": "Absent du catalogue actuel ; conservé dans la chaîne.", + "sub.fallbackPollInvalid": "Saisissez un entier de 5000 à 600000 ms.", + "sub.v2Compatibility.title": "Compatibilité V2 du parent natif", + "sub.v2Compatibility.risk": "Si un parent ChatGPT natif délègue à ce modèle routé via V2, la tâche peut être chiffrée et échouer avant son exécution. Les tâches lisibles des parents routés ne sont pas affectées.", + "sub.v2Compatibility.recoveryUnknown": "Ce serveur ne fournit pas l’activation ni l’éligibilité de la récupération. Utilisez V1/texte clair, ou activez la récupération V2 expérimentale uniquement si éligible. Elle ajoute quota, latence, dépendance au backend et risque de perte de fidélité ; elle ne corrige pas le protocole amont.", + "sub.v2Compatibility.details": "Détails de compatibilité", "logs.title": "Journaux des requêtes", "logs.tabLogs": "Journaux", "logs.tabDebug": "Débogage", diff --git a/gui/src/i18n/ja.ts b/gui/src/i18n/ja.ts index 81cd40bca9..300d1f8c51 100644 --- a/gui/src/i18n/ja.ts +++ b/gui/src/i18n/ja.ts @@ -646,12 +646,6 @@ export const ja: Record = { "sub.ultraModeLoadFail": "ウルトラモード設定を読み込めませんでした — プロキシは実行中ですか?", "sub.ultraModeSaveFail": "ウルトラモード設定の保存に失敗しました", "sub.ultraModeSaved": "ウルトラモードを保存しました。新しい Codex セッションから適用されます。", - "sub.fallbackLabel": "サブエージェントのフォールバックチェーン", - "sub.fallbackHint": "サブエージェントモデルが利用できないか失敗した場合に順番に試すモデルです。", - "sub.fallbackAdd": "フォールバックモデルを追加…", - "sub.fallbackPoll": "利用可能性チェック間隔", - "sub.fallbackSaved": "サブエージェントのフォールバック設定を保存しました。", - "sub.fallbackSaveFailed": "フォールバック設定の保存に失敗しました", // logs "logs.title": "リクエストログ", @@ -2435,6 +2429,18 @@ export const ja: Record = { "sub.sections": "サブエージェントのセクション", "sub.delegation.model": "最初に呼ぶモデル", "sub.delegation.modelHint": "Codex が作業を任せるとき、最初に呼ぶモデルです。上のおすすめが呼べる候補で、ここで選んだものがその中の第一候補になります。", + "sub.fallbackLabel": "サブエージェントのフォールバックチェーン", + "sub.fallbackHint": "サブエージェントモデルが利用できないか失敗した場合に順番に試すモデルです。", + "sub.fallbackAdd": "フォールバックモデルを追加…", + "sub.fallbackPoll": "利用可能性チェック間隔", + "sub.fallbackSaved": "サブエージェントのフォールバック設定を保存しました。", + "sub.fallbackSaveFailed": "フォールバック設定の保存に失敗しました", + "sub.fallbackUnavailable": "現在の一覧にはありませんが、チェーンに保持されます。", + "sub.fallbackPollInvalid": "5000〜600000 ms の整数を入力してください。", + "sub.v2Compatibility.title": "ネイティブ親の V2 互換性", + "sub.v2Compatibility.risk": "ネイティブ ChatGPT 親が V2 でこのルーティングモデルに委任すると、タスクが暗号化され実行前に失敗する場合があります。ルーティング親からの読み取り可能なタスクは影響を受けません。", + "sub.v2Compatibility.recoveryUnknown": "このサーバーは復旧の有効状態や適格性を公開していません。V1・平文互換の委任を使うか、適格な場合のみ実験的 V2 復旧を有効にしてください。復旧にはクォータ、遅延、バックエンド依存、忠実度低下の可能性があり、上流プロトコルは修正されません。", + "sub.v2Compatibility.details": "互換性の詳細", "dash.syncModelsHint": "接続済みのプロバイダーをもとに Codex のモデルカタログを書き直します。", "dash.syncRun": "今すぐ同期", "lab.title": "Compatibility Lab", diff --git a/gui/src/i18n/ko.ts b/gui/src/i18n/ko.ts index 35a726e6ba..42c000c6bb 100644 --- a/gui/src/i18n/ko.ts +++ b/gui/src/i18n/ko.ts @@ -709,6 +709,12 @@ export const ko: Record = { "sub.fallbackPoll": "가용성 확인 간격", "sub.fallbackSaved": "서브에이전트 폴백 설정을 저장했습니다.", "sub.fallbackSaveFailed": "폴백 설정을 저장하지 못했습니다", + "sub.fallbackUnavailable": "현재 목록에 없지만 체인에 유지됩니다.", + "sub.fallbackPollInvalid": "5000~600000ms 범위의 정수를 입력하세요.", + "sub.v2Compatibility.title": "네이티브 부모의 V2 호환성", + "sub.v2Compatibility.risk": "네이티브 ChatGPT 부모가 V2로 이 라우팅 모델에 위임하면 작업이 암호화되어 실행 전에 실패할 수 있습니다. 라우팅 부모가 보내는 읽을 수 있는 작업에는 영향이 없습니다.", + "sub.v2Compatibility.recoveryUnknown": "이 서버는 복구 활성화 여부와 사용 가능 상태를 제공하지 않습니다. V1·평문 호환 위임을 사용하거나, 조건을 충족할 때만 실험적 V2 복구를 켜세요. 복구에는 할당량·지연·백엔드 의존성과 원문 충실도 손실 가능성이 따르며, 업스트림 프로토콜을 고치지는 않습니다.", + "sub.v2Compatibility.details": "호환성 자세히 보기", // logs "logs.title": "요청 로그", diff --git a/gui/src/i18n/ru.ts b/gui/src/i18n/ru.ts index a7cc5f72e8..51fcaef210 100644 --- a/gui/src/i18n/ru.ts +++ b/gui/src/i18n/ru.ts @@ -701,12 +701,6 @@ export const ru: Record = { "sub.ultraModeLoadFail": "Не удалось загрузить настройки ультра-режима — работает ли прокси?", "sub.ultraModeSaveFail": "Не удалось сохранить настройки ультра-режима", "sub.ultraModeSaved": "Ультра-режим сохранён. Применяется к новым сеансам Codex.", - "sub.fallbackLabel": "Цепочка резервных моделей субагента", - "sub.fallbackHint": "Модели, которые последовательно пробуются, если модель субагента недоступна или завершается ошибкой.", - "sub.fallbackAdd": "Добавить резервную модель…", - "sub.fallbackPoll": "Интервал проверки доступности", - "sub.fallbackSaved": "Настройки резервных моделей субагента сохранены.", - "sub.fallbackSaveFailed": "Не удалось сохранить настройки резервных моделей", // logs "logs.title": "Журнал запросов", @@ -2437,6 +2431,18 @@ export const ru: Record = { "sub.sections": "Разделы подагентов", "sub.delegation.model": "Модель, которую вызывать первой", "sub.delegation.modelHint": "Модель, к которой Codex обращается первой, когда передаёт работу. Список выше — кого он вообще может вызвать, а здесь выбирается первый в очереди.", + "sub.fallbackLabel": "Цепочка резервных моделей субагента", + "sub.fallbackHint": "Модели, которые последовательно пробуются, если модель субагента недоступна или завершается ошибкой.", + "sub.fallbackAdd": "Добавить резервную модель…", + "sub.fallbackPoll": "Интервал проверки доступности", + "sub.fallbackSaved": "Настройки резервных моделей субагента сохранены.", + "sub.fallbackSaveFailed": "Не удалось сохранить настройки резервных моделей", + "sub.fallbackUnavailable": "Сейчас отсутствует в каталоге; сохранена в цепочке.", + "sub.fallbackPollInvalid": "Введите целое число от 5000 до 600000 мс.", + "sub.v2Compatibility.title": "Совместимость V2 с нативным родителем", + "sub.v2Compatibility.risk": "Если нативный родитель ChatGPT делегирует этой маршрутизируемой модели через V2, задача может быть зашифрована и завершиться ошибкой до выполнения. Читаемые задачи маршрутизируемых родителей не затрагиваются.", + "sub.v2Compatibility.recoveryUnknown": "Сервер не сообщает, включено ли восстановление и доступно ли оно. Используйте V1/открытый текст или включите экспериментальное восстановление V2 только при соответствии условиям. Оно расходует квоту, увеличивает задержку, зависит от бэкенда и может снизить точность; исходный протокол не исправляется.", + "sub.v2Compatibility.details": "Подробнее о совместимости", "dash.syncModelsHint": "Перезаписывает каталог моделей Codex по подключённым провайдерам.", "dash.syncRun": "Синхронизировать", "lab.title": "Compatibility Lab", diff --git a/gui/src/i18n/tr.ts b/gui/src/i18n/tr.ts index 5c0ade9077..c764bf11ca 100644 --- a/gui/src/i18n/tr.ts +++ b/gui/src/i18n/tr.ts @@ -714,6 +714,12 @@ export const tr: Record = { "sub.fallbackPoll": "Kullanılabilirlik kontrol aralığı", "sub.fallbackSaved": "Alt ajan yedek ayarları kaydedildi.", "sub.fallbackSaveFailed": "Yedek ayarlar kaydedilemedi", + "sub.fallbackUnavailable": "Şu anda listelenmiyor; zincirde korunur.", + "sub.fallbackPollInvalid": "5000–600000 ms arasında bir tam sayı girin.", + "sub.v2Compatibility.title": "Yerel üst ajanın V2 uyumluluğu", + "sub.v2Compatibility.risk": "Yerel ChatGPT üst ajanı V2 ile bu yönlendirilmiş modele görev verirse görev şifrelenmiş olabilir ve yürütülmeden başarısız olabilir. Yönlendirilmiş üst ajanların okunabilir görevleri etkilenmez.", + "sub.v2Compatibility.recoveryUnknown": "Bu sunucu kurtarmanın etkinliğini veya uygunluğunu bildirmez. V1/düz metin kullanın ya da deneysel V2 kurtarmayı yalnızca uygunsa açın. Kurtarma kota, gecikme, arka uç bağımlılığı ve aslına uygunluk kaybı getirebilir; üst sistem protokolünü düzeltmez.", + "sub.v2Compatibility.details": "Uyumluluk ayrıntıları", // logs "logs.title": "İstek Günlükleri", diff --git a/gui/src/i18n/zh-TW.ts b/gui/src/i18n/zh-TW.ts index cae0175057..ab6aedd67a 100644 --- a/gui/src/i18n/zh-TW.ts +++ b/gui/src/i18n/zh-TW.ts @@ -555,12 +555,6 @@ export const zhTW: Record = { "sub.ultraModeLoadFail": "無法載入超級模式設定 — 代理是否在執行?", "sub.ultraModeSaveFail": "儲存超級模式設定失敗", "sub.ultraModeSaved": "超級模式已儲存。適用於新的 Codex 會話。", - "sub.fallbackLabel": "子代理備援鏈", - "sub.fallbackHint": "子代理模型無法使用或失敗時,依序嘗試的模型。", - "sub.fallbackAdd": "新增備援模型…", - "sub.fallbackPoll": "可用性檢查間隔", - "sub.fallbackSaved": "子代理備援設定已儲存。", - "sub.fallbackSaveFailed": "備援設定儲存失敗", "logs.title": "請求日誌", "logs.tabLogs": "日誌", "logs.tabDebug": "除錯", @@ -1972,6 +1966,18 @@ export const zhTW: Record = { "sub.sections": "子代理分區", "sub.delegation.model": "優先調用的模型", "sub.delegation.modelHint": "Codex 分派工作時最先調用的模型。上面的推薦是可調用的名單,這裡選的是其中第一順位。", + "sub.fallbackLabel": "子代理備援鏈", + "sub.fallbackHint": "子代理模型無法使用或失敗時,依序嘗試的模型。", + "sub.fallbackAdd": "新增備援模型…", + "sub.fallbackPoll": "可用性檢查間隔", + "sub.fallbackSaved": "子代理備援設定已儲存。", + "sub.fallbackSaveFailed": "備援設定儲存失敗", + "sub.fallbackUnavailable": "目前未列出,仍保留在回退鏈中。", + "sub.fallbackPollInvalid": "請輸入 5000 到 600000 ms 之間的整數。", + "sub.v2Compatibility.title": "原生父代理的 V2 相容性", + "sub.v2Compatibility.risk": "原生 ChatGPT 父代理透過 V2 委派給此路由模型時,任務可能被加密並在執行前失敗。路由父代理傳送的可讀任務不受影響。", + "sub.v2Compatibility.recoveryUnknown": "此伺服器未提供復原功能的啟用或適用狀態。請使用 V1/明文相容委派,或僅在符合條件時啟用實驗性 V2 復原。復原會增加配額消耗、延遲、後端依賴及保真度損失風險,並不修復上游協定。", + "sub.v2Compatibility.details": "相容性詳情", "debug.loadFailed": "無法載入偵錯設定。", "provider.name.volcengine": "Volcengine Ark", "provider.name.volcengineCodingPlan": "Volcengine Ark Coding Plan", diff --git a/gui/src/i18n/zh.ts b/gui/src/i18n/zh.ts index ce44edc693..052f449855 100644 --- a/gui/src/i18n/zh.ts +++ b/gui/src/i18n/zh.ts @@ -696,12 +696,6 @@ export const zh: Record = { "sub.ultraModeLoadFail": "无法加载超级模式设置 — 代理是否在运行?", "sub.ultraModeSaveFail": "保存超级模式设置失败", "sub.ultraModeSaved": "超级模式已保存。适用于新的 Codex 会话。", - "sub.fallbackLabel": "子代理回退链", - "sub.fallbackHint": "子代理模型不可用或失败时按顺序尝试的模型。", - "sub.fallbackAdd": "添加回退模型…", - "sub.fallbackPoll": "可用性检查间隔", - "sub.fallbackSaved": "子代理回退设置已保存。", - "sub.fallbackSaveFailed": "保存回退设置失败", // logs "logs.title": "请求日志", @@ -2435,6 +2429,18 @@ export const zh: Record = { "sub.sections": "子代理分区", "sub.delegation.model": "优先调用的模型", "sub.delegation.modelHint": "Codex 分派工作时最先调用的模型。上面的推荐是可调用的名单,这里选的是其中第一顺位。", + "sub.fallbackLabel": "子代理回退链", + "sub.fallbackHint": "子代理模型不可用或失败时按顺序尝试的模型。", + "sub.fallbackAdd": "添加回退模型…", + "sub.fallbackPoll": "可用性检查间隔", + "sub.fallbackSaved": "子代理回退设置已保存。", + "sub.fallbackSaveFailed": "保存回退设置失败", + "sub.fallbackUnavailable": "当前未列出,仍保留在回退链中。", + "sub.fallbackPollInvalid": "请输入 5000 到 600000 ms 之间的整数。", + "sub.v2Compatibility.title": "原生父代理的 V2 兼容性", + "sub.v2Compatibility.risk": "原生 ChatGPT 父代理通过 V2 委派给此路由模型时,任务可能被加密并在执行前失败。路由父代理发送的可读任务不受影响。", + "sub.v2Compatibility.recoveryUnknown": "此服务器未提供恢复功能的启用或适用状态。请使用 V1/明文兼容委派,或仅在符合条件时启用实验性 V2 恢复。恢复会增加配额消耗、延迟、后端依赖及保真度损失风险,并不修复上游协议。", + "sub.v2Compatibility.details": "兼容性详情", "dash.syncModelsHint": "按已连接的提供商重写 Codex 的模型目录。", "dash.syncRun": "立即同步", "lab.title": "Compatibility Lab", diff --git a/gui/src/pages/Subagents.tsx b/gui/src/pages/Subagents.tsx index 299c9306fe..cbdb138e33 100644 --- a/gui/src/pages/Subagents.tsx +++ b/gui/src/pages/Subagents.tsx @@ -22,6 +22,8 @@ export default function Subagents({ apiBase }: { apiBase: string }) { const [fallback, setFallback] = useState(() => cached?.fallback ?? []); const [fallbackPollMs, setFallbackPollMs] = useState(() => cached?.pollMs ?? 60000); const [fallbackBusy, setFallbackBusy] = useState(false); + const fallbackSaveInFlight = useRef(false); + const committed = useRef(cached); const [status, setStatus] = useState(""); const [ok, setOk] = useState(false); const [busy, setBusy] = useState(false); @@ -49,12 +51,15 @@ export default function Subagents({ apiBase }: { apiBase: string }) { enabled?: boolean; multiAgentMode?: "v1" | "default" | "v2"; multiAgentModeHintText?: string | null; + keepNativeChatGptOnV1?: boolean; }>(res, t("sub.ultraModeLoadFail")); if (!data) return false; if (signal?.aborted || generation !== ultraLoadGeneration.current || currentUltraApiBase.current !== apiBase) return false; setUltraLoadFailed(false); setUltraMode({ enabled: data.enabled ?? false, + loaded: true, + keepNativeChatGptOnV1: data.keepNativeChatGptOnV1 === true, hintText: data.multiAgentModeHintText ?? null, // Ultra mode replaces Codex's effort-derived policy for every model. The // `default` surface still preserves upstream V1 pins (for example luna), @@ -132,9 +137,12 @@ export default function Subagents({ apiBase }: { apiBase: string }) { const next = { available, chosen: (response.chosen ?? []).filter(model => availableSet.has(model)), - fallback: (fallbackResponse.models ?? []).filter(model => availableSet.has(model)), + // Configured targets remain editable even when discovery no longer advertises them. + fallback: fallbackResponse.models ?? [], pollMs: fallbackResponse.pollMs ?? 60000, }; + if (signal?.aborted) throw signal.reason; + committed.current = next; setChosen(next.chosen); setFallback(next.fallback); setFallbackPollMs(next.pollMs); @@ -185,7 +193,9 @@ export default function Subagents({ apiBase }: { apiBase: string }) { const d = await readJsonOrThrow<{ applied?: string[] }>(r, t("sub.saveFailed")); const applied = d?.applied ?? chosen; if (d?.applied) setChosen(d.applied); - writeSessionListCache(cacheKey, { available, chosen: applied, fallback, pollMs: fallbackPollMs }); + const next = { available, chosen: applied, fallback: committed.current?.fallback ?? [], pollMs: committed.current?.pollMs ?? 60000 }; + committed.current = next; + writeSessionListCache(cacheKey, next); setOk(true); setStatus(t("sub.saved", { n: applied.length, cmd: "ocx sync" })); } catch (error) { @@ -198,8 +208,11 @@ export default function Subagents({ apiBase }: { apiBase: string }) { }; const saveFallback = async () => { - if (fallbackBusy) return; + if (fallbackSaveInFlight.current || !Number.isInteger(fallbackPollMs) || fallbackPollMs < 5000 || fallbackPollMs > 600000) return; + fallbackSaveInFlight.current = true; + const requestApiBase = apiBase; setFallbackBusy(true); + setStatus(""); try { const r = await fetch(`${apiBase}/api/subagent-model-fallback`, { method: "PUT", @@ -207,14 +220,20 @@ export default function Subagents({ apiBase }: { apiBase: string }) { body: JSON.stringify({ models: fallback, pollMs: fallbackPollMs }), }); const d = await readJsonOrThrow<{ models?: string[]; pollMs?: number }>(r, t("sub.fallbackSaveFailed")); - if (d?.models) setFallback(d.models); - if (d?.pollMs) setFallbackPollMs(d.pollMs); + if (currentUltraApiBase.current !== requestApiBase) return; + if (!d || !Array.isArray(d.models) || typeof d.pollMs !== "number") throw new Error(t("sub.fallbackSaveFailed")); + setFallback(d.models); + setFallbackPollMs(d.pollMs); + const next = { available, chosen: committed.current?.chosen ?? [], fallback: d.models, pollMs: d.pollMs }; + committed.current = next; + writeSessionListCache(cacheKey, next); setOk(true); setStatus(t("sub.fallbackSaved")); } catch (error) { setOk(false); setStatus(error instanceof Error && error.message ? error.message : t("sub.networkError")); } finally { + fallbackSaveInFlight.current = false; setFallbackBusy(false); } }; diff --git a/gui/src/pages/use-subagent-delegation.ts b/gui/src/pages/use-subagent-delegation.ts index 716eb11482..9baa5baa9a 100644 --- a/gui/src/pages/use-subagent-delegation.ts +++ b/gui/src/pages/use-subagent-delegation.ts @@ -21,6 +21,8 @@ export type DelegationPatch = { /** Ultra mode (Proactive delegation for every model/effort) via /api/v2. */ export type UltraModeState = { + loaded?: boolean; + keepNativeChatGptOnV1?: boolean; enabled: boolean; hintText: string | null; multiAgentV2Enabled: boolean; diff --git a/gui/src/styles-subagents-workspace.css b/gui/src/styles-subagents-workspace.css index c6292077b7..a9f9466ce7 100644 --- a/gui/src/styles-subagents-workspace.css +++ b/gui/src/styles-subagents-workspace.css @@ -575,3 +575,16 @@ } } } + + +/* Fallback targets keep their identifiers readable next to row actions. */ +.swi-fallback-controls { display: flex; flex-direction: column; align-items: stretch; gap: var(--space-2); flex: 1 1 55%; min-width: 0; } +.swi-fallback-row { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); } +.swi-fallback-model { min-width: 0; overflow-wrap: anywhere; } +.swi-fallback-model .setting-hint { display: block; } +.swi-fallback-actions { display: inline-flex; flex-shrink: 0; } +.swi-fallback-controls > .btn { align-self: flex-end; } +@media (max-width: 640px) { + .swi-fallback-editor { flex-direction: column; } + .swi-fallback-controls { width: 100%; } +} diff --git a/gui/tests/multi-agent-guidance.test.tsx b/gui/tests/multi-agent-guidance.test.tsx index 16470385b8..8907406f0e 100644 --- a/gui/tests/multi-agent-guidance.test.tsx +++ b/gui/tests/multi-agent-guidance.test.tsx @@ -65,7 +65,14 @@ function props(overrides: Partial = {}): Props { guidanceEnabled: false, syncCodexDefaults: true, onSave: (patch) => { requests.push(patch); }, - ultraMode: { enabled: false, hintText: null, multiAgentV2Enabled: false }, + ultraMode: { enabled: false, hintText: null, multiAgentV2Enabled: false, multiAgentMode: "default" }, + fallback: [], + fallbackPollMs: 60000, + fallbackBusy: false, + availableModels: [], + onFallbackChange: () => {}, + onFallbackPollMsChange: () => {}, + onFallbackSave: () => {}, ultraSaving: false, onUltraModeSave: () => {}, ultraLoadFailed: false, diff --git a/gui/tests/subagents-fallback.test.tsx b/gui/tests/subagents-fallback.test.tsx new file mode 100644 index 0000000000..20badc4980 --- /dev/null +++ b/gui/tests/subagents-fallback.test.tsx @@ -0,0 +1,422 @@ +import { afterEach, beforeEach, expect, test } from "bun:test"; +import { Window } from "happy-dom"; +import { act } from "react"; +import type { Root } from "react-dom/client"; +import { clearClientResourceStoresForTests } from "../src/client-resource"; +import { en } from "../src/i18n/en"; +import { LanguageProvider } from "../src/i18n/provider"; +import Subagents from "../src/pages/Subagents"; +import { readSessionListCache } from "../src/session-list-cache"; + +const CACHE_KEY = "ocx.subagents.v1:"; +const FALLBACK_PATH = "/api/subagent-model-fallback"; +const ROSTER_PATH = "/api/subagent-models"; +const UNAVAILABLE_MODEL = "retired-provider/configured-model"; +const globals = [ + "document", "window", "navigator", "localStorage", "sessionStorage", "fetch", "IS_REACT_ACT_ENVIRONMENT", +] as const; + +type CachedSubagents = { available: string[]; chosen: string[]; fallback: string[]; pollMs: number }; +type FallbackSettings = { models: string[]; pollMs: number }; +type SentRequest = { path: string; method: string; init?: RequestInit }; +type V2Settings = { + enabled: boolean; + multiAgentMode: "v1" | "default" | "v2"; + multiAgentModeHintText: string | null; + keepNativeChatGptOnV1: boolean; +}; + +let previousGlobals: Record<(typeof globals)[number], PropertyDescriptor | undefined>; +let testWindow: Window; +let container: HTMLElement; +let root: Root | null = null; +let requests: SentRequest[]; +let available: string[]; +let chosen: string[]; +let fallbackSettings: FallbackSettings; +let failFallbackPut: boolean; +let v2Settings: V2Settings; +let preferredModel: string | null; +let fallbackGetGate: Promise | null; + +beforeEach(() => { + clearClientResourceStoresForTests(); + previousGlobals = Object.fromEntries(globals.map(key => [key, Object.getOwnPropertyDescriptor(globalThis, key)])) as typeof previousGlobals; + testWindow = new Window({ url: "http://localhost/" }); + Object.defineProperty(testWindow.navigator, "language", { configurable: true, value: "en-US" }); + Object.defineProperties(globalThis, { + document: { configurable: true, value: testWindow.document }, + window: { configurable: true, value: testWindow }, + navigator: { configurable: true, value: testWindow.navigator }, + localStorage: { configurable: true, value: testWindow.localStorage }, + sessionStorage: { configurable: true, value: testWindow.sessionStorage }, + IS_REACT_ACT_ENVIRONMENT: { configurable: true, value: true }, + }); + + requests = []; + available = ["a-1", "a-2", "a-3"]; + chosen = ["a-1"]; + fallbackSettings = { models: ["a-2"], pollMs: 45_000 }; + failFallbackPut = false; + v2Settings = { enabled: true, multiAgentMode: "v2", multiAgentModeHintText: null, keepNativeChatGptOnV1: false }; + preferredModel = null; + fallbackGetGate = null; + Object.defineProperty(globalThis, "fetch", { + configurable: true, + value: async (input: RequestInfo | URL, init?: RequestInit) => { + const path = new URL(String(input), "http://localhost/").pathname; + const method = init?.method ?? "GET"; + requests.push({ path, method, init }); + // Match agent-settings-routes: fallback uses models, roster uses chosen/applied. + if (path === FALLBACK_PATH && method === "GET") { + if (fallbackGetGate) await fallbackGetGate; + return Response.json({ ...fallbackSettings, available }); + } + if (path === FALLBACK_PATH && method === "PUT") { + if (failFallbackPut) return Response.json({ error: "Fallback settings could not be persisted" }, { status: 500 }); + fallbackSettings = JSON.parse(String(init?.body)) as FallbackSettings; + return Response.json({ ok: true, ...fallbackSettings }); + } + if (path === ROSTER_PATH && method === "GET") return Response.json({ available, chosen }); + if (path === ROSTER_PATH && method === "PUT") { + chosen = (JSON.parse(String(init?.body)) as { models: string[] }).models; + return Response.json({ applied: chosen }); + } + if (path === "/api/v2" && method === "GET") { + return Response.json(v2Settings); + } + if (path === "/api/injection-model" && method === "GET") { + return Response.json({ + model: preferredModel, + effort: null, + available: [ + { provider: "openai", model: "gpt-5.4", namespaced: "gpt-5.4" }, + { provider: "anthropic", model: "claude-sonnet-4-6", namespaced: "anthropic/claude-sonnet-4-6" }, + ], + efforts: [], + }); + } + throw new Error(`Unexpected request: ${method} ${path}`); + }, + }); + container = testWindow.document.createElement("div") as unknown as HTMLElement; + testWindow.document.body.appendChild(container); +}); + +afterEach(async () => { + try { + if (root) { + const current = root; + await act(async () => { current.unmount(); }); + root = null; + } + } finally { + clearClientResourceStoresForTests(); + testWindow.close(); + for (const key of globals) { + const descriptor = previousGlobals[key]; + if (descriptor) Object.defineProperty(globalThis, key, descriptor); + else Reflect.deleteProperty(globalThis, key); + } + } +}); + +async function mount() { + // Match sibling input tests: initialize ReactDOM's event support after installing the DOM. + const { createRoot } = await import("react-dom/client"); + await act(async () => { + root = createRoot(container); + root.render(); + }); + expect(requests.some(request => request.path === FALLBACK_PATH && request.method === "GET")).toBe(true); + expect(editor()).toBeTruthy(); +} + +function editor(): HTMLElement { + const element = container.querySelector(".swi-fallback-editor"); + if (!element) throw new Error("Fallback editor not found"); + return element; +} + +function rows(): HTMLElement[] { + return Array.from(editor().querySelectorAll(".swi-fallback-row")); +} + +function expectOrder(models: string[]) { + expect(rows()).toHaveLength(models.length); + models.forEach((model, index) => { + // The model span can also contain the unavailable-model warning. + expect(rows()[index]?.querySelector("span")?.textContent?.trim().startsWith(`${index + 1}. ${model}`)).toBe(true); + expect(rowButton(index, "sub.removeAria", model)).toBeTruthy(); + }); +} + +function labelledButton(scope: ParentNode, label: string): HTMLButtonElement { + const button = Array.from(scope.querySelectorAll("button")) + .find(candidate => candidate.getAttribute("aria-label") === label); + if (!button) throw new Error(`Button not found: ${label}`); + return button; +} + +function rowButton(index: number, key: "sub.moveUp" | "sub.moveDown" | "sub.removeAria", model: string) { + const row = rows()[index]; + if (!row) throw new Error(`Fallback row not found: ${index}`); + return labelledButton(row, en[key].replace("{m}", model)); +} + +function saveButton(scope: ParentNode = editor()): HTMLButtonElement { + const button = Array.from(scope.querySelectorAll("button")) + .find(candidate => candidate.textContent?.trim() === en["common.save"]); + if (!button) throw new Error("Save button not found"); + return button; +} + +async function click(button: HTMLButtonElement) { + expect(button.disabled).toBe(false); + await act(async () => { button.click(); }); +} + +async function addFallback(model: string) { + const trigger = labelledButton(editor(), en["sub.fallbackAdd"]); + expect(trigger.getAttribute("role")).toBe("combobox"); + await click(trigger); + // Select portals its listbox into document.body, outside the page container. + const listbox = testWindow.document.getElementById(trigger.getAttribute("aria-controls") ?? ""); + if (!listbox) throw new Error("Fallback model listbox not found"); + const option = Array.from(listbox.querySelectorAll('[role="option"]')) + .find(candidate => candidate.textContent?.trim() === model); + if (!option) throw new Error(`Fallback option not found: ${model}`); + await click(option as unknown as HTMLButtonElement); + expect(trigger.getAttribute("aria-expanded")).toBe("false"); +} + +function pollInput(): HTMLInputElement { + const input = editor().querySelector('input[type="number"]'); + if (!input) throw new Error("Fallback polling interval input not found"); + return input; +} + +async function changePollMs(value: number) { + await act(async () => { + const input = pollInput(); + Object.getOwnPropertyDescriptor(testWindow.HTMLInputElement.prototype, "value")!.set!.call(input, String(value)); + input.dispatchEvent(new testWindow.Event("input", { bubbles: true })); + input.dispatchEvent(new testWindow.Event("change", { bubbles: true })); + }); +} + +function putBodies(path = FALLBACK_PATH): unknown[] { + return requests.filter(request => request.path === path && request.method === "PUT") + .map(request => JSON.parse(String(request.init?.body)) as unknown); +} + +function cached(): CachedSubagents | null { + return readSessionListCache(CACHE_KEY); +} + +test("preserves an unavailable configured fallback ID on load and save", async () => { + fallbackSettings = { models: [UNAVAILABLE_MODEL, "a-2"], pollMs: 45_000 }; + expect(available).not.toContain(UNAVAILABLE_MODEL); + await mount(); + + expectOrder([UNAVAILABLE_MODEL, "a-2"]); + expect(rows()[0]?.textContent).toContain(en["sub.fallbackUnavailable"]); + expect(rows()[1]?.textContent).not.toContain(en["sub.fallbackUnavailable"]); + expect(cached()?.fallback).toEqual([UNAVAILABLE_MODEL, "a-2"]); + await click(saveButton()); + expect(putBodies()).toEqual([{ models: [UNAVAILABLE_MODEL, "a-2"], pollMs: 45_000 }]); + expectOrder([UNAVAILABLE_MODEL, "a-2"]); + expect(container.textContent).toContain(en["sub.fallbackSaved"]); +}); + +test("adds, reorders in both directions, and removes fallback models before saving their exact order", async () => { + await mount(); + await addFallback("a-3"); + expectOrder(["a-2", "a-3"]); + expect(rowButton(0, "sub.moveUp", "a-2").disabled).toBe(true); + expect(rowButton(1, "sub.moveDown", "a-3").disabled).toBe(true); + + await click(rowButton(1, "sub.moveUp", "a-3")); + expectOrder(["a-3", "a-2"]); + await click(rowButton(0, "sub.moveDown", "a-3")); + expectOrder(["a-2", "a-3"]); + await addFallback("a-1"); + await click(rowButton(0, "sub.removeAria", "a-2")); + expectOrder(["a-3", "a-1"]); + expect(putBodies()).toEqual([]); + + await click(saveButton()); + expect(putBodies()).toEqual([{ models: ["a-3", "a-1"], pollMs: 45_000 }]); + expect(putBodies(ROSTER_PATH)).toEqual([]); +}); + +test("removes only the selected duplicate fallback occurrence by index", async () => { + fallbackSettings.models = ["a-2", "a-1", "a-2", "a-3"]; + await mount(); + expectOrder(["a-2", "a-1", "a-2", "a-3"]); + + await click(rowButton(2, "sub.removeAria", "a-2")); + expectOrder(["a-2", "a-1", "a-3"]); + await click(saveButton()); + expect(putBodies()).toEqual([{ models: ["a-2", "a-1", "a-3"], pollMs: 45_000 }]); +}); + +test("a failed fallback PUT retains the editable draft and leaves the committed cache unchanged", async () => { + await mount(); + const committed = cached(); + expect(committed).toEqual({ available, chosen: ["a-1"], fallback: ["a-2"], pollMs: 45_000 }); + await addFallback("a-3"); + await changePollMs(90_000); + failFallbackPut = true; + await click(saveButton()); + + expect(putBodies()).toEqual([{ models: ["a-2", "a-3"], pollMs: 90_000 }]); + expectOrder(["a-2", "a-3"]); + expect(pollInput().value).toBe("90000"); + expect(container.textContent).toContain("Fallback settings could not be persisted"); + expect(container.textContent).not.toContain(en["sub.fallbackSaved"]); + expect(saveButton().disabled).toBe(false); + expect(cached()).toEqual(committed); + + failFallbackPut = false; + await click(saveButton()); + expect(putBodies()).toEqual([ + { models: ["a-2", "a-3"], pollMs: 90_000 }, + { models: ["a-2", "a-3"], pollMs: 90_000 }, + ]); + expect(cached()?.fallback).toEqual(["a-2", "a-3"]); + expect(cached()?.pollMs).toBe(90_000); +}); + +test("a successful fallback save updates committed session data without committing a roster draft", async () => { + await mount(); + await click(labelledButton(container, en["sub.workspace.addToFeatured"].replace("{m}", "a-3"))); + await addFallback("a-3"); + await changePollMs(120_000); + await click(saveButton()); + + expect(putBodies()).toEqual([{ models: ["a-2", "a-3"], pollMs: 120_000 }]); + expect(putBodies(ROSTER_PATH)).toEqual([]); + expect(cached()).toEqual({ available, chosen: ["a-1"], fallback: ["a-2", "a-3"], pollMs: 120_000 }); + expectOrder(["a-2", "a-3"]); + expect(container.querySelectorAll(".swi-featured-row").length).toBe(2); +}); + +test("independent roster Save never caches an unsaved fallback draft", async () => { + await mount(); + await addFallback("a-3"); + await changePollMs(90_000); + await click(labelledButton(container, en["sub.workspace.addToFeatured"].replace("{m}", "a-3"))); + const rosterSaveRow = container.querySelector(".swi-save-row"); + if (!rosterSaveRow) throw new Error("Roster Save row not found"); + await click(saveButton(rosterSaveRow)); + + expect(putBodies(ROSTER_PATH)).toEqual([{ models: ["a-1", "a-3"] }]); + expect(putBodies()).toEqual([]); + expect(cached()).toEqual({ available, chosen: ["a-1", "a-3"], fallback: ["a-2"], pollMs: 45_000 }); + expectOrder(["a-2", "a-3"]); + expect(pollInput().value).toBe("90000"); + + // Saving the fallback afterward must retain the already committed roster. + await click(saveButton()); + expect(putBodies()).toEqual([{ models: ["a-2", "a-3"], pollMs: 90_000 }]); + expect(cached()).toEqual({ available, chosen: ["a-1", "a-3"], fallback: ["a-2", "a-3"], pollMs: 90_000 }); +}); + +test("remount shows the committed fallback and roster while a fresh fallback GET is pending", async () => { + await mount(); + await addFallback("a-3"); + await changePollMs(120_000); + await click(saveButton()); + + // A later roster save must not commit these newer fallback edits. + await click(rowButton(0, "sub.removeAria", "a-2")); + await changePollMs(90_000); + await click(labelledButton(container, en["sub.workspace.addToFeatured"].replace("{m}", "a-3"))); + const rosterSaveRow = container.querySelector(".swi-save-row"); + if (!rosterSaveRow) throw new Error("Roster Save row not found"); + await click(saveButton(rosterSaveRow)); + expectOrder(["a-3"]); + expect(pollInput().value).toBe("90000"); + + const current = root!; + await act(async () => { current.unmount(); }); + root = null; + // Keep sessionStorage, but discard the resource store so it cannot mask a stale session seed. + clearClientResourceStoresForTests(); + const getsBefore = requests.filter(request => request.path === FALLBACK_PATH && request.method === "GET").length; + let releaseGet!: () => void; + fallbackGetGate = new Promise(resolve => { releaseGet = resolve; }); + try { + await mount(); + expect(requests.filter(request => request.path === FALLBACK_PATH && request.method === "GET")).toHaveLength(getsBefore + 1); + // These assertions run before the fresh GET can return any data. + expectOrder(["a-2", "a-3"]); + expect(pollInput().value).toBe("120000"); + expect(Array.from(container.querySelectorAll(".swi-featured-name"), node => node.textContent?.trim())) + .toEqual(["a-1", "a-3"]); + expect(cached()).toEqual({ available, chosen: ["a-1", "a-3"], fallback: ["a-2", "a-3"], pollMs: 120_000 }); + } finally { + await act(async () => { releaseGet(); }); + fallbackGetGate = null; + } + expectOrder(["a-2", "a-3"]); + expect(pollInput().value).toBe("120000"); +}); + +test("invalid polling intervals disable Save without a PUT or cache mutation, and a valid interval recovers", async () => { + await mount(); + const committed = cached(); + for (const interval of [0, 4_999, 600_001, 5_000.5]) { + await changePollMs(interval); + expect(pollInput().getAttribute("aria-invalid")).toBe("true"); + expect(editor().querySelector('[role="alert"]')?.textContent).toContain(en["sub.fallbackPollInvalid"]); + expect(saveButton().disabled).toBe(true); + await act(async () => { saveButton().click(); }); + expect(putBodies()).toEqual([]); + expect(cached()).toEqual(committed); + } + + await changePollMs(5_000); + expect(pollInput().getAttribute("aria-invalid")).toBe("false"); + expect(editor().querySelector('[role="alert"]')).toBeNull(); + await click(saveButton()); + expect(putBodies()).toEqual([{ models: ["a-2"], pollMs: 5_000 }]); + expect(cached()?.pollMs).toBe(5_000); +}); + +const compatibilityCases: Array<{ + name: string; + model: string; + enabled: boolean; + mode: V2Settings["multiAgentMode"]; + keepNative: boolean; + warning: boolean; +}> = [ + { name: "native preferred model", model: "gpt-5.4", enabled: true, mode: "v2", keepNative: false, warning: false }, + { name: "routed preferred model on the default surface", model: "anthropic/claude-sonnet-4-6", enabled: false, mode: "default", keepNative: false, warning: true }, + { name: "routed preferred model on V1", model: "anthropic/claude-sonnet-4-6", enabled: false, mode: "v1", keepNative: false, warning: false }, + { name: "forced V2 preserving native V1 with global V2 disabled", model: "anthropic/claude-sonnet-4-6", enabled: false, mode: "v2", keepNative: true, warning: false }, + { name: "global V2 enabled despite native V1 preservation", model: "anthropic/claude-sonnet-4-6", enabled: true, mode: "v2", keepNative: true, warning: true }, +]; + +test.each(compatibilityCases)("V2 compatibility guidance: $name", async ({ model, enabled, mode, keepNative, warning }) => { + preferredModel = model; + v2Settings = { enabled, multiAgentMode: mode, multiAgentModeHintText: null, keepNativeChatGptOnV1: keepNative }; + await mount(); + + const note = container.querySelector('.swi-v2-compatibility[role="note"]'); + if (warning) { + expect(note).toBeTruthy(); + expect(note?.textContent).toContain(en["sub.v2Compatibility.title"]); + expect(note?.textContent).toContain(en["sub.v2Compatibility.risk"]); + // The response exposes no recovery state: guidance must explicitly say it is unknown. + expect(note?.textContent).toContain(en["sub.v2Compatibility.recoveryUnknown"]); + expect(note?.querySelector("a")?.getAttribute("href")).toBe("https://github.com/lidge-jun/opencodex/issues/92"); + expect(note?.querySelector('[role="switch"], [aria-pressed], input[type="checkbox"]')).toBeNull(); + } else { + expect(note).toBeNull(); + expect(container.textContent).not.toContain(en["sub.v2Compatibility.recoveryUnknown"]); + } + expect(requests.filter(request => request.method !== "GET")).toEqual([]); +}); From ffcd7abbaa210fad6ab235047d190248c5d6d52d Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 18:36:13 +0900 Subject: [PATCH 8/9] fix(gui): guard fallback hydration races and preserve row focus [skip ci] Co-authored-by: x3M3x <98298256+x3M3x@users.noreply.github.com> --- .../SubagentDelegationSection.tsx | 40 ++++- gui/src/pages/Subagents.tsx | 42 +++-- gui/tests/subagents-fallback.test.tsx | 151 +++++++++++++++++- 3 files changed, 214 insertions(+), 19 deletions(-) diff --git a/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx b/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx index dbbbd99948..6fe043461c 100644 --- a/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx +++ b/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx @@ -6,7 +6,7 @@ * better next to the roster it affects: the roster picks who may be called, this picks who * gets called first. */ -import { useState } from "react"; +import { useLayoutEffect, useRef, useState } from "react"; import { Select, Tooltip } from "../../ui"; import { IconArrowDown, IconArrowUp, IconInfo, IconX } from "../../icons"; import { useT, type TKey } from "../../i18n/shared"; @@ -63,12 +63,36 @@ export default function SubagentDelegationSection({ const nativeMayUseV2 = ultraMode.enabled || (ultraMode.multiAgentMode !== "v1" && !(ultraMode.multiAgentMode === "v2" && ultraMode.keepNativeChatGptOnV1)); const showV2Compatibility = !ultraLoadFailed && ultraMode.loaded === true && routedPreferred && nativeMayUseV2; + const fallbackControlsRef = useRef(null); + const nextRowId = useRef(0); + const rowIdentity = useRef>([]); + // Reuse each configured occurrence across reorder; duplicates have distinct IDs. + if (rowIdentity.current.length !== fallback.length || rowIdentity.current.some((row, i) => row.model !== fallback[i])) { + const remaining = [...rowIdentity.current]; + rowIdentity.current = fallback.map(modelName => { + const old = remaining.findIndex(row => row.model === modelName); + return old >= 0 ? remaining.splice(old, 1)[0] : { model: modelName, id: nextRowId.current++ }; + }); + } + const pendingFocus = useRef<{ row: number; action: string } | null>(null); + useLayoutEffect(() => { + const target = pendingFocus.current; + if (!target) return; + pendingFocus.current = null; + const row = fallbackControlsRef.current?.querySelectorAll(".swi-fallback-row")[target.row]; + const action = row?.querySelector(`button[data-action="${target.action}"]:not(:disabled)`) + ?? row?.querySelector("button:not(:disabled)") + ?? fallbackControlsRef.current?.querySelector('button[role="combobox"]'); + action?.focus(); + }, [fallback]); const validPollMs = Number.isInteger(fallbackPollMs) && fallbackPollMs >= 5000 && fallbackPollMs <= 600000; const moveFallback = (index: number, direction: -1 | 1) => { const next = [...fallback]; const target = index + direction; if (fallbackBusy || target < 0 || target >= next.length) return; [next[index], next[target]] = [next[target], next[index]]; + [rowIdentity.current[index], rowIdentity.current[target]] = [rowIdentity.current[target], rowIdentity.current[index]]; + pendingFocus.current = { row: target, action: direction === -1 ? "up" : "down" }; onFallbackChange(next); }; @@ -134,16 +158,20 @@ export default function SubagentDelegationSection({
{t("sub.fallbackLabel")}
{t("sub.fallbackHint")}
-
+
{fallback.map((modelName, index) => ( -
+
{index + 1}. {modelName} {!availableModels.includes(modelName) && {t("sub.fallbackUnavailable")}} - - - + + +
))} diff --git a/gui/src/pages/Subagents.tsx b/gui/src/pages/Subagents.tsx index cbdb138e33..cf9f1b33d0 100644 --- a/gui/src/pages/Subagents.tsx +++ b/gui/src/pages/Subagents.tsx @@ -8,7 +8,7 @@ import { useDataSurface } from "../data-surface"; import { DataSurfaceSkeleton } from "../components/data-surface"; import { useSubagentDelegation, type UltraModePatch, type UltraModeState } from "./use-subagent-delegation"; -type CachedSubagents = { available: string[]; chosen: string[]; fallback: string[]; pollMs: number }; +type CachedSubagents = { available: string[]; chosen: string[]; fallback?: string[]; pollMs?: number }; function seedSubagents(cacheKey: string): CachedSubagents | null { return readSessionListCache(cacheKey); @@ -22,6 +22,9 @@ export default function Subagents({ apiBase }: { apiBase: string }) { const [fallback, setFallback] = useState(() => cached?.fallback ?? []); const [fallbackPollMs, setFallbackPollMs] = useState(() => cached?.pollMs ?? 60000); const [fallbackBusy, setFallbackBusy] = useState(false); + const [fallbackLoaded, setFallbackLoaded] = useState(() => Array.isArray(cached?.fallback) && Number.isInteger(cached?.pollMs)); + const fallbackRevision = useRef(0); + const rosterRevision = useRef(0); const fallbackSaveInFlight = useRef(false); const committed = useRef(cached); const [status, setStatus] = useState(""); @@ -125,6 +128,8 @@ export default function Subagents({ apiBase }: { apiBase: string }) { const loadSubagents = useCallback(async (signal?: AbortSignal): Promise => { // The resource layer's deadline abort must reach the wire — a signal dropped // here is a store that can only settle by race timeout. + const rosterReadRevision = rosterRevision.current; + const fallbackReadRevision = fallbackRevision.current; const [rosterRes, fallbackRes] = await Promise.all([ fetch(`${apiBase}/api/subagent-models`, { signal }), fetch(`${apiBase}/api/subagent-model-fallback`, { signal }), @@ -134,18 +139,23 @@ export default function Subagents({ apiBase }: { apiBase: string }) { if (!response || !fallbackResponse) throw new Error(t("sub.loadFail")); const available = response.available ?? fallbackResponse.available ?? []; const availableSet = new Set(available); + const rosterCurrent = rosterReadRevision === rosterRevision.current && !saveInFlight.current; + const fallbackCurrent = fallbackReadRevision === fallbackRevision.current && !fallbackSaveInFlight.current; const next = { available, - chosen: (response.chosen ?? []).filter(model => availableSet.has(model)), + chosen: rosterCurrent ? (response.chosen ?? []).filter(model => availableSet.has(model)) : committed.current?.chosen ?? [], // Configured targets remain editable even when discovery no longer advertises them. - fallback: fallbackResponse.models ?? [], - pollMs: fallbackResponse.pollMs ?? 60000, + fallback: fallbackCurrent ? fallbackResponse.models ?? [] : committed.current?.fallback ?? [], + pollMs: fallbackCurrent ? fallbackResponse.pollMs ?? 60000 : committed.current?.pollMs ?? 60000, }; if (signal?.aborted) throw signal.reason; committed.current = next; - setChosen(next.chosen); - setFallback(next.fallback); - setFallbackPollMs(next.pollMs); + if (rosterCurrent) setChosen(next.chosen); + if (fallbackCurrent) { + setFallback(next.fallback); + setFallbackPollMs(next.pollMs); + setFallbackLoaded(true); + } writeSessionListCache(cacheKey, next); return next; }, [apiBase, cacheKey, t]); @@ -166,10 +176,12 @@ export default function Subagents({ apiBase }: { apiBase: string }) { const toggle = (m: string) => { if (busy) return; setStatus(""); + rosterRevision.current += 1; setChosen(prev => prev.includes(m) ? prev.filter(x => x !== m) : (prev.length >= FEATURED_MAX ? prev : [...prev, m])); }; const move = (i: number, dir: -1 | 1) => { if (busy) return; + rosterRevision.current += 1; setChosen(prev => { const next = [...prev]; const j = i + dir; @@ -182,6 +194,7 @@ export default function Subagents({ apiBase }: { apiBase: string }) { const save = async () => { if (busy || saveInFlight.current) return; saveInFlight.current = true; + rosterRevision.current += 1; setBusy(true); setStatus(""); try { @@ -191,9 +204,11 @@ export default function Subagents({ apiBase }: { apiBase: string }) { body: JSON.stringify({ models: chosen }), }); const d = await readJsonOrThrow<{ applied?: string[] }>(r, t("sub.saveFailed")); + rosterRevision.current += 1; const applied = d?.applied ?? chosen; if (d?.applied) setChosen(d.applied); - const next = { available, chosen: applied, fallback: committed.current?.fallback ?? [], pollMs: committed.current?.pollMs ?? 60000 }; + // A legacy roster-only seed does not prove that an empty fallback was loaded. + const next = { ...committed.current, available, chosen: applied }; committed.current = next; writeSessionListCache(cacheKey, next); setOk(true); @@ -208,8 +223,9 @@ export default function Subagents({ apiBase }: { apiBase: string }) { }; const saveFallback = async () => { - if (fallbackSaveInFlight.current || !Number.isInteger(fallbackPollMs) || fallbackPollMs < 5000 || fallbackPollMs > 600000) return; + if (!fallbackLoaded || fallbackSaveInFlight.current || !Number.isInteger(fallbackPollMs) || fallbackPollMs < 5000 || fallbackPollMs > 600000) return; fallbackSaveInFlight.current = true; + fallbackRevision.current += 1; const requestApiBase = apiBase; setFallbackBusy(true); setStatus(""); @@ -222,6 +238,7 @@ export default function Subagents({ apiBase }: { apiBase: string }) { const d = await readJsonOrThrow<{ models?: string[]; pollMs?: number }>(r, t("sub.fallbackSaveFailed")); if (currentUltraApiBase.current !== requestApiBase) return; if (!d || !Array.isArray(d.models) || typeof d.pollMs !== "number") throw new Error(t("sub.fallbackSaveFailed")); + fallbackRevision.current += 1; setFallback(d.models); setFallbackPollMs(d.pollMs); const next = { available, chosen: committed.current?.chosen ?? [], fallback: d.models, pollMs: d.pollMs }; @@ -260,6 +277,7 @@ export default function Subagents({ apiBase }: { apiBase: string }) {
{status && {status}} {state.showError && {t("sub.loadFail")}} + {!fallbackLoaded && state.showError && } { void save(); }} fallback={fallback} fallbackPollMs={fallbackPollMs} - fallbackBusy={fallbackBusy} - onFallbackChange={setFallback} - onFallbackPollMsChange={setFallbackPollMs} + fallbackBusy={fallbackBusy || !fallbackLoaded} + onFallbackChange={models => { fallbackRevision.current += 1; setFallback(models); }} + onFallbackPollMsChange={pollMs => { fallbackRevision.current += 1; setFallbackPollMs(pollMs); }} onFallbackSave={() => { void saveFallback(); }} delegation={{ model: delegation.model, diff --git a/gui/tests/subagents-fallback.test.tsx b/gui/tests/subagents-fallback.test.tsx index 20badc4980..ad794b8261 100644 --- a/gui/tests/subagents-fallback.test.tsx +++ b/gui/tests/subagents-fallback.test.tsx @@ -16,7 +16,7 @@ const globals = [ "document", "window", "navigator", "localStorage", "sessionStorage", "fetch", "IS_REACT_ACT_ENVIRONMENT", ] as const; -type CachedSubagents = { available: string[]; chosen: string[]; fallback: string[]; pollMs: number }; +type CachedSubagents = { available: string[]; chosen: string[]; fallback?: string[]; pollMs?: number }; type FallbackSettings = { models: string[]; pollMs: number }; type SentRequest = { path: string; method: string; init?: RequestInit }; type V2Settings = { @@ -38,6 +38,7 @@ let failFallbackPut: boolean; let v2Settings: V2Settings; let preferredModel: string | null; let fallbackGetGate: Promise | null; +let pendingFallbackResponse: Promise | null; beforeEach(() => { clearClientResourceStoresForTests(); @@ -61,6 +62,7 @@ beforeEach(() => { v2Settings = { enabled: true, multiAgentMode: "v2", multiAgentModeHintText: null, keepNativeChatGptOnV1: false }; preferredModel = null; fallbackGetGate = null; + pendingFallbackResponse = null; Object.defineProperty(globalThis, "fetch", { configurable: true, value: async (input: RequestInfo | URL, init?: RequestInit) => { @@ -69,6 +71,11 @@ beforeEach(() => { requests.push({ path, method, init }); // Match agent-settings-routes: fallback uses models, roster uses chosen/applied. if (path === FALLBACK_PATH && method === "GET") { + if (pendingFallbackResponse) { + const pending = pendingFallbackResponse; + pendingFallbackResponse = null; + return pending; + } if (fallbackGetGate) await fallbackGetGate; return Response.json({ ...fallbackSettings, available }); } @@ -250,6 +257,51 @@ test("adds, reorders in both directions, and removes fallback models before savi expect(putBodies(ROSTER_PATH)).toEqual([]); }); +test("keyboard moves retain row focus and removal moves focus to the next row or add control", async () => { + fallbackSettings.models = ["a-1", "a-2", "a-3"]; + await mount(); + + const activateWithEnter = async (button: HTMLButtonElement) => { + expect(button.disabled).toBe(false); + await act(async () => { + button.focus(); + expect(testWindow.document.activeElement).toBe(button); + button.dispatchEvent(new testWindow.KeyboardEvent("keydown", { key: "Enter", code: "Enter", bubbles: true })); + // happy-dom does not synthesize native button activation from Enter. Supply the + // keyboard-generated click (detail 0) explicitly; this test covers focus restoration. + button.dispatchEvent(new testWindow.MouseEvent("click", { bubbles: true, detail: 0 })); + button.dispatchEvent(new testWindow.KeyboardEvent("keyup", { key: "Enter", code: "Enter", bubbles: true })); + }); + }; + + const middleRow = rows()[1]; + await activateWithEnter(rowButton(1, "sub.moveDown", "a-2")); + expectOrder(["a-1", "a-3", "a-2"]); + expect(rows()[2]).toBe(middleRow); + expect(rowButton(2, "sub.moveDown", "a-2").disabled).toBe(true); + // The requested direction is disabled at the boundary; focus an enabled action + // in the moved row, rather than the neighboring row or document.body. + expect(testWindow.document.activeElement).toBe(rowButton(2, "sub.moveUp", "a-2")); + + await activateWithEnter(rowButton(2, "sub.moveUp", "a-2")); + expectOrder(["a-1", "a-2", "a-3"]); + expect(rows()[1]).toBe(middleRow); + expect(testWindow.document.activeElement).toBe(rowButton(1, "sub.moveUp", "a-2")); + + await activateWithEnter(rowButton(1, "sub.removeAria", "a-2")); + expectOrder(["a-1", "a-3"]); + expect(testWindow.document.activeElement).toBe(rowButton(1, "sub.removeAria", "a-3")); + + await activateWithEnter(rowButton(1, "sub.removeAria", "a-3")); + expectOrder(["a-1"]); + expect(testWindow.document.activeElement).toBe(rowButton(0, "sub.removeAria", "a-1")); + + await activateWithEnter(rowButton(0, "sub.removeAria", "a-1")); + expectOrder([]); + expect(testWindow.document.activeElement).toBe(labelledButton(editor(), en["sub.fallbackAdd"])); + expect(putBodies()).toEqual([]); +}); + test("removes only the selected duplicate fallback occurrence by index", async () => { fallbackSettings.models = ["a-2", "a-1", "a-2", "a-3"]; await mount(); @@ -364,6 +416,103 @@ test("remount shows the committed fallback and roster while a fresh fallback GET expect(pollInput().value).toBe("120000"); }); +test("a legacy cache keeps fallback disabled through GET failure, roster Save, and remount", async () => { + const legacyCache = { available, chosen: ["a-1"] }; + testWindow.sessionStorage.setItem(CACHE_KEY, JSON.stringify(legacyCache)); + let releaseGet!: (response: Response) => void; + pendingFallbackResponse = new Promise(resolve => { releaseGet = resolve; }); + + const assertBlocked = async (expectedCache = legacyCache) => { + expect(labelledButton(editor(), en["sub.fallbackAdd"]).disabled).toBe(true); + expect(pollInput().disabled).toBe(true); + expect(saveButton().disabled).toBe(true); + expect(Array.from(editor().querySelectorAll("input, button")) + .every(control => control.disabled)).toBe(true); + await act(async () => { saveButton().click(); }); + expect(putBodies()).toEqual([]); + expect(cached()).toEqual(expectedCache); + expect(cached()).not.toHaveProperty("fallback"); + expect(cached()).not.toHaveProperty("pollMs"); + // A failed read must never turn the page's empty placeholder into a saved empty chain. + expect(fallbackSettings).toEqual({ models: ["a-2"], pollMs: 45_000 }); + }; + + try { + await mount(); + expect(rows()).toHaveLength(0); + expect(pendingFallbackResponse).toBeNull(); + await assertBlocked(); + } finally { + await act(async () => { + releaseGet(Response.json({ error: "Fallback discovery failed" }, { status: 503 })); + }); + } + expect(container.textContent).toContain(en["sub.loadFail"]); + await assertBlocked(); + + await click(labelledButton(container, en["sub.workspace.addToFeatured"].replace("{m}", "a-3"))); + const rosterSaveRow = container.querySelector(".swi-save-row"); + if (!rosterSaveRow) throw new Error("Roster Save row not found"); + await click(saveButton(rosterSaveRow)); + const savedRosterCache = { available, chosen: ["a-1", "a-3"] }; + expect(putBodies(ROSTER_PATH)).toEqual([{ models: ["a-1", "a-3"] }]); + await assertBlocked(savedRosterCache); + + const current = root!; + await act(async () => { current.unmount(); }); + root = null; + clearClientResourceStoresForTests(); + const getsBefore = requests.filter(request => request.path === FALLBACK_PATH && request.method === "GET").length; + pendingFallbackResponse = new Promise(resolve => { releaseGet = resolve; }); + try { + await mount(); + expect(requests.filter(request => request.path === FALLBACK_PATH && request.method === "GET")).toHaveLength(getsBefore + 1); + expect(pendingFallbackResponse).toBeNull(); + await assertBlocked(savedRosterCache); + } finally { + await act(async () => { + releaseGet(Response.json({ error: "Fallback discovery still unavailable" }, { status: 503 })); + }); + } + expect(container.textContent).toContain(en["sub.loadFail"]); + await assertBlocked(savedRosterCache); + expect(putBodies(ROSTER_PATH)).toEqual([{ models: ["a-1", "a-3"] }]); +}); + +test.each([false, true])("a captured old fallback GET cannot overwrite a newer draft or save (saved=%s)", async (saveNewer) => { + const committedA = { available, chosen: ["a-1"], fallback: ["a-2"], pollMs: 45_000 }; + testWindow.sessionStorage.setItem(CACHE_KEY, JSON.stringify(committedA)); + // Serialize A before any edit or PUT. Reading mutable fallbackSettings after the gate + // would accidentally return B and let the stale-response regression pass. + const capturedOldResponse = Response.json({ models: ["a-2"], pollMs: 45_000, available }); + let releaseGet!: (response: Response) => void; + pendingFallbackResponse = new Promise(resolve => { releaseGet = resolve; }); + const committedB = { available, chosen: ["a-1"], fallback: ["a-3"], pollMs: 90_000 }; + + try { + await mount(); + expect(pendingFallbackResponse).toBeNull(); + expectOrder(["a-2"]); + await addFallback("a-3"); + await click(rowButton(0, "sub.removeAria", "a-2")); + await changePollMs(90_000); + if (saveNewer) await click(saveButton()); + expectOrder(["a-3"]); + expect(pollInput().value).toBe("90000"); + expect(cached()).toEqual(saveNewer ? committedB : committedA); + } finally { + await act(async () => { releaseGet(capturedOldResponse); }); + } + + // The delayed GET has now settled; both UI fields and the committed session seed + // must retain their respective newer-draft / newer-save semantics. + expect(capturedOldResponse.bodyUsed).toBe(true); + expectOrder(["a-3"]); + expect(pollInput().value).toBe("90000"); + expect(cached()).toEqual(saveNewer ? committedB : committedA); + expect(putBodies()).toEqual(saveNewer ? [{ models: ["a-3"], pollMs: 90_000 }] : []); +}); + test("invalid polling intervals disable Save without a PUT or cache mutation, and a valid interval recovers", async () => { await mount(); const committed = cached(); From f1b8f2d2f1edee55b68202469f86a5334710688d Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 19:07:57 +0900 Subject: [PATCH 9/9] fix(gui): keep fallback render identities in state [skip ci] CI 34106956362 gates101697798420: remove render-time ref access and dynamic selector construction while preserving occurrence identity and keyboard focus. Co-authored-by: x3M3x <98298256+x3M3x@users.noreply.github.com> --- .../SubagentDelegationSection.tsx | 35 ++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx b/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx index 6fe043461c..a1b405c2d9 100644 --- a/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx +++ b/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx @@ -64,15 +64,22 @@ export default function SubagentDelegationSection({ && !(ultraMode.multiAgentMode === "v2" && ultraMode.keepNativeChatGptOnV1)); const showV2Compatibility = !ultraLoadFailed && ultraMode.loaded === true && routedPreferred && nativeMayUseV2; const fallbackControlsRef = useRef(null); - const nextRowId = useRef(0); - const rowIdentity = useRef>([]); - // Reuse each configured occurrence across reorder; duplicates have distinct IDs. - if (rowIdentity.current.length !== fallback.length || rowIdentity.current.some((row, i) => row.model !== fallback[i])) { - const remaining = [...rowIdentity.current]; - rowIdentity.current = fallback.map(modelName => { + const [identity, setIdentity] = useState(() => ({ + models: fallback, + rows: fallback.map((rowModel, id) => ({ model: rowModel, id })), + nextId: fallback.length, + })); + let rows = identity.rows; + // Keys are render state. Guarded prop reconciliation retains each occurrence; + // event handlers move the same identities with their corresponding models. + if (identity.models !== fallback) { + const remaining = [...identity.rows]; + let nextId = identity.nextId; + rows = fallback.map(modelName => { const old = remaining.findIndex(row => row.model === modelName); - return old >= 0 ? remaining.splice(old, 1)[0] : { model: modelName, id: nextRowId.current++ }; + return old >= 0 ? remaining.splice(old, 1)[0] : { model: modelName, id: nextId++ }; }); + setIdentity({ models: fallback, rows, nextId }); } const pendingFocus = useRef<{ row: number; action: string } | null>(null); useLayoutEffect(() => { @@ -80,7 +87,8 @@ export default function SubagentDelegationSection({ if (!target) return; pendingFocus.current = null; const row = fallbackControlsRef.current?.querySelectorAll(".swi-fallback-row")[target.row]; - const action = row?.querySelector(`button[data-action="${target.action}"]:not(:disabled)`) + const enabledActions = row?.querySelectorAll("button[data-action]:not(:disabled)"); + const action = Array.from(enabledActions ?? []).find(button => button.dataset.action === target.action) ?? row?.querySelector("button:not(:disabled)") ?? fallbackControlsRef.current?.querySelector('button[role="combobox"]'); action?.focus(); @@ -91,7 +99,9 @@ export default function SubagentDelegationSection({ const target = index + direction; if (fallbackBusy || target < 0 || target >= next.length) return; [next[index], next[target]] = [next[target], next[index]]; - [rowIdentity.current[index], rowIdentity.current[target]] = [rowIdentity.current[target], rowIdentity.current[index]]; + const nextRows = [...rows]; + [nextRows[index], nextRows[target]] = [nextRows[target], nextRows[index]]; + setIdentity({ ...identity, models: next, rows: nextRows }); pendingFocus.current = { row: target, action: direction === -1 ? "up" : "down" }; onFallbackChange(next); }; @@ -160,7 +170,7 @@ export default function SubagentDelegationSection({
{fallback.map((modelName, index) => ( -
+
{index + 1}. {modelName} {!availableModels.includes(modelName) && {t("sub.fallbackUnavailable")}} @@ -168,9 +178,10 @@ export default function SubagentDelegationSection({