diff --git a/docs-site/src/content/docs/fr/guides/sub-agent-surface.md b/docs-site/src/content/docs/fr/guides/sub-agent-surface.md index 4fb0ece971..87c11ebcec 100644 --- a/docs-site/src/content/docs/fr/guides/sub-agent-surface.md +++ b/docs-site/src/content/docs/fr/guides/sub-agent-surface.md @@ -5,9 +5,9 @@ description: Contrôlez la manière dont Codex génère et gère les sous-agents ## Que sont les sous-agents -Un sous-agent est un travailleur Codex distinct que l'agent principal peut créer pour une tâche ciblée. Il a son -son propre contexte et ses propres outils, afin que plusieurs tâches indépendantes puissent s'exécuter en parallèle. opencodex contrôle lequel -La surface de collaboration Codex expose ces travailleurs, quels modèles Codex leur propose et comment un +Un sous-agent est un travailleur Codex distinct que l'agent principal peut créer pour une tâche ciblée. Il possède +son propre contexte et ses propres outils, afin que plusieurs tâches indépendantes puissent s'exécuter en parallèle. opencodex contrôle +quelle surface de collaboration Codex expose ces travailleurs, quels modèles Codex leur propose et comment un modèle défaillant peut reculer. Il ne décide pas quand votre agent principal doit déléguer. ## Modes @@ -20,6 +20,12 @@ Choisissez le mode pour les **nouvelles sessions**. Les sessions existantes cons | **base** (par défaut) | Paramètres de modèle en amont : GPT-5.6 Sol/Terra utilisent la v2, Luna utilise la v1, et les modèles non définis explicitement suivent l’indicateur de fonctionnalité `multi_agent_v2` de Codex. | La plupart des utilisateurs. Ce mode respecte la surface prévue par Codex pour chaque modèle, sans en imposer une globalement. | | **v2** | Outils plats `spawn_agent`, `send_message`, `followup_task`, `interrupt_agent` et liste d'agents, avec sessions simultanées. | Utilisateurs souhaitant utiliser le flux de travail simultané le plus récent et comprenant l'héritage de modèle et la limitation des tâches chiffrées ci-dessous. | +En **v2**, l'option facultative **Garder ChatGPT sur v1** (`keepNativeChatGptOnV1`) laisse Sol/Terra +sur la surface v1 afin qu'ils puissent encore lancer Grok ou Claude. Les parents natifs ChatGPT +chiffrent les corps `NEW_TASK` v2 ; les modèles routés ne peuvent pas les lire. Les parents routés +restent sur v2, où les tâches enfants sont en texte clair. C'est un interrupteur *à l'intérieur* +de v2, pas un quatrième mode de catalogue. CLI : `ocx v2 mode v2` puis `ocx v2 keep-native-v1 on`. + :::tip[Pas sûr ?] Commencez par **base**. Choisissez **v1** lorsque la délégation entre fournisseurs doit fonctionner de manière prévisible. Forcer **v2** uniquement lorsque vous souhaitez spécifiquement son modèle de session le plus récent dans chaque entrée de catalogue. @@ -31,7 +37,7 @@ Le mode sélectionné contrôle le champ `multi_agent_version` dans chaque entr - **v1** inscrit `multi_agent_version = "v1"` sur chaque modèle. - **base** restaure les paramètres en amont. Les entrées sans valeur explicite suivent l’indicateur de fonctionnalité natif `multi_agent_v2`. -- **v2** inscrit `multi_agent_version = "v2"` sur chaque modèle. +- **v2** inscrit `multi_agent_version = "v2"` sur chaque modèle, sauf lorsque **Garder ChatGPT sur v1** est activé : les lignes natives ChatGPT restent `"v1"` et les lignes routées ou combo restent `"v2"`. opencodex applique cela comme passe finale à la fois au catalogue `/v1/models` en direct et au catalogue synchronisé sur le disque. C'est pourquoi un changement de mode affecte de manière cohérente les sessions App, CLI et TUI nouvellement créées. @@ -115,9 +121,9 @@ apparaît plus tôt dans la chaîne. ## Livraison de tâches v2 cryptées -Codex peut envoyer une tâche enfant v2 native vers routé uniquement sous forme `encrypted_content` chiffrée par le backend. Cela -la charge utile peut être lue par le backend natif ChatGPT, mais pas par un fournisseur externe. C'est le -connue [#92 limitation](https://github.com/lidge-jun/opencodex/issues/92). +Codex peut envoyer une tâche enfant v2 native vers routé uniquement sous forme `encrypted_content` chiffrée par le backend. Cette +charge utile peut être lue par le backend natif ChatGPT, mais pas par un fournisseur externe. C'est la +limitation connue [#92](https://github.com/lidge-jun/opencodex/issues/92). opencodex échoue en toute sécurité au lieu de transférer une tâche vide ou illisible : @@ -157,6 +163,7 @@ canoniques pour les tâches chiffrées. - **Tableau de bord** → première cellule statistique : choisissez **v1**, **base** ou **v2**. - **Modèles** → contrôle segmenté de la rangée supérieure : choisissez le même mode global. +- **Modèles** → **Garder ChatGPT sur v1** : activez cette option uniquement lorsque le mode global est **v2**. Elle est ignorée en **v1** et **base**. - **Tableau de bord** → **Délégation de sous-agent** : définissez les conseils model/effort et l'activation explicite natif par défaut. - **Sous-agents** : choisissez et ordonnez la liste, puis configurez la chaîne de repli globale. @@ -169,6 +176,8 @@ ocx v2 status ocx v2 mode v1 ocx v2 mode default ocx v2 mode v2 +ocx v2 keep-native-v1 on +ocx v2 keep-native-v1 off ocx v2 threads 8 ``` diff --git a/docs-site/src/content/docs/fr/reference/configuration/agents.md b/docs-site/src/content/docs/fr/reference/configuration/agents.md index 9422d72761..37e1f2111d 100644 --- a/docs-site/src/content/docs/fr/reference/configuration/agents.md +++ b/docs-site/src/content/docs/fr/reference/configuration/agents.md @@ -10,6 +10,7 @@ Les paramètres des agents déterminent la surface de collaboration Codex annonc | Champ | Type | Valeur par défaut | Signification | | --- | --- | --- | --- | | `multiAgentMode?` | `"v1" \| "default" \| "v2"` | `"default"` | `v1` marque tous les modèles du catalogue comme compatibles v1 ; `v2` les marque tous comme compatibles v2. `default` rétablit les choix imposés en amont (Sol/Terra en v2, Luna en v1) et suit sinon l’indicateur natif `multi_agent_v2`. S’applique aux nouvelles sessions. | +| `keepNativeChatGptOnV1?` | `boolean` | `false` | Lorsque `multiAgentMode` vaut `"v2"`, marque les lignes natives ChatGPT (Sol/Terra et les autres modèles du backend ChatGPT) comme v1. Les parents routés restent en v2. Utilisez cette option pour qu'un parent ChatGPT puisse encore lancer Grok ou Claude — les tâches enfants v2 natives sont chiffrées par le service en amont ([#92](https://github.com/lidge-jun/opencodex/issues/92)). Ignoré en `v1` et `default`. | | `subagentModels?` | `string[]` | `gpt-5.5`, `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-5.6-luna`, `gpt-5.4-mini` | Jusqu’à cinq identifiants de modèles natifs non qualifiés, qualifiés par un compte sous la forme `/`, ou routés sous la forme `provider/model`, affichés en tête du sélecteur de sous-agents. Le tableau de bord ne propose que les identifiants natifs non qualifiés et les identifiants routés ; lors de l’enregistrement, il omet les choix exacts qualifiés par un compte. Pour les définir, utilisez `ocx agent subagents set` ou modifiez la configuration. Une liste explicitement vide est conservée. | | `injectionModel?` | `string` | — | Modèle de sous-agent natif ou routé privilégié dans les consignes de délégation v2 produites par le proxy. | | `injectionEffort?` | `string` | — | Niveau d’effort privilégié (de `low` à `ultra`), pertinent uniquement avec `injectionModel`. | @@ -23,7 +24,7 @@ Les paramètres des agents déterminent la surface de collaboration Codex annonc | `subagentEffortCap?` | `string` | — | Plafond supplémentaire réservé aux tours enfants créés. Lorsque les deux plafonds s’appliquent, le plus bas l’emporte. | | `agentTaskRecovery?` | `object` | — | Mécanisme expérimental, soumis à activation explicite, pour récupérer les tâches v2 chiffrées par le service en amont lorsqu’elles sont envoyées à des fournisseurs routés. Désactivé sauf si `enabled: true` ; voir [Récupération des tâches v2 chiffrées](#récupération-des-tâches-v2-chiffrées). | -Gérez la surface depuis le tableau de bord ou avec `ocx v2 status|on|off|mode |threads |mode-hint `. Les changements de mode s’appliquent aux nouvelles sessions. `maxConcurrentThreadsPerSession` est un champ de `PUT /api/v2`, et non une clé de `config.json`. Après l’activation de v2, `ocx v2 threads ` écrit `max_concurrent_threads_per_session` sous `[features.multi_agent_v2]` dans le fichier `$CODEX_HOME/config.toml` de Codex. +Gérez la surface depuis le tableau de bord ou avec `ocx v2 status|on|off|mode |keep-native-v1 |threads |mode-hint `. Les changements de mode s’appliquent aux nouvelles sessions. `maxConcurrentThreadsPerSession` est un champ de `PUT /api/v2`, et non une clé de `config.json`. Après l’activation de v2, `ocx v2 threads ` écrit `max_concurrent_threads_per_session` sous `[features.multi_agent_v2]` dans le fichier `$CODEX_HOME/config.toml` de Codex. Le **mode Ultra** — accessible depuis l’interrupteur Sous-agents du tableau de bord, le champ `multiAgentModeHintText` de `PUT /api/v2` et `ocx v2 mode-hint` — écrit `features.multi_agent_v2.multi_agent_mode_hint_text` dans le fichier `$CODEX_HOME/config.toml` de Codex. La commande CLI `ocx v2 mode-hint` conserve cette clé même lorsque `multi_agent_v2` est désactivé ; elle n’active ni ne désactive la fonctionnalité. Cette indication remplace la politique multi-agents que codex-rs déduit du niveau d’effort : tous les modèles et tous les niveaux d’effort reçoivent alors le prompt de délégation Proactive. Elle ne modifie **pas** le niveau d’effort de raisonnement. diff --git a/docs-site/src/content/docs/guides/sub-agent-surface.md b/docs-site/src/content/docs/guides/sub-agent-surface.md index 32a689c560..6d09880fc6 100644 --- a/docs-site/src/content/docs/guides/sub-agent-surface.md +++ b/docs-site/src/content/docs/guides/sub-agent-surface.md @@ -20,6 +20,11 @@ Choose the mode for **new sessions**. Existing sessions keep the surface they st | **base** (default) | Upstream model pins: GPT-5.6 Sol/Terra use v2, Luna uses v1, and unpinned models follow Codex's `multi_agent_v2` feature flag. | Most users. It follows Codex's intended surface for each model without forcing one globally. | | **v2** | Flat `spawn_agent`, `send_message`, `followup_task`, `interrupt_agent`, and agent-list tools, with concurrent sessions. | Users who want the newer concurrent workflow and understand model inheritance and the encrypted-task limitation below. | +On **v2**, an optional **Keep ChatGPT on v1** switch (`keepNativeChatGptOnV1`) leaves Sol/Terra +on the v1 surface so they can still spawn Grok or Claude. ChatGPT-native parents encrypt v2 +`NEW_TASK` bodies; routed models cannot read them. Routed parents stay on v2, where child tasks +are plaintext. This is a switch *inside* v2, not a fourth catalog mode. + :::tip[Not sure?] Start with **base**. Choose **v1** when cross-provider delegation must work predictably. Force **v2** only when you specifically want its newer session model across every catalog entry. @@ -31,7 +36,7 @@ The selected mode controls the `multi_agent_version` field in every catalog entr - **v1** stamps `multi_agent_version = "v1"` on every model. - **base** restores upstream pins. Unpinned entries follow the native `multi_agent_v2` feature flag. -- **v2** stamps `multi_agent_version = "v2"` on every model. +- **v2** stamps `multi_agent_version = "v2"` on every model, except when **Keep ChatGPT on v1** is enabled: ChatGPT-native rows stay `"v1"` and routed or combo rows stay `"v2"`. opencodex applies this as the final pass to both the live `/v1/models` catalog and the catalog synced to disk. That is why a mode change affects newly created App, CLI, and TUI sessions consistently. diff --git a/docs-site/src/content/docs/ja/guides/sub-agent-surface.md b/docs-site/src/content/docs/ja/guides/sub-agent-surface.md index ec0c290829..7a9ac7aa12 100644 --- a/docs-site/src/content/docs/ja/guides/sub-agent-surface.md +++ b/docs-site/src/content/docs/ja/guides/sub-agent-surface.md @@ -27,7 +27,7 @@ description: Codex がすべてのモデルにわたってサブエージェン - **v1** はすべてのモデルに `multi_agent_version = "v1"` を刻印します。 - **base** は上流のピンを復元します。固定されていないエントリは、ネイティブ `multi_agent_v2` 機能フラグに従います。 -- **v2** はすべてのモデルに `multi_agent_version = "v2"` のスタンプを押します。 +- **v2** はすべてのモデルに `multi_agent_version = "v2"` のスタンプを押します。ただし **ChatGPT を v1 に保つ** を有効にした場合は例外で、ChatGPT ネイティブの行は `"v1"` のまま、ルーティング/コンボの行は `"v2"` になります。 opencodex は、これを最終パスとしてライブ `/v1/models` カタログとディスクに同期されたカタログの両方に適用します。そのため、モードの変更は、新しく作成されたアプリ、CLI、および TUI セッションに一貫して影響します。 diff --git a/docs-site/src/content/docs/ko/guides/sub-agent-surface.md b/docs-site/src/content/docs/ko/guides/sub-agent-surface.md index 9eac7b3b61..6b8f0064a0 100644 --- a/docs-site/src/content/docs/ko/guides/sub-agent-surface.md +++ b/docs-site/src/content/docs/ko/guides/sub-agent-surface.md @@ -27,7 +27,7 @@ description: Codex가 모든 모델에서 서브에이전트를 생성하고 관 - **v1**은 모든 모델에 `multi_agent_version = "v1"`을 설정합니다. - **base**는 업스트림 핀을 복원합니다. 핀이 없는 항목은 기본 `multi_agent_v2` 기능 플래그를 따릅니다. -- **v2**는 모든 모델에 `multi_agent_version = "v2"`를 설정합니다. +- **v2**는 모든 모델에 `multi_agent_version = "v2"`를 설정합니다. 단 **ChatGPT를 v1로 유지**를 켜면 예외입니다: ChatGPT 네이티브 항목은 `"v1"`로 남고, 라우팅/콤보 항목은 `"v2"`가 됩니다. opencodex는 이 값을 Codex가 읽는 실시간 `/v1/models` 카탈로그와 디스크에 동기화된 카탈로그 모두에 마지막 단계로 적용합니다. 그래서 모드를 바꾸면 새로 만들어지는 App, CLI, TUI 세션에 일관되게 반영됩니다. diff --git a/docs-site/src/content/docs/reference/cli/agents.md b/docs-site/src/content/docs/reference/cli/agents.md index 370fc639c0..e09159d1c5 100644 --- a/docs-site/src/content/docs/reference/cli/agents.md +++ b/docs-site/src/content/docs/reference/cli/agents.md @@ -17,7 +17,7 @@ surface modes, delegation, effort, and fallback behavior fit together. ocx agent subagents set ark/model-a,openai/gpt-5.5 ``` -### `ocx v2 |threads |mode-hint >` +### `ocx v2 |keep-native-v1 |threads |mode-hint >` Manage the Codex `multi_agent_v2` feature flag and the three-state multi-agent surface mode. @@ -28,7 +28,8 @@ Manage the Codex `multi_agent_v2` feature flag and the three-state multi-agent s | `off` | Disable the `multi_agent_v2` feature and resync the catalog. | | `mode v1` | Force all models to v1, disable native v2, and preserve the active thread limit. | | `mode default` | Respect upstream model surface pins. | -| `mode v2` | Force all models to v2, enable native v2, and preserve the active thread limit. | +| `mode v2` | Force models to v2, enable native v2, and preserve the active thread limit. ChatGPT-native models are exempt while `keep-native-v1` is on. | +| `keep-native-v1 on\|off` | Under `mode v2`, keep ChatGPT-native models on v1 instead of stamping them v2. | | `threads ` | Set the active v1/v2 thread limit to an integer of at least 1. | | `mode-hint ` | Set the Proactive delegation hint (Ultra mode) for every model and effort. | | `mode-hint --clear` | Remove the hint so the effort-derived policy (ultra = proactive) resumes. | diff --git a/docs-site/src/content/docs/reference/configuration/agents.md b/docs-site/src/content/docs/reference/configuration/agents.md index 0b9ec7886d..ddf93a2d47 100644 --- a/docs-site/src/content/docs/reference/configuration/agents.md +++ b/docs-site/src/content/docs/reference/configuration/agents.md @@ -11,6 +11,7 @@ routes, and limits delegated work. | Field | Type | Default | Meaning | | --- | --- | --- | --- | | `multiAgentMode?` | `"v1" \| "default" \| "v2"` | `"default"` | `v1` stamps every catalog model as v1; `v2` stamps every model as v2. `default` restores upstream pins (Sol/Terra v2, Luna v1) and otherwise follows the native `multi_agent_v2` flag. Applies to new sessions. | +| `keepNativeChatGptOnV1?` | `boolean` | `false` | When `multiAgentMode` is `"v2"`, stamp ChatGPT-native rows (Sol/Terra and other ChatGPT-backend models) as v1. Routed parents stay on v2. Use this so a ChatGPT parent can still spawn Grok or Claude — native v2 child tasks are backend-encrypted ([#92](https://github.com/lidge-jun/opencodex/issues/92)). Ignored in `v1` and `default`. | | `subagentModels?` | `string[]` | `gpt-5.5`, `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-5.6-luna`, `gpt-5.4-mini` | Up to five bare native, account-qualified `/`, or routed `provider/model` ids featured first in the sub-agent picker. The dashboard offers only bare native and routed ids and omits exact account-qualified choices when it saves; use `ocx agent subagents set` or edit the configuration for exact choices. An explicit empty list is preserved. | | `injectionModel?` | `string` | — | Preferred native or routed sub-agent model used in proxy-authored v2 delegation guidance. | | `injectionEffort?` | `string` | — | Preferred effort (`low` through `ultra`), meaningful only with `injectionModel`. | @@ -25,7 +26,7 @@ routes, and limits delegated work. | `agentTaskRecovery?` | `object` | — | Experimental opt-in recovery for backend-encrypted v2 tasks sent to routed providers. Disabled unless `enabled: true`; see [Encrypted v2 task recovery](#encrypted-v2-task-recovery). | Manage the surface with the dashboard or -`ocx v2 status|on|off|mode |threads |mode-hint `. +`ocx v2 status|on|off|mode |keep-native-v1 |threads |mode-hint `. Mode changes apply to new sessions. `maxConcurrentThreadsPerSession` is a `PUT /api/v2` field, not a `config.json` key; `ocx v2 threads ` writes `max_concurrent_threads_per_session` under `[features.multi_agent_v2]` in Codex's `$CODEX_HOME/config.toml` after v2 is enabled. diff --git a/docs-site/src/content/docs/ru/guides/sub-agent-surface.md b/docs-site/src/content/docs/ru/guides/sub-agent-surface.md index a8be75722a..8b6e7d504e 100644 --- a/docs-site/src/content/docs/ru/guides/sub-agent-surface.md +++ b/docs-site/src/content/docs/ru/guides/sub-agent-surface.md @@ -36,7 +36,7 @@ Codex: - **v1** записывает `multi_agent_version = "v1"` для каждой модели. - **base** восстанавливает upstream pin'ы. У записей без pin'а поведение определяется feature flag'ом `multi_agent_v2`. -- **v2** записывает `multi_agent_version = "v2"` для каждой модели. +- **v2** записывает `multi_agent_version = "v2"` для каждой модели, кроме случая, когда включён режим **Оставить ChatGPT на v1**: собственные строки ChatGPT остаются `"v1"`, а маршрутизируемые и комбо-строки остаются `"v2"`. opencodex применяет это как финальный проход и к живому каталогу `/v1/models`, и к каталогу, синхронизированному на диск. Поэтому смена режима одинаково влияет на новые App-, CLI- и diff --git a/docs-site/src/content/docs/tr/guides/sub-agent-surface.md b/docs-site/src/content/docs/tr/guides/sub-agent-surface.md index cf50c88509..04e6859e15 100644 --- a/docs-site/src/content/docs/tr/guides/sub-agent-surface.md +++ b/docs-site/src/content/docs/tr/guides/sub-agent-surface.md @@ -36,7 +36,7 @@ alanını denetler: - **v1**, her modele `multi_agent_version = "v1"` damgalar. - **base**, yukarı akış sabitlemelerini geri yükler. Sabitlenmemiş girdiler yerel `multi_agent_v2` özellik bayrağını takip eder. -- **v2**, her modele `multi_agent_version = "v2"` damgalar. +- **v2**, her modele `multi_agent_version = "v2"` damgalar; ancak **ChatGPT'yi v1'de tut** etkinken bu kural dışıdır: ChatGPT yerel satırları `"v1"` kalır, yönlendirilen ve combo satırları `"v2"` kalır. opencodex bunu hem canlı `/v1/models` kataloğuna hem de diske senkronize edilen kataloğa son geçiş olarak uygular. Bir mod değişikliğinin yeni oluşturulan App, diff --git a/docs-site/src/content/docs/zh-cn/guides/sub-agent-surface.md b/docs-site/src/content/docs/zh-cn/guides/sub-agent-surface.md index 89a5996b3f..3882d15c9a 100644 --- a/docs-site/src/content/docs/zh-cn/guides/sub-agent-surface.md +++ b/docs-site/src/content/docs/zh-cn/guides/sub-agent-surface.md @@ -27,7 +27,7 @@ description: 控制 Codex 如何在所有模型上生成和管理子代理。 - **v1** 会把所有模型的 `multi_agent_version` 设为 `"v1"`。 - **base** 会恢复上游固定值。未固定的条目会遵循原生 `multi_agent_v2` 功能开关。 -- **v2** 会把所有模型的 `multi_agent_version` 设为 `"v2"`。 +- **v2** 会把所有模型的 `multi_agent_version` 设为 `"v2"`;但启用 **让 ChatGPT 保持 v1** 时例外:ChatGPT 原生条目保持 `"v1"`,路由/组合条目仍为 `"v2"`。 opencodex 会把这一点作为最后一步同时应用到实时的 `/v1/models` 目录和同步到磁盘的目录。因此,模式更改会一致影响新建的 App、CLI 和 TUI 会话。 diff --git a/docs-site/src/content/docs/zh-tw/guides/sub-agent-surface.md b/docs-site/src/content/docs/zh-tw/guides/sub-agent-surface.md index e4affe9649..7cdb8fb49d 100644 --- a/docs-site/src/content/docs/zh-tw/guides/sub-agent-surface.md +++ b/docs-site/src/content/docs/zh-tw/guides/sub-agent-surface.md @@ -29,7 +29,7 @@ opencodex 允許你為目錄中的所有模型選擇多代理協作介面。儀 - **v1 模式**:強制所有條目使用 `multi_agent_version = "v1"`,覆蓋上游固定值。 - **base 模式**:恢復上游預設值。已固定的模型使用快照值;未固定的模型不寫入該欄位,交由 Codex 功能開關決定。 -- **v2 模式**:強制所有條目使用 `multi_agent_version = "v2"`,覆蓋上游固定值。 +- **v2 模式**:強制所有條目使用 `multi_agent_version = "v2"`,覆蓋上游固定值;但啟用 **讓 ChatGPT 保持 v1** 時例外:ChatGPT 原生條目維持 `"v1"`,路由/組合條目仍為 `"v2"`。 無論是即時 `/v1/models` 目錄回應,還是磁碟目錄同步,這項覆蓋都會作為最後一步執行。因此,無論條目原本如何生成,新會話都會使用一致的模式。 diff --git a/gui/src/i18n/de.ts b/gui/src/i18n/de.ts index 3876fe7844..a4a681d9b7 100644 --- a/gui/src/i18n/de.ts +++ b/gui/src/i18n/de.ts @@ -503,7 +503,9 @@ export const de: Record = { "models.v2ModeDesc_v1": "Alle Modelle → v1-Oberfläche", "models.v2ModeDesc_default": "Upstream-Standard (sol/terra=v2, luna=v1)", "models.v2ModeDesc_v2": "Alle Modelle → v2-Oberfläche", - "models.v2Help": "Steuert die Multi-Agent-Oberfläche für alle Modelle.\n\nv1: Klassischer Single-Thread-Agent. Jedes Modell nutzt die v1-Collab-Oberfläche.\nbase: Upstream-Standard — sol/terra nutzen v2, luna v1, andere folgen dem Codex-Feature-Flag.\nv2: Multi-Thread-Agent mit spawn_agent. Jedes Modell nutzt die v2-Collab-Oberfläche.\n\nÄnderungen gelten für neue Sitzungen.", + "models.keepNativeOnV1": "ChatGPT auf v1 lassen", + "models.keepNativeOnV1Hint": "ChatGPT-native Eltern verschlüsseln v2-Kindaufgaben — Grok und Claude können sie nicht lesen. An lassen, wenn Sol/Terra weiterhin geroutete Modelle starten sollen. Geroutete Eltern bleiben auf v2.", + "models.v2Help": "Steuert die Multi-Agent-Oberfläche für alle Modelle.\n\nv1: Klassischer Single-Thread-Agent. Jedes Modell nutzt die v1-Collab-Oberfläche.\nbase: Upstream-Standard — sol/terra nutzen v2, luna v1, andere folgen dem Codex-Feature-Flag.\nv2: Multi-Thread-Agent mit spawn_agent. Jedes Modell nutzt die v2-Collab-Oberfläche.\n\nUnter v2 lässt „ChatGPT auf v1 lassen“ Sol/Terra auf v1, damit sie weiter Grok oder Claude starten können. ChatGPT verschlüsselt v2-Kindaufgaben; geroutete Modelle können sie nicht lesen. Geroutete Eltern bleiben auf v2.\n\nÄnderungen gelten für neue Sitzungen.", "dash.multiAgent": "Sub-Agent", "models.v2Conflict": "[agents] max_threads ist gesetzt — codex verweigert den Start; entferne es aus config.toml", "models.v2Applied": "Sub-Agent-Modus aktualisiert — gilt für neue Sitzungen (Codex-App neu starten, um die Auswahl zu aktualisieren)", diff --git a/gui/src/i18n/en.ts b/gui/src/i18n/en.ts index 5773cf826f..6ed131e19c 100644 --- a/gui/src/i18n/en.ts +++ b/gui/src/i18n/en.ts @@ -528,7 +528,9 @@ export const en = { "models.v2ModeDesc_v1": "All models → v1 surface", "models.v2ModeDesc_default": "Upstream defaults (sol/terra=v2, luna=v1)", "models.v2ModeDesc_v2": "All models → v2 surface", - "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\nChanges apply to new sessions.", + "models.keepNativeOnV1": "Keep ChatGPT on v1", + "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", "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)", diff --git a/gui/src/i18n/fr.ts b/gui/src/i18n/fr.ts index f5c8a01b9f..1382ed2ee9 100644 --- a/gui/src/i18n/fr.ts +++ b/gui/src/i18n/fr.ts @@ -513,7 +513,9 @@ export const fr: Record = { "models.v2ModeDesc_v1": "Tous les modèles → interface v1", "models.v2ModeDesc_default": "Valeurs par défaut en amont (sol/terra=v2, luna=v1)", "models.v2ModeDesc_v2": "Tous les modèles → interface 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\nLes modifications s’appliquent aux nouvelles sessions.", + "models.keepNativeOnV1": "Garder ChatGPT sur v1", + "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", "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)", diff --git a/gui/src/i18n/ja.ts b/gui/src/i18n/ja.ts index 3c55198ebd..10f91145f2 100644 --- a/gui/src/i18n/ja.ts +++ b/gui/src/i18n/ja.ts @@ -511,7 +511,9 @@ export const ja: Record = { "models.v2ModeDesc_v1": "すべてのモデル → v1 サーフェス", "models.v2ModeDesc_default": "上流のデフォルト(sol/terra=v2、luna=v1)", "models.v2ModeDesc_v2": "すべてのモデル → v2 サーフェス", - "models.v2Help": "すべてのモデルのマルチエージェントサーフェスを制御します。\n\nv1: クラシックな単一スレッドエージェント。すべてのモデルが v1 コラボサーフェスを使います。\nベース: 上流のデフォルト — sol/terra は v2、luna は v1、それ以外は codex のフィーチャーフラグに従います。\nv2: spawn_agent を備えたマルチスレッドエージェント。すべてのモデルが v2 コラボサーフェスを使います。\n\n変更は新規セッションに適用されます。", + "models.keepNativeOnV1": "ChatGPT を v1 のまま", + "models.keepNativeOnV1Hint": "ChatGPT ネイティブの親は v2 子タスクを暗号化するため、Grok や Claude は読めません。Sol/Terra から routed モデルを spawn するならオンのまま。routed 親は v2 のままです。", + "models.v2Help": "すべてのモデルのマルチエージェントサーフェスを制御します。\n\nv1: クラシックな単一スレッドエージェント。すべてのモデルが v1 コラボサーフェスを使います。\nベース: 上流のデフォルト — sol/terra は v2、luna は v1、それ以外は codex のフィーチャーフラグに従います。\nv2: spawn_agent を備えたマルチスレッドエージェント。すべてのモデルが v2 コラボサーフェスを使います。\n\nv2 では「ChatGPT を v1 のまま」にすると Sol/Terra が v1 に留まり、Grok や Claude を spawn できます。ChatGPT は v2 子タスクを暗号化するため routed モデルは読めません。routed 親は v2 のままです。\n\n変更は新規セッションに適用されます。", "dash.multiAgent": "サブエージェント", "models.v2Conflict": "[agents] max_threads が設定されています — codex は起動を拒否します; config.toml から削除してください", "models.v2Applied": "サブエージェントモードを更新しました — 新規セッションに適用(ピッカーを更新するには Codex アプリを再起動)", diff --git a/gui/src/i18n/ko.ts b/gui/src/i18n/ko.ts index 09632c73e7..b19fcad3e4 100644 --- a/gui/src/i18n/ko.ts +++ b/gui/src/i18n/ko.ts @@ -513,7 +513,9 @@ export const ko: Record = { "models.v2ModeDesc_v1": "전 모델 → v1 서피스", "models.v2ModeDesc_default": "업스트림 기본값 (sol/terra=v2, luna=v1)", "models.v2ModeDesc_v2": "전 모델 → v2 서피스", - "models.v2Help": "모든 모델의 멀티에이전트 서피스를 제어합니다.\n\nv1: 단일 스레드 에이전트. 모든 모델이 v1 서피스를 사용합니다.\nbase: 업스트림 기본값 — sol/terra는 v2, luna는 v1, 나머지는 codex 플래그를 따릅니다.\nv2: 멀티 스레드 에이전트(spawn_agent). 모든 모델이 v2 서피스를 사용합니다.\n\n새 세션부터 적용됩니다.", + "models.keepNativeOnV1": "ChatGPT는 v1 유지", + "models.keepNativeOnV1Hint": "ChatGPT 네이티브 부모는 v2 자식 작업을 암호화해서 Grok/Claude가 읽지 못합니다. Sol/Terra가 routed 모델을 spawn해야 하면 켜 두세요. routed 부모는 v2를 유지합니다.", + "models.v2Help": "모든 모델의 멀티에이전트 서피스를 제어합니다.\n\nv1: 단일 스레드 에이전트. 모든 모델이 v1 서피스를 사용합니다.\nbase: 업스트림 기본값 — sol/terra는 v2, luna는 v1, 나머지는 codex 플래그를 따릅니다.\nv2: 멀티 스레드 에이전트(spawn_agent). 모든 모델이 v2 서피스를 사용합니다.\n\nv2에서 ChatGPT는 v1 유지를 켜면 Sol/Terra가 v1에 남아 Grok이나 Claude를 spawn할 수 있습니다. ChatGPT는 v2 자식 작업을 암호화하므로 routed 모델은 읽지 못합니다. routed 부모는 v2를 유지합니다.\n\n새 세션부터 적용됩니다.", "models.v2DocsLink": "v1 / v2가 뭔가요?", "dash.multiAgent": "서브에이전트", "models.v2Conflict": "[agents] max_threads가 남아 있어 codex가 부팅을 거부합니다 — config.toml에서 제거하세요", diff --git a/gui/src/i18n/ru.ts b/gui/src/i18n/ru.ts index abcc924d3f..252de8396c 100644 --- a/gui/src/i18n/ru.ts +++ b/gui/src/i18n/ru.ts @@ -516,7 +516,9 @@ export const ru: Record = { "models.v2ModeDesc_v1": "Все модели → поверхность v1", "models.v2ModeDesc_default": "Вышестоящие значения по умолчанию (sol/terra=v2, luna=v1)", "models.v2ModeDesc_v2": "Все модели → поверхность v2", - "models.v2Help": "Управляет мультиагентной поверхностью для всех моделей.\n\nv1: Классический однопоточный агент. Каждая модель использует поверхность взаимодействия v1.\nbase: Вышестоящие значения по умолчанию — sol/terra используют v2, luna использует v1, остальные следуют функциональному флагу codex.\nv2: Многопоточный агент со spawn_agent. Каждая модель использует поверхность взаимодействия v2.\n\nИзменения применяются к новым сессиям.", + "models.keepNativeOnV1": "Оставить ChatGPT на v1", + "models.keepNativeOnV1Hint": "Нативные родители ChatGPT шифруют дочерние задачи v2 — Grok и Claude их не читают. Оставьте включённым, если Sol/Terra должны порождать routed-модели. Routed-родители остаются на v2.", + "models.v2Help": "Управляет мультиагентной поверхностью для всех моделей.\n\nv1: Классический однопоточный агент. Каждая модель использует поверхность взаимодействия v1.\nbase: Вышестоящие значения по умолчанию — sol/terra используют v2, luna использует v1, остальные следуют функциональному флагу codex.\nv2: Многопоточный агент со spawn_agent. Каждая модель использует поверхность взаимодействия v2.\n\nНа v2 «Оставить ChatGPT на v1» оставляет Sol/Terra на v1, чтобы они могли порождать Grok или Claude. ChatGPT шифрует дочерние задачи v2 — routed-модели их не читают. Routed-родители остаются на v2.\n\nИзменения применяются к новым сессиям.", "dash.multiAgent": "Подагент", "models.v2Conflict": "Задан [agents] max_threads — codex откажется запускаться; удалите его из config.toml", "models.v2Applied": "Режим подагента обновлён — применяется к новым сессиям (перезапустите приложение Codex, чтобы обновить селектор моделей)", diff --git a/gui/src/i18n/tr.ts b/gui/src/i18n/tr.ts index 4a38a1fcde..7d50716b79 100644 --- a/gui/src/i18n/tr.ts +++ b/gui/src/i18n/tr.ts @@ -519,7 +519,9 @@ export const tr: Record = { "models.v2ModeDesc_v1": "Tüm modeller → v1 yüzeyi", "models.v2ModeDesc_default": "Yukarı akış varsayılanları", "models.v2ModeDesc_v2": "Tüm modeller → v2 yüzeyi", - "models.v2Help": "v1 alt ajanları birincil modelle sınırlandırır; base standart ajan sınırlarını devralır; v2 tam çoklu ajan orkestrasyonunu etkinleştirir.", + "models.keepNativeOnV1": "ChatGPT v1'de kalsın", + "models.keepNativeOnV1Hint": "ChatGPT yerel ebeveynleri v2 çocuk görevlerini şifreler; Grok ve Claude okuyamaz. Sol/Terra yönlendirilmiş modelleri spawn edecekse açık bırakın. Yönlendirilmiş ebeveynler v2'de kalır.", + "models.v2Help": "v1 alt ajanları birincil modelle sınırlandırır; taban standart ajan sınırlarını devralır; v2 tam çoklu ajan orkestrasyonunu etkinleştirir.\n\nv2'de ChatGPT v1'de kalsın, Sol/Terra'yı v1'de bırakır; böylece Grok veya Claude spawn edebilirler. ChatGPT v2 çocuk görevlerini şifreler; yönlendirilmiş modeller okuyamaz. Yönlendirilmiş ebeveynler v2'de kalır.\n\nDeğişiklikler yeni oturumlara uygulanır.", "dash.multiAgent": "Alt Ajan", "models.v2Conflict": "[agents] max_threads ayarlanmış — config.toml dosyasından kaldırın", "models.v2Applied": "Çoklu ajan modu güncellendi. Yeni oturumlar bu modu kullanacaktır; model seçiciyi yenilemek için Codex uygulamasını yeniden başlatın.", diff --git a/gui/src/i18n/zh-TW.ts b/gui/src/i18n/zh-TW.ts index fa273129c2..9dd4ef7b69 100644 --- a/gui/src/i18n/zh-TW.ts +++ b/gui/src/i18n/zh-TW.ts @@ -395,7 +395,9 @@ export const zhTW: Record = { "models.v2ModeDesc_v1": "所有模型 → v1 介面", "models.v2ModeDesc_default": "上游預設值 (sol/terra=v2, luna=v1)", "models.v2ModeDesc_v2": "所有模型 → v2 介面", - "models.v2Help": "控制所有模型的多代理介面。\n\nv1: 經典單執行緒代理。所有模型使用 v1 協作介面。\nbase: 上游預設值 — sol/terra 使用 v2,luna 使用 v1,其餘跟隨 codex 功能標誌。\nv2: 多執行緒代理(spawn_agent)。所有模型使用 v2 協作介面。\n\n更改在新會話中生效。", + "models.keepNativeOnV1": "ChatGPT 維持 v1", + "models.keepNativeOnV1Hint": "ChatGPT 原生父代理會加密 v2 子任務,Grok/Claude 無法讀取。若 Sol/Terra 仍需派發路由模型,請保持開啟。路由父代理仍使用 v2。", + "models.v2Help": "控制所有模型的多代理介面。\n\nv1: 經典單執行緒代理。所有模型使用 v1 協作介面。\nbase: 上游預設值 — sol/terra 使用 v2,luna 使用 v1,其餘跟隨 codex 功能標誌。\nv2: 多執行緒代理(spawn_agent)。所有模型使用 v2 協作介面。\n\n在 v2 下,「ChatGPT 維持 v1」會讓 Sol/Terra 留在 v1,以便繼續派發 Grok 或 Claude。ChatGPT 會加密 v2 子任務,路由模型無法讀取;路由父代理仍留在 v2。\n\n更改在新會話中生效。", "dash.multiAgent": "子代理", "models.v2Conflict": "[agents] max_threads 仍存在 — codex 將拒絕啟動,請從 config.toml 移除", "models.v2Applied": "子代理模式已更新 — 新會話生效(重新啟動 Codex 應用以重新整理選擇器)", diff --git a/gui/src/i18n/zh.ts b/gui/src/i18n/zh.ts index fe5366432a..260b6a233f 100644 --- a/gui/src/i18n/zh.ts +++ b/gui/src/i18n/zh.ts @@ -510,7 +510,9 @@ export const zh: Record = { "models.v2ModeDesc_v1": "所有模型 → v1 界面", "models.v2ModeDesc_default": "上游默认值 (sol/terra=v2, luna=v1)", "models.v2ModeDesc_v2": "所有模型 → v2 界面", - "models.v2Help": "控制所有模型的多代理界面。\n\nv1: 经典单线程代理。所有模型使用 v1 协作界面。\nbase: 上游默认值 — sol/terra 使用 v2,luna 使用 v1,其余跟随 codex 功能标志。\nv2: 多线程代理(spawn_agent)。所有模型使用 v2 协作界面。\n\n更改在新会话中生效。", + "models.keepNativeOnV1": "ChatGPT 保持 v1", + "models.keepNativeOnV1Hint": "仅当 ChatGPT 原生父代理仍留在 v2 时,才会加密 v2 子任务,Grok/Claude 无法读取。开启此选项可让 Sol/Terra 留在 v1,从而避免该加密。路由父代理仍使用 v2。", + "models.v2Help": "控制所有模型的多代理界面。\n\nv1: 经典单线程代理。所有模型使用 v1 协作界面。\nbase: 上游默认值 — sol/terra 使用 v2,luna 使用 v1,其余跟随 codex 功能标志。\nv2: 多线程代理(spawn_agent)。所有模型使用 v2 协作界面。\n\n在 v2 下,「ChatGPT 保持 v1」会让 Sol/Terra 留在 v1,以便继续派发 Grok 或 Claude。ChatGPT 会加密 v2 子任务,路由模型无法读取;路由父代理仍留在 v2。\n\n更改在新会话中生效。", "models.v2DocsLink": "v1 / v2 是什么?", "dash.multiAgent": "子代理", "models.v2Conflict": "[agents] max_threads 仍存在 — codex 将拒绝启动,请从 config.toml 移除", diff --git a/gui/src/pages/Models.tsx b/gui/src/pages/Models.tsx index f2fab8604a..703c6c5348 100644 --- a/gui/src/pages/Models.tsx +++ b/gui/src/pages/Models.tsx @@ -304,6 +304,7 @@ export default function Models({ apiBase, restartEpoch = 0 }: { apiBase: string; agentsMaxThreadsConflict: data.agentsMaxThreadsConflict === true, maxConcurrentThreadsPerSession: typeof data.maxConcurrentThreadsPerSession === "number" ? data.maxConcurrentThreadsPerSession : null, multiAgentMode: data.multiAgentMode === "v1" || data.multiAgentMode === "v2" ? data.multiAgentMode : "default", + keepNativeChatGptOnV1: data.keepNativeChatGptOnV1 === true, }); } catch { setV2(null); // old server / network: hide the section instead of guessing @@ -771,9 +772,15 @@ export default function Models({ apiBase, restartEpoch = 0 }: { apiBase: string; } }; - const setMultiAgentMode = async (mode: "v1" | "default" | "v2") => { + /** + * Both v2 surface writes adopt the response directly instead of calling + * `loadV2()`. `loadV2` returns early while `v2BusyRef` is still held by the + * in-flight write, so the refetch was a no-op and the control kept its old + * value until the next 10s poll. That is visible here: "Keep ChatGPT on v1" + * only renders while the mode is v2, so a stale mode also delayed the row. + */ + const putV2Setting = async (body: Record) => { if (!v2 || v2BusyRef.current) return; - if (v2.multiAgentMode === mode) return; setV2Busy(true); v2BusyRef.current = true; setV2Note(""); @@ -782,14 +789,25 @@ export default function Models({ apiBase, restartEpoch = 0 }: { apiBase: string; const r = await fetch(`${apiBase}/api/v2`, { method: "PUT", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ multiAgentMode: mode }), + body: JSON.stringify(body), }); try { const data = await readJsonOrThrow(r, t("models.saveFailed")); - void loadV2(); + if (!data || typeof data.enabled !== "boolean") { + setOk(false); + setStatus(t("models.saveFailed")); + return; + } + setV2({ + enabled: data.enabled, + agentsMaxThreadsConflict: data.agentsMaxThreadsConflict === true, + maxConcurrentThreadsPerSession: typeof data.maxConcurrentThreadsPerSession === "number" ? data.maxConcurrentThreadsPerSession : null, + multiAgentMode: data.multiAgentMode === "v1" || data.multiAgentMode === "v2" ? data.multiAgentMode : "default", + keepNativeChatGptOnV1: data.keepNativeChatGptOnV1 === true, + }); setOk(true); setStatus(t("models.v2Applied")); - setV2Note((data?.warnings ?? []).join(" ")); + setV2Note((data.warnings ?? []).join(" ")); } catch (e) { setOk(false); setStatus(e instanceof Error ? e.message : t("models.saveFailed")); @@ -802,6 +820,16 @@ export default function Models({ apiBase, restartEpoch = 0 }: { apiBase: string; } }; + const setMultiAgentMode = async (mode: "v1" | "default" | "v2") => { + if (!v2 || v2.multiAgentMode === mode) return; + await putV2Setting({ multiAgentMode: mode }); + }; + + const setKeepNativeChatGptOnV1 = async (next: boolean) => { + if (!v2 || v2.keepNativeChatGptOnV1 === next) return; + await putV2Setting({ keepNativeChatGptOnV1: next }); + }; + const putV2Threads = async (value: number) => { // Same guards as the flag toggle: single-flight + server-side idempotence // (setMaxConcurrentThreads no-ops on equal value), so a re-selected current @@ -831,6 +859,7 @@ export default function Models({ apiBase, restartEpoch = 0 }: { apiBase: string; agentsMaxThreadsConflict: data.agentsMaxThreadsConflict === true, maxConcurrentThreadsPerSession: typeof data.maxConcurrentThreadsPerSession === "number" ? data.maxConcurrentThreadsPerSession : null, multiAgentMode: data.multiAgentMode === "v1" || data.multiAgentMode === "v2" ? data.multiAgentMode : "default", + keepNativeChatGptOnV1: data.keepNativeChatGptOnV1 === true, }); setOk(true); setStatus(t("models.v2ThreadsApplied")); @@ -1292,6 +1321,24 @@ export default function Models({ apiBase, restartEpoch = 0 }: { apiBase: string; )} + {v2 && v2.multiAgentMode === "v2" && ( +
+
+ {t("models.keepNativeOnV1")} + void setKeepNativeChatGptOnV1(!v2.keepNativeChatGptOnV1)} + disabled={v2Busy} + label={t("models.keepNativeOnV1")} + /> + + + + +
+
+ )} {v2 && (v2.enabled || v2.agentsMaxThreadsConflict || v2Note) && ( diff --git a/gui/src/pages/models-shared.ts b/gui/src/pages/models-shared.ts index a8205616cb..368d9743b5 100644 --- a/gui/src/pages/models-shared.ts +++ b/gui/src/pages/models-shared.ts @@ -62,6 +62,7 @@ export interface V2Status { agentsMaxThreadsConflict: boolean; maxConcurrentThreadsPerSession?: number | null; multiAgentMode?: "v1" | "default" | "v2"; + keepNativeChatGptOnV1?: boolean; } export interface ShadowCallData { diff --git a/gui/src/styles-models-workspace.css b/gui/src/styles-models-workspace.css index e2cc78310b..75433cc64f 100644 --- a/gui/src/styles-models-workspace.css +++ b/gui/src/styles-models-workspace.css @@ -210,6 +210,50 @@ align-items: center; } +/* + "Keep ChatGPT on v1" is a sub-setting of the Sub-agent surface control, not a + peer of it. It sits in the right-hand grid column directly under the v1/base/v2 + chips and stays right-aligned with them, so it reads as a qualifier on the + selected mode instead of floating in the empty space beside Shadow Call. +*/ +.models-v2-keep-native-row { + grid-column: 2; + justify-self: end; + display: flex; + justify-content: flex-end; + min-width: 0; + /* Pull up against the mode row's own min-height so the pair reads as one block. */ + margin-top: calc(var(--space-1) * -1); +} + +.models-v2-keep-native { + display: inline-flex; + align-items: center; + gap: var(--space-2); + min-width: 0; +} + +.models-v2-keep-native-label { + color: var(--muted); + white-space: nowrap; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; +} + +/* Sits in the same 24px gutter as the Sub-agent help button directly above it, + so both rows end on one right edge. */ +.models-v2-keep-native-info { + display: inline-flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + flex: 0 0 24px; + color: var(--muted); + cursor: help; +} + /* ── Provider group header (Classic + Workspace) ─────── */ .models-provider-head { @@ -436,6 +480,17 @@ flex-wrap: wrap; justify-self: start; } + + .models-v2-keep-native-row { + grid-column: 1; + justify-self: start; + justify-content: flex-start; + margin-top: 0; + } + + .models-v2-keep-native { + white-space: normal; + } } /* diff --git a/gui/tests/models-keep-native-v1-placement.test.ts b/gui/tests/models-keep-native-v1-placement.test.ts new file mode 100644 index 0000000000..4e3969df58 --- /dev/null +++ b/gui/tests/models-keep-native-v1-placement.test.ts @@ -0,0 +1,80 @@ +import { expect, test } from "bun:test"; + +const modelsSource = await Bun.file(new URL("../src/pages/Models.tsx", import.meta.url)).text(); +const workspaceCss = await Bun.file(new URL("../src/styles-models-workspace.css", import.meta.url)).text(); + +/** + * "Keep ChatGPT on v1" qualifies the selected Sub-agent surface, so it has to + * render under the v1/base/v2 chips in the right-hand column of the controls + * grid. Reusing `.models-v2-mode-row` put it in the left (Shadow Call) column + * instead, where it read as an unrelated floating switch. + */ +test("keep-native-v1 switch renders in its own right-column row, not a second mode row", () => { + const block = modelsSource.slice(modelsSource.indexOf('v2.multiAgentMode === "v2"')); + const row = block.slice(0, block.indexOf("\n ") + 1); + + expect(row).toContain("models-v2-keep-native-row"); + expect(row).toContain("models.keepNativeOnV1"); + // The old markup reused the mode row and hard-coded an inline offset. + expect(row).not.toContain('className="models-v2-mode-row row" style={{ marginTop: 8 }}'); +}); + +test("keep-native-v1 row is pinned to the Sub-agent column and right-aligned", () => { + const rule = workspaceCss.slice(workspaceCss.indexOf(".models-v2-keep-native-row {")); + const body = rule.slice(0, rule.indexOf("}")); + + expect(body).toContain("grid-column: 2"); + expect(body).toContain("justify-self: end"); +}); + +test("keep-native-v1 row falls back to the single-column stack under 1160px", () => { + const narrow = workspaceCss.slice(workspaceCss.indexOf("@media (max-width: 1160px)")); + const scoped = narrow.slice(0, narrow.indexOf("@container")); + + expect(scoped).toContain(".models-v2-keep-native-row"); + expect(scoped).toContain("grid-column: 1"); + expect(scoped).toContain("justify-self: start"); +}); + +/** + * `Tooltip` renders a