From 02aa1285cb2d4a159620fc0b76a90585e8fdf7c6 Mon Sep 17 00:00:00 2001 From: Ingwannu Date: Sat, 5 Sep 2026 03:22:09 +0000 Subject: [PATCH 1/2] fix(responses): preserve trusted encrypted fallback routes --- .../docs/fr/guides/sub-agent-surface.md | 8 +-- .../docs/fr/reference/configuration/agents.md | 2 +- .../docs/fr/reference/proxy-formats.md | 2 +- .../content/docs/guides/sub-agent-surface.md | 15 +++--- .../docs/ja/guides/sub-agent-surface.md | 7 +-- .../docs/ja/reference/configuration/agents.md | 2 +- .../docs/ja/reference/proxy-formats.md | 2 +- .../docs/ko/guides/sub-agent-surface.md | 4 +- .../docs/ko/reference/configuration/agents.md | 2 +- .../docs/ko/reference/proxy-formats.md | 2 +- .../docs/reference/configuration/agents.md | 8 +-- .../content/docs/reference/proxy-formats.md | 2 +- .../docs/ru/guides/sub-agent-surface.md | 8 +-- .../docs/ru/reference/configuration/agents.md | 8 +-- .../docs/ru/reference/proxy-formats.md | 2 +- .../docs/tr/guides/sub-agent-surface.md | 14 ++--- .../docs/tr/reference/configuration/agents.md | 9 ++-- .../docs/tr/reference/proxy-formats.md | 3 +- .../docs/zh-cn/guides/sub-agent-surface.md | 4 +- .../zh-cn/reference/configuration/agents.md | 2 +- .../docs/zh-cn/reference/proxy-formats.md | 2 +- .../docs/zh-tw/guides/sub-agent-surface.md | 13 ++--- .../zh-tw/reference/configuration/agents.md | 2 +- .../docs/zh-tw/reference/proxy-formats.md | 2 +- src/codex/subagent-model-fallback.ts | 14 ++++- src/server/responses/core.ts | 4 +- tests/routing/subagent-model-fallback.test.ts | 46 ++++++++++++++++ .../server/agent-task-recovery-combo.test.ts | 28 ++++++++++ tests/server/agent-task-recovery.test.ts | 52 +++++++++++++++++++ 29 files changed, 211 insertions(+), 58 deletions(-) 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 87c11ebcec..46c88dcbf6 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 @@ -116,8 +116,9 @@ pendant un temps de recharge, il manque un compte Codex poolé utilisable ou au- Les sondes de disponibilité sont mises en cache pendant `subagentModelFallbackPollMs` (60 secondes par défaut). La solution de secours ne rend pas lisibles les tâches chiffrées incompatibles. Lorsque la tâche enfant est chiffrée pour -ChatGPT, la sélection est restreinte aux cibles ChatGPT natives canoniques même si un modèle externe -apparaît plus tôt dans la chaîne. +ChatGPT, la sélection est restreinte aux cibles ChatGPT natives canoniques et aux routes Responses directes avec authentification +par clé explicitement approuvées via `allowEncryptedV2AgentTasks: true`, même si un autre modèle externe apparaît plus tôt dans +la chaîne. Les combos restent limités aux cibles natives canoniques. ## Livraison de tâches v2 cryptées @@ -128,7 +129,8 @@ 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 : - Une route directe non native renvoie HTTP 400 avec - `error.code = "unreadable_encrypted_agent_task"` et ne fait pas écho au texte chiffré. + `error.code = "unreadable_encrypted_agent_task"` et ne fait pas écho au texte chiffré, sauf si + son fournisseur Responses à authentification par clé active explicitement `allowEncryptedV2AgentTasks: true`. - Un combo considère uniquement les cibles ChatGPT natives canoniques pour cette tâche, y compris les tentatives. Si aucun est disponible, il renvoie la même erreur 400. - Une tâche lisible en texte clair conserve la route normale et le comportement de repli. 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 37e1f2111d..ab808870d4 100644 --- a/docs-site/src/content/docs/fr/reference/configuration/agents.md +++ b/docs-site/src/content/docs/fr/reference/configuration/agents.md @@ -58,7 +58,7 @@ Pour un tour enfant créé, l’ordre de repli est le suivant : Les chaînes de repli propres à un rôle doivent résider dans la configuration d’opencodex. L’ajout de `model_fallback` dans `$CODEX_HOME/agents/*.toml` amène Codex 0.146+ à rejeter le fichier de rôle entier à cause de ce champ inconnu, puis à ignorer le rôle (#1190). Une ancienne ligne `model_fallback` dans le fichier TOML reste lue par souci de rétrocompatibilité, mais `ocx doctor` la signale. -opencodex ignore les candidats désactivés, non routables, en mauvais état, en période de temporisation ou ayant atteint le seuil de quota. L’instantané de disponibilité est mis en cache pendant `subagentModelFallbackPollMs`. Les tâches enfants chiffrées peuvent limiter la chaîne aux cibles ChatGPT natives canoniques ; si aucune ne peut lire la charge chiffrée, la requête échoue au lieu d’envoyer un texte chiffré illisible à une autre destination. +opencodex ignore les candidats désactivés, non routables, en mauvais état, en période de temporisation ou ayant atteint le seuil de quota. L’instantané de disponibilité est mis en cache pendant `subagentModelFallbackPollMs`. Les tâches enfants chiffrées limitent la chaîne aux cibles ChatGPT natives canoniques et aux routes Responses directes avec authentification par clé explicitement approuvées via `allowEncryptedV2AgentTasks: true` ; si aucune ne peut consommer la charge chiffrée, la requête échoue au lieu d’envoyer un texte chiffré illisible à une autre destination. Les combos restent limités aux cibles natives canoniques. ```json { diff --git a/docs-site/src/content/docs/fr/reference/proxy-formats.md b/docs-site/src/content/docs/fr/reference/proxy-formats.md index 38bb350903..e8023fec3a 100644 --- a/docs-site/src/content/docs/fr/reference/proxy-formats.md +++ b/docs-site/src/content/docs/fr/reference/proxy-formats.md @@ -310,7 +310,7 @@ Les erreurs utilisent l'enveloppe du dialecte client lorsque cela est nécessair | 401 | `authentication_error` | Un identifiant requis pour l’admission au proxy est manquant ou invalide | | 403 | `origin_rejected` | Une demande de plan de données Réponses/OpenAI ou une mise à niveau WebSocket provient d'une origine non autorisée | | 503 | `combo_unavailable` | Chaque cible du combo sélectionné est indisponible, en temps de recharge, désactivée ou autrement inéligible | -| 400 | `unreadable_encrypted_agent_task` | Une tâche de travail v2 chiffrée n'a pas de cible native éligible pouvant la consommer | +| 400 | `unreadable_encrypted_agent_task` | Une tâche de travail v2 chiffrée n'a ni cible ChatGPT canonique ni cible Responses explicitement approuvée pouvant la consommer | | 426 | `upgrade_required` | Le transport Réponses WebSocket est désactivé ou la mise à niveau a échoué ; utiliser HTTP | Les échecs d'origine Anthropic sont restitués dans l'enveloppe d'erreur de Anthropic, donc le rejet d'origine est un 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 f88ba9c10b..23ef2ad891 100644 --- a/docs-site/src/content/docs/guides/sub-agent-surface.md +++ b/docs-site/src/content/docs/guides/sub-agent-surface.md @@ -117,8 +117,9 @@ inside a cooldown, missing a usable pooled Codex account, or beyond the configur Availability probes are cached for `subagentModelFallbackPollMs` (60 seconds by default). Fallback does not make incompatible encrypted tasks readable. When the child task is encrypted for -ChatGPT, selection is restricted to canonical native ChatGPT targets even if an external model -appears earlier in the chain. +ChatGPT, selection is restricted to canonical native ChatGPT targets and direct key-auth Responses +routes explicitly trusted with `allowEncryptedV2AgentTasks: true`, even if another external model +appears earlier in the chain. Combos remain canonical-native-only. ## Encrypted v2 task delivery @@ -129,14 +130,16 @@ known [#92 limitation](https://github.com/lidge-jun/opencodex/issues/92). opencodex fails safely instead of forwarding an empty or unreadable task: - A direct non-native route returns HTTP 400 with - `error.code = "unreadable_encrypted_agent_task"` and does not echo the ciphertext. + `error.code = "unreadable_encrypted_agent_task"` and does not echo the ciphertext unless its + key-auth Responses provider explicitly opts in with `allowEncryptedV2AgentTasks: true`. - A combo considers only canonical native ChatGPT targets for that task, including retries. If none is available, it returns the same 400 error. - A readable plaintext task keeps the normal route and fallback behavior. -Recovery options are to select a native ChatGPT child, add a native ChatGPT target to the combo, use -v1 for heterogeneous-provider delegation, or resend the task as plaintext v2 `agent_message` -content when you control the caller. +Recovery options are to select a native ChatGPT child, explicitly trust a direct key-auth Responses +relay that can consume the opaque payload, add a native ChatGPT target to the combo, use v1 for +heterogeneous-provider delegation, or resend the task as plaintext v2 `agent_message` content when +you control the caller. An experimental, disabled-by-default `agentTaskRecovery` option can recover this specific native- to-routed shape through a raw Responses passthrough to the fixed ChatGPT `/responses` endpoint using 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 7a9ac7aa12..82f1331de5 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 @@ -72,7 +72,7 @@ v1 では、opencodex は、`max` または `ultra` の取り組みでアップ 重複するモデル ID は、最初に出現したモデル ID を保持しながら削除されます。選択中、opencodex は、無効になっている、ルーティングできない、無効なプロバイダーによってサポートされている、異常とマークされている、クールダウン中、使用可能なプールされた Codex アカウントがない、または設定されたクォータしきい値を超えている候補をスキップします。可用性プローブは `subagentModelFallbackPollMs` に対してキャッシュされます (デフォルトでは 60 秒)。 -フォールバックでは、互換性のない暗号化タスクは読み取り可能になりません。子タスクが ChatGPT 用に暗号化されている場合、外部モデルがチェーンの前の方に表示されている場合でも、選択は正規のネイティブ ChatGPT ターゲットに制限されます。 +フォールバックでは、互換性のない暗号化タスクは読み取り可能になりません。子タスクが ChatGPT 用に暗号化されている場合、別の外部モデルがチェーンの前の方に表示されていても、選択は正規のネイティブ ChatGPT ターゲットと、`allowEncryptedV2AgentTasks: true` で明示的に信頼された直接のキー認証 Responses ルートに制限されます。コンボは引き続き正規のネイティブ対象だけを使用します。 ## 暗号化された v2 タスク配信 @@ -80,8 +80,9 @@ Codex は、v2 ネイティブからルーティングされた子タスクを opencodex は、空のタスクまたは読み取り不可能なタスクを転送するのではなく、安全に失敗します。 -- 直接の非ネイティブ ルートは HTTP 400 を返します。 -`error.code = "unreadable_encrypted_agent_task"` であり、暗号文はエコーされません。 +- 直接の非ネイティブ ルートは HTTP 400 と +`error.code = "unreadable_encrypted_agent_task"` を返し、暗号文をエコーしません。ただし、 +キー認証 Responses プロバイダーが `allowEncryptedV2AgentTasks: true` を明示的に有効にした場合を除きます。 - コンボでは、再試行を含む、そのタスクの正規のネイティブ ChatGPT ターゲットのみが考慮されます。何もない場合 が利用可能な場合は、同じ 400 エラーが返されます。 - 読み取り可能なプレーンテキストのタスクは、通常のルートとフォールバック動作を維持します。 diff --git a/docs-site/src/content/docs/ja/reference/configuration/agents.md b/docs-site/src/content/docs/ja/reference/configuration/agents.md index 03b86332ef..ff8bf51d3d 100644 --- a/docs-site/src/content/docs/ja/reference/configuration/agents.md +++ b/docs-site/src/content/docs/ja/reference/configuration/agents.md @@ -53,7 +53,7 @@ V1 ガイダンスは、`max` または `ultra` でのみプロアクティブ 拒否し、ロールをスキップします(#1190)。TOML 内のレガシー `model_fallback` 行は後方互換性の ために引き続き読み取られますが、`ocx doctor` がそれをフラグ付けします。 -opencodex は、無効、ルーティング不能、異常、冷却期間、またはクォータしきい値の候補をスキップします。可用性スナップショットは `subagentModelFallbackPollMs` に対してキャッシュされます。暗号化された子タスクは、チェーンを正規のネイティブ ChatGPT ターゲットに制限できます。暗号化されたペイロードを読み取ることができる人がいない場合、読み取り不可能な暗号文が別の場所にルーティングされる代わりに、リクエストは失敗します。 +opencodex は、無効、ルーティング不能、異常、冷却期間、またはクォータしきい値の候補をスキップします。可用性スナップショットは `subagentModelFallbackPollMs` に対してキャッシュされます。暗号化された子タスクでは、チェーンを正規のネイティブ ChatGPT ターゲットと、`allowEncryptedV2AgentTasks: true` で明示的に信頼された直接のキー認証 Responses ルートに制限します。暗号化されたペイロードを処理できる対象がない場合、読み取り不可能な暗号文を別の場所へ送らず、リクエストは失敗します。コンボは引き続き正規のネイティブ対象だけを使用します。 ```json { diff --git a/docs-site/src/content/docs/ja/reference/proxy-formats.md b/docs-site/src/content/docs/ja/reference/proxy-formats.md index aaff91eb9f..93c2be4904 100644 --- a/docs-site/src/content/docs/ja/reference/proxy-formats.md +++ b/docs-site/src/content/docs/ja/reference/proxy-formats.md @@ -221,7 +221,7 @@ Responses-family および Chat リクエストは、プロバイダーまたは | 401 | `authentication_error` |必要なプロキシ アドミッション資格情報が見つからないか無効です。 | 403 | `origin_rejected` | Responses/OpenAI データプレーン リクエストまたは WebSocket アップグレードが、許可されていないオリジンから送信されました。 | 503 | `combo_unavailable` |選択したコンボ内のすべてのターゲットは使用不可、クールダウン中、無効、またはその他の理由で不適格です。 -| 400 | `unreadable_encrypted_agent_task` |暗号化された v2 ワーカー タスクには、それを使用できる適格なネイティブ ChatGPT ターゲットがありません。 +| 400 | `unreadable_encrypted_agent_task` | 暗号化された v2 ワーカー タスクには、それを処理できる正規の ChatGPT ターゲットも明示的に信頼された Responses ターゲットもありません。 | | 426 | `upgrade_required` |応答 WebSocket トランスポートが無効になっているか、アップグレードが失敗しました。 HTTP を使用する | Anthropic オリジンの失敗は Anthropic のエラー エンベロープでレンダリングされるため、オリジンの拒否は OpenAI スタイルの `origin_rejected` 本体ではなく、その方言上の 403 `permission_error` になります。 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 6b8f0064a0..5baf9853ea 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 @@ -72,7 +72,7 @@ v1에서는 opencodex가 `max` 또는 `ultra` 추론 강도에서만 업스트 중복 모델 id는 첫 번째 출현을 유지한 채 제거합니다. 선택 과정에서 opencodex는 비활성화된 후보, 라우팅 불가 후보, 비활성화된 프로바이더가 받쳐주는 후보, unhealthy로 표시된 후보, cooldown 중인 후보, 사용할 수 있는 pooled Codex 계정이 없는 후보, 또는 설정된 quota 임계치를 넘는 후보를 건너뜁니다. 가용성 프로브는 기본값 60초인 `subagentModelFallbackPollMs` 동안 캐시됩니다. -폴백이 호환되지 않는 암호화 작업을 읽을 수 있게 만들어 주지는 않습니다. 자식 작업이 ChatGPT용으로 암호화되어 있으면, 체인 앞쪽에 외부 모델이 있더라도 선택은 정규 네이티브 ChatGPT 대상만 허용됩니다. +폴백이 호환되지 않는 암호화 작업을 읽을 수 있게 만들어 주지는 않습니다. 자식 작업이 ChatGPT용으로 암호화되어 있으면, 체인 앞쪽에 다른 외부 모델이 있더라도 정규 네이티브 ChatGPT 대상과 `allowEncryptedV2AgentTasks: true`로 명시적으로 신뢰한 직접 키 인증 Responses 라우트만 선택합니다. 콤보는 계속 정규 네이티브 대상만 사용합니다. ## 암호화된 v2 작업 전달 @@ -80,7 +80,7 @@ Codex는 v2 네이티브→라우팅 자식 작업을 백엔드 암호화된 `en opencodex는 읽을 수 없거나 빈 작업을 그대로 넘기지 않고 안전하게 실패합니다. -- 비네이티브 직접 라우팅은 HTTP 400과 `error.code = "unreadable_encrypted_agent_task"`를 반환하며, 암호문을 에코하지 않습니다. +- 비네이티브 직접 라우팅은 키 인증 Responses 프로바이더가 `allowEncryptedV2AgentTasks: true`로 명시적으로 허용한 경우가 아니면 HTTP 400과 `error.code = "unreadable_encrypted_agent_task"`를 반환하며, 암호문을 에코하지 않습니다. - 콤보는 해당 작업에 대해 재시도를 포함해 정규 네이티브 ChatGPT 대상만 고려합니다. 사용할 수 있는 대상이 없으면 같은 400 오류를 반환합니다. - 읽을 수 있는 평문 작업은 정상 라우트와 폴백 동작을 그대로 유지합니다. diff --git a/docs-site/src/content/docs/ko/reference/configuration/agents.md b/docs-site/src/content/docs/ko/reference/configuration/agents.md index 47589fb3cc..013fa962e3 100644 --- a/docs-site/src/content/docs/ko/reference/configuration/agents.md +++ b/docs-site/src/content/docs/ko/reference/configuration/agents.md @@ -53,7 +53,7 @@ V1 안내는 `max` 또는 `ultra`에서만 선제 텍스트로 제공됩니다. 거부하고 역할을 건너뜁니다 (#1190). TOML의 기존 `model_fallback` 줄은 하위 호환성을 위해 계속 읽히지만 `ocx doctor`가 이를 표시합니다. -opencodex는 비활성, 라우팅 불가, 비정상, 쿨다운 중, 또는 할당량 임계값에 걸린 후보를 건너뜁니다. 사용 가능성 스냅샷은 `subagentModelFallbackPollMs` 동안 캐시됩니다. 암호화된 하위 작업은 체인을 정규 네이티브 ChatGPT 대상으로만 제한할 수 있습니다. 어떤 대상도 암호화된 페이로드를 읽을 수 없으면, 읽을 수 없는 암호문을 다른 곳으로 라우팅하는 대신 요청이 실패합니다. +opencodex는 비활성, 라우팅 불가, 비정상, 쿨다운 중, 또는 할당량 임계값에 걸린 후보를 건너뜁니다. 사용 가능성 스냅샷은 `subagentModelFallbackPollMs` 동안 캐시됩니다. 암호화된 하위 작업은 정규 네이티브 ChatGPT 대상과 `allowEncryptedV2AgentTasks: true`로 명시적으로 신뢰한 직접 키 인증 Responses 라우트만 후보로 사용합니다. 암호화된 페이로드를 처리할 수 있는 대상이 없으면 읽을 수 없는 암호문을 다른 곳으로 보내지 않고 요청이 실패합니다. 콤보는 계속 정규 네이티브 대상만 사용합니다. ```json { diff --git a/docs-site/src/content/docs/ko/reference/proxy-formats.md b/docs-site/src/content/docs/ko/reference/proxy-formats.md index b5b9d22d55..a3b82e4f63 100644 --- a/docs-site/src/content/docs/ko/reference/proxy-formats.md +++ b/docs-site/src/content/docs/ko/reference/proxy-formats.md @@ -289,7 +289,7 @@ data-plane key는 management credential이 아닙니다. management API는 별 | 401 | `authentication_error` | 필요한 프록시 admission credential이 없거나 유효하지 않습니다 | | 403 | `origin_rejected` | Responses/OpenAI data-plane 요청 또는 WebSocket 업그레이드가 허용되지 않은 origin에서 들어왔습니다 | | 503 | `combo_unavailable` | 선택한 combo의 모든 대상이 사용할 수 없거나, cooldown 중이거나, 비활성화되어 있거나, 다른 이유로 부적합합니다 | -| 400 | `unreadable_encrypted_agent_task` | 암호화된 v2 worker task를 소비할 수 있는 적격 네이티브 ChatGPT 대상이 없습니다 | +| 400 | `unreadable_encrypted_agent_task` | 암호화된 v2 worker task를 처리할 수 있는 정규 ChatGPT 대상이나 명시적으로 신뢰한 Responses 대상이 없습니다 | | 426 | `upgrade_required` | Responses WebSocket transport가 비활성화되어 있거나 업그레이드에 실패했습니다. HTTP를 사용하십시오 | Anthropic-origin 실패는 Anthropic의 error envelope로 렌더링됩니다. 따라서 해당 방언에서 origin 거부는 diff --git a/docs-site/src/content/docs/reference/configuration/agents.md b/docs-site/src/content/docs/reference/configuration/agents.md index 76e0a23927..108c497a5d 100644 --- a/docs-site/src/content/docs/reference/configuration/agents.md +++ b/docs-site/src/content/docs/reference/configuration/agents.md @@ -100,9 +100,11 @@ field and skip the role (#1190). A legacy `model_fallback` line in the TOML is s read for backwards compatibility, but `ocx doctor` flags it. opencodex skips disabled, unroutable, unhealthy, cooling-down, or quota-threshold candidates. The -availability snapshot is cached for `subagentModelFallbackPollMs`. Encrypted child tasks can restrict -the chain to canonical native ChatGPT targets; if none can read the encrypted payload, the request -fails instead of routing unreadable ciphertext elsewhere. +availability snapshot is cached for `subagentModelFallbackPollMs`. Encrypted child tasks restrict +the chain to canonical native ChatGPT targets plus direct key-auth Responses routes explicitly +trusted with `allowEncryptedV2AgentTasks: true`; if none can consume the encrypted payload, the +request fails instead of routing unreadable ciphertext elsewhere. Combo routing remains +canonical-native-only. ```json { diff --git a/docs-site/src/content/docs/reference/proxy-formats.md b/docs-site/src/content/docs/reference/proxy-formats.md index 3794f4c836..60c74adb4a 100644 --- a/docs-site/src/content/docs/reference/proxy-formats.md +++ b/docs-site/src/content/docs/reference/proxy-formats.md @@ -356,7 +356,7 @@ Errors use the client dialect's envelope where needed, but these status/code mea | 401 | `authentication_error` | A required proxy admission credential is missing or invalid | | 403 | `origin_rejected` | A Responses/OpenAI data-plane request or WebSocket upgrade came from a disallowed origin | | 503 | `combo_unavailable` | Every target in the selected combo is unavailable, in cooldown, disabled, or otherwise ineligible | -| 400 | `unreadable_encrypted_agent_task` | An encrypted v2 worker task has no eligible native ChatGPT target that can consume it | +| 400 | `unreadable_encrypted_agent_task` | An encrypted v2 worker task has no eligible canonical ChatGPT or explicitly trusted Responses target that can consume it | | 426 | `upgrade_required` | The Responses WebSocket transport is disabled or the upgrade failed; use HTTP | Anthropic-origin failures are rendered in Anthropic's error envelope, so the origin rejection is a 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 8b6e7d504e..d8cf873514 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 @@ -111,8 +111,9 @@ opencodex по-прежнему читает устаревшую строку ` `subagentModelFallbackPollMs` (по умолчанию 60 секунд). Fallback не делает несовместимые encrypted task читаемыми. Когда задача потомка зашифрована для -ChatGPT, выбор ограничивается каноническими нативными целями ChatGPT, даже если внешняя модель -появляется раньше в цепочке. +ChatGPT, выбор ограничивается каноническими нативными целями ChatGPT и прямыми key-auth +Responses-маршрутами, явно доверенными через `allowEncryptedV2AgentTasks: true`, даже если другая +внешняя модель появляется раньше в цепочке. Combo по-прежнему использует только нативные цели. ## Доставка шифрованных задач v2 @@ -123,7 +124,8 @@ Codex может отправить задачу child v2 из native-to-routed opencodex завершаетcя безопасно и не пересылает пустую или нечитаемую задачу: - Прямой не-нативный маршрут возвращает HTTP 400 с - `error.code = "unreadable_encrypted_agent_task"` и не отражает ciphertext назад. + `error.code = "unreadable_encrypted_agent_task"` и не отражает ciphertext назад, если его + key-auth Responses-провайдер явно не включил `allowEncryptedV2AgentTasks: true`. - Combo для такой задачи рассматривает только канонические нативные цели ChatGPT, включая retry. Если ни одной подходящей цели нет, возвращается тот же HTTP 400. - Читаемая plaintext-задача сохраняет обычное поведение маршрутизации и fallback. diff --git a/docs-site/src/content/docs/ru/reference/configuration/agents.md b/docs-site/src/content/docs/ru/reference/configuration/agents.md index 4febe3254f..7c9338beae 100644 --- a/docs-site/src/content/docs/ru/reference/configuration/agents.md +++ b/docs-site/src/content/docs/ru/reference/configuration/agents.md @@ -80,9 +80,11 @@ user-owned target field'ы считаются конфликтом и сохра opencodex пропускает кандидатов, которые отключены, не маршрутизируются, unhealthy, находятся в cooldown либо уже достигли порога quota. Availability-снимок кэшируется на -`subagentModelFallbackPollMs`. Шифрованные child-task'и могут ограничить цепочку каноническими -native ChatGPT-target'ами; если ни одна из них не может прочитать encrypted payload, запрос -завершается ошибкой вместо отправки нечитаемого ciphertext наружу. +`subagentModelFallbackPollMs`. Для шифрованных child-task'ов цепочка ограничена каноническими +native ChatGPT-target'ами и прямыми key-auth Responses-маршрутами, явно доверенными через +`allowEncryptedV2AgentTasks: true`. Если ни один из них не может обработать encrypted payload, +запрос завершается ошибкой вместо отправки нечитаемого ciphertext наружу. Combo по-прежнему +использует только канонические native-цели. ```json { diff --git a/docs-site/src/content/docs/ru/reference/proxy-formats.md b/docs-site/src/content/docs/ru/reference/proxy-formats.md index 5d0cd6b98a..f7a61f41b2 100644 --- a/docs-site/src/content/docs/ru/reference/proxy-formats.md +++ b/docs-site/src/content/docs/ru/reference/proxy-formats.md @@ -290,7 +290,7 @@ Direct, поэтому remote proxy key здесь обязан идти чер | 401 | `authentication_error` | Отсутствует обязательный credential для proxy-admission или он неверен | | 403 | `origin_rejected` | Data-plane запрос или WebSocket-upgrade Responses/OpenAI пришёл с запрещённого origin | | 503 | `combo_unavailable` | Все цели выбранной combo недоступны, в cooldown, отключены или иным образом не подходят | -| 400 | `unreadable_encrypted_agent_task` | У шифрованной задачи воркера v2 нет подходящей нативной цели ChatGPT, способной её прочитать | +| 400 | `unreadable_encrypted_agent_task` | У шифрованной задачи воркера v2 нет ни подходящей канонической цели ChatGPT, ни явно доверенной цели Responses, способной её обработать | | 426 | `upgrade_required` | Транспорт Responses WebSocket выключен или upgrade не удался; используйте HTTP | Сбои, пришедшие с Anthropic-side, отрисовываются в error envelope Anthropic, поэтому отклонение 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 04e6859e15..a4f919e420 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 @@ -133,8 +133,10 @@ probları `subagentModelFallbackPollMs` (varsayılan olarak 60 saniye) boyunca önbelleğe alınır. Geri dönüş, uyumsuz şifrelenmiş görevleri okunabilir kılmaz. Çocuk görevi -ChatGPT için şifrelendiğinde, zincirde daha önce harici bir model görünse bile -seçim kurallı yerel ChatGPT hedefleriyle sınırlandırılır. +ChatGPT için şifrelendiğinde, zincirde daha önce başka bir harici model görünse +bile seçim kurallı yerel ChatGPT hedefleriyle ve +`allowEncryptedV2AgentTasks: true` kullanılarak açıkça güvenilen doğrudan anahtar kimlik doğrulamalı Responses +rotalarıyla sınırlıdır. Kombolar yalnızca kurallı yerel hedefleri kullanmaya devam eder. ## Şifrelenmiş v2 görev teslimi @@ -146,9 +148,9 @@ bilinen [#92 sınırlamasıdır](https://github.com/lidge-jun/opencodex/issues/9 opencodex boş veya okunamayan bir görevi iletmek yerine güvenli bir şekilde başarısız olur: -- Doğrudan yerel olmayan bir rota `error.code = - "unreadable_encrypted_agent_task"` ile HTTP 400 döndürür ve şifreli metni - yankılamaz. +- Doğrudan yerel olmayan bir rota, anahtar kimlik doğrulamalı Responses sağlayıcısı + `allowEncryptedV2AgentTasks: true` ile açıkça etkinleştirilmedikçe `error.code = + "unreadable_encrypted_agent_task"` ile HTTP 400 döndürür ve şifreli metni yankılamaz. - Bir kombo, yeniden denemeler de dahil olmak üzere bu görev için yalnızca kurallı yerel ChatGPT hedeflerini değerlendirir. Hiçbiri yoksa aynı 400 hatasını döndürür. @@ -315,5 +317,3 @@ sabitler. Model bağlam sınırı alt ajan modundan bağımsızdır. Modeller sayfasında yapılandırın; yerel OpenAI modelleri gerçek bağlam pencerelerini korur. - - diff --git a/docs-site/src/content/docs/tr/reference/configuration/agents.md b/docs-site/src/content/docs/tr/reference/configuration/agents.md index 8fa28a22af..4e48b930ab 100644 --- a/docs-site/src/content/docs/tr/reference/configuration/agents.md +++ b/docs-site/src/content/docs/tr/reference/configuration/agents.md @@ -118,9 +118,11 @@ için hala okunur, ancak `ocx doctor` bunu bayraklar. opencodex devre dışı bırakılmış, yönlendirilemez, sağlıksız, soğumada olan veya kota eşiği adaylarını atlar. Kullanılabilirlik anlık görüntüsü `subagentModelFallbackPollMs` boyunca önbelleğe alınır. Şifrelenmiş çocuk -görevleri zinciri kurallı yerel ChatGPT hedefleriyle kısıtlayabilir; hiçbiri -şifrelenmiş yükü okuyamazsa istek okunamayan şifreli metni başka bir yere -yönlendirmek yerine başarısız olur. +görevlerinde zincir, kurallı yerel ChatGPT hedefleriyle ve +`allowEncryptedV2AgentTasks: true` kullanılarak açıkça güvenilen doğrudan anahtar +kimlik doğrulamalı Responses rotalarıyla sınırlıdır. Hiçbiri şifrelenmiş yükü +işleyemezse istek, okunamayan şifreli metni başka bir yere yönlendirmek yerine +başarısız olur. Kombolar yalnızca kurallı yerel hedefleri kullanmaya devam eder. ```json { @@ -247,4 +249,3 @@ ile `xhigh` arasını sunar. v1, varsayılan ve v2 davranışının yeni başlayanlara yönelik açıklaması için [Alt ajan yüzeyleri](/tr/guides/sub-agent-surface/) sayfasına bakın. - diff --git a/docs-site/src/content/docs/tr/reference/proxy-formats.md b/docs-site/src/content/docs/tr/reference/proxy-formats.md index 3258c31e39..9c647f436b 100644 --- a/docs-site/src/content/docs/tr/reference/proxy-formats.md +++ b/docs-site/src/content/docs/tr/reference/proxy-formats.md @@ -324,7 +324,7 @@ anlamları kararlıdır: | 401 | `authentication_error` | Gerekli bir proxy kabul kimlik bilgisi eksik veya geçersiz | | 403 | `origin_rejected` | Bir Responses/OpenAI veri düzlemi isteği veya WebSocket yükseltmesi izin verilmeyen bir kaynaktan geldi | | 503 | `combo_unavailable` | Seçilen komdodaki her hedef kullanılamaz, soğumada, devre dışı veya başka şekilde uygun değil | -| 400 | `unreadable_encrypted_agent_task` | Şifrelenmiş bir v2 çalışan görevinin onu tüketebilecek uygun yerel bir ChatGPT hedefi yok | +| 400 | `unreadable_encrypted_agent_task` | Şifrelenmiş bir v2 çalışan görevinin onu işleyebilecek uygun kurallı ChatGPT veya açıkça güvenilen Responses hedefi yok | | 426 | `upgrade_required` | Responses WebSocket aktarımı devre dışı bırakıldı veya yükseltme başarısız oldu; HTTP kullanın | Anthropic kaynaklı arızalar Anthropic'in hata zarfında işlenir, bu nedenle @@ -347,4 +347,3 @@ okuyamazsa opencodex bu sağlayıcıya okunamayan baytlar göndermek yerine `unreadable_encrypted_agent_task` ile başarısız olur. Çalışan görevleri etrafındaki istemci davranışı için [Alt Ajan Arayüzü](/tr/guides/sub-agent-surface/) sayfasına bakın. - 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 3882d15c9a..8471ee9f38 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 @@ -72,7 +72,7 @@ per-role fallback 链应该放在 opencodex 配置里,而不是 `$CODEX_HOME/a 重复的模型 id 会在保留第一次出现的前提下移除。在选择过程中,opencodex 会跳过已禁用、不可路由、由已禁用 provider 支撑、标记为 unhealthy、处于 cooldown、没有可用 pooled Codex 账户,或者超出配置配额阈值的候选项。可用性探测会缓存 `subagentModelFallbackPollMs` 的时长,默认 60 秒。 -fallback 不会让不兼容的加密任务变得可读。当子任务为 ChatGPT 加密时,即使链中更靠前出现了外部模型,选择也只会限制在规范的原生 ChatGPT 目标上。 +fallback 不会让不兼容的加密任务变得可读。当子任务为 ChatGPT 加密时,即使链中更靠前出现了其他外部模型,选择也只会限制在规范的原生 ChatGPT 目标,以及通过 `allowEncryptedV2AgentTasks: true` 明确信任的直接密钥认证 Responses 路由。combo 仍然只使用规范的原生目标。 ## 加密的 v2 任务传递 @@ -80,7 +80,7 @@ Codex 只能把 v2 原生到路由的子任务作为后端加密的 `encrypted_c opencodex 会安全失败,而不是转发空任务或不可读任务: -- 直接的非原生路由会返回 HTTP 400,并且 `error.code = "unreadable_encrypted_agent_task"`,不会回显密文。 +- 直接的非原生路由会返回 HTTP 400,并且 `error.code = "unreadable_encrypted_agent_task"`,不会回显密文;但其密钥认证 Responses provider 通过 `allowEncryptedV2AgentTasks: true` 明确选择加入时除外。 - 对于该任务,combo 只会考虑规范的原生 ChatGPT 目标,包括重试。如果没有可用目标,则返回相同的 400 错误。 - 可读的明文任务会保持正常的路由和 fallback 行为。 diff --git a/docs-site/src/content/docs/zh-cn/reference/configuration/agents.md b/docs-site/src/content/docs/zh-cn/reference/configuration/agents.md index 0afa4603fe..7a1832cdaf 100644 --- a/docs-site/src/content/docs/zh-cn/reference/configuration/agents.md +++ b/docs-site/src/content/docs/zh-cn/reference/configuration/agents.md @@ -52,7 +52,7 @@ per-role fallback 链必须放在 opencodex 配置里。把 `model_fallback` 写 `$CODEX_HOME/agents/*.toml` 会让 Codex 0.146+ 把整个角色文件当作未知字段拒绝并跳过该角色 (#1190)。TOML 中的旧版 `model_fallback` 仍会被读取以保持向后兼容,但 `ocx doctor` 会标记它。 -opencodex 会跳过已禁用、不可路由、不健康、处于冷却中,或已达到配额阈值的候选项。可用性快照会在 `subagentModelFallbackPollMs` 期间缓存。加密的子任务可以把链限制为规范的原生 ChatGPT 目标;如果没有任何目标能读取加密载荷,请求就会失败,而不是把不可读的密文路由到别处。 +opencodex 会跳过已禁用、不可路由、不健康、处于冷却中,或已达到配额阈值的候选项。可用性快照会在 `subagentModelFallbackPollMs` 期间缓存。对于加密的子任务,候选链只包含规范的原生 ChatGPT 目标,以及通过 `allowEncryptedV2AgentTasks: true` 明确信任的直接密钥认证 Responses 路由。如果没有任何目标能处理加密载荷,请求就会失败,而不是把不可读的密文路由到别处。combo 仍然只使用规范的原生目标。 ```json { diff --git a/docs-site/src/content/docs/zh-cn/reference/proxy-formats.md b/docs-site/src/content/docs/zh-cn/reference/proxy-formats.md index 52f255091b..d087650071 100644 --- a/docs-site/src/content/docs/zh-cn/reference/proxy-formats.md +++ b/docs-site/src/content/docs/zh-cn/reference/proxy-formats.md @@ -242,7 +242,7 @@ Responses 家族和 Chat 请求会把 `Authorization` 留给提供方或 Codex D | 401 | `authentication_error` | 所需的代理准入凭证缺失或无效 | | 403 | `origin_rejected` | 一条 Responses/OpenAI 数据平面请求或 WebSocket 升级来自不允许的 origin | | 503 | `combo_unavailable` | 所选 combo 中的所有目标都不可用、处于冷却、已禁用或以其他方式不具备资格 | -| 400 | `unreadable_encrypted_agent_task` | 一个加密的 v2 worker task 没有任何可消费它的合格原生 ChatGPT 目标 | +| 400 | `unreadable_encrypted_agent_task` | 一个加密的 v2 worker task 没有任何可处理它的合格规范 ChatGPT 目标或明确信任的 Responses 目标 | | 426 | `upgrade_required` | Responses WebSocket 传输被禁用,或升级失败;请改用 HTTP | Anthropic 来源的失败会以 Anthropic 的错误封装呈现,因此该方言中的 origin 拒绝会是 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 7cdb8fb49d..ca74fe7dd6 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 @@ -6,7 +6,7 @@ description: 全域控制 Codex 在所有模型上生成和管理子代理的方 opencodex 允許你為目錄中的所有模型選擇多代理協作介面。儀表板和 Models 頁面中的 **Sub-agent** 開關會全域控制這一設定。 :::note -在 v2 介面(`multi_agent_v2`)上,子代理**預設**繼承父會話的模型:`fork_turns` 預設為 `all`,而全量歷史 fork 會拒絕覆蓋。自 v2.7.2 起,opencodex 注入的指引會教模型如何打破繼承 —— 將 `fork_turns` 設為 `"none"`(或如 `"3"` 的部分 fork)的 `spawn_agent` 呼叫可以傳入 `model` / `reasoning_effort` 引數;即使公開的工具 schema 中看不到這些引數,Codex 執行環境也會解析並應用。已知傳輸限制:當**原生**父代理 spawn 一個路由到**非原生** provider 的子代理時,Codex 用戶端可能只以後端加密的 `encrypted_content` 傳送 `NEW_TASK` 載荷([#92](https://github.com/lidge-jun/opencodex/issues/92))。opencodex 不會把這種無法讀取的任務轉發給外部 provider:直接路由會回傳 HTTP 400 和錯誤碼 `unreadable_encrypted_agent_task`;組合路由則會跳過無法解密的目標,並在存在可用目標時選擇規範的原生 ChatGPT 目標。恢復方法:異構 provider 委派改用 v1、選擇原生 ChatGPT 子代理,或將任務重新作為明文 v2 `agent_message` 內容傳送。另有預設停用的實驗性 `agentTaskRecovery`;它會增加 ChatGPT 配額用量與延遲,且依賴非公開後端行為。 +在 v2 介面(`multi_agent_v2`)上,子代理**預設**繼承父會話的模型:`fork_turns` 預設為 `all`,而全量歷史 fork 會拒絕覆蓋。自 v2.7.2 起,opencodex 注入的指引會教模型如何打破繼承 —— 將 `fork_turns` 設為 `"none"`(或如 `"3"` 的部分 fork)的 `spawn_agent` 呼叫可以傳入 `model` / `reasoning_effort` 引數;即使公開的工具 schema 中看不到這些引數,Codex 執行環境也會解析並應用。已知傳輸限制:當**原生**父代理 spawn 一個路由到**非原生** provider 的子代理時,Codex 用戶端可能只以後端加密的 `encrypted_content` 傳送 `NEW_TASK` 載荷([#92](https://github.com/lidge-jun/opencodex/issues/92))。opencodex 不會把這種無法讀取的任務轉發給任意外部 provider:直接路由通常回傳 HTTP 400 和錯誤碼 `unreadable_encrypted_agent_task`,但以 `allowEncryptedV2AgentTasks: true` 明確信任的直接金鑰驗證 Responses 路由可以原樣接收;組合路由仍會跳過無法解密的目標,並在存在可用目標時選擇規範的原生 ChatGPT 目標。恢復方法:異構 provider 委派改用 v1、選擇原生 ChatGPT 子代理、使用明確信任的 Responses relay,或將任務重新作為明文 v2 `agent_message` 內容傳送。另有預設停用的實驗性 `agentTaskRecovery`;它會增加 ChatGPT 配額用量與延遲,且依賴非公開後端行為。 ::: ## What sub-agents are @@ -21,7 +21,7 @@ opencodex 允許你為目錄中的所有模型選擇多代理協作介面。儀 | --- | --- | --- | | **v1** | `multi_agent_v1` | 使用經典的名稱空間代理工具,以及 `send_input` / `close_agent` / `resume_agent`。`spawn_agent` 的模型覆蓋可以在其他模型上生成子代理。 | | **base**(預設) | 上游固定值 | 恢復上游模型的固定值:gpt-5.6-sol 和 gpt-5.6-terra 使用 v2,gpt-5.6-luna 使用 v1;未固定的模型遵循 Codex 的 `multi_agent_v2` 功能開關。生成行為取決於該模型最終使用的介面。 | -| **v2** | `multi_agent_v2` | 使用扁平的 `spawn_agent` 工具、併發會話,以及 `send_message` / `followup_task` / `wait_agent` / `interrupt_agent`。全量歷史 fork 時子代理繼承父模型;`fork_turns: "none"`(或部分 fork)時接受 `model` / `reasoning_effort` 覆蓋。如果原生→路由子代理只收到後端加密的任務內容,外部路由會回傳 `unreadable_encrypted_agent_task`;混合組合會優先選擇可解密的原生目標([#92](https://github.com/lidge-jun/opencodex/issues/92))。 | +| **v2** | `multi_agent_v2` | 使用扁平的 `spawn_agent` 工具、併發會話,以及 `send_message` / `followup_task` / `wait_agent` / `interrupt_agent`。全量歷史 fork 時子代理繼承父模型;`fork_turns: "none"`(或部分 fork)時接受 `model` / `reasoning_effort` 覆蓋。如果原生→路由子代理只收到後端加密的任務內容,未明確信任的外部路由會回傳 `unreadable_encrypted_agent_task`;明確信任的直接金鑰驗證 Responses 路由可以原樣接收,而混合組合仍優先選擇可解密的原生目標([#92](https://github.com/lidge-jun/opencodex/issues/92))。 | ## 運作原理 @@ -87,8 +87,9 @@ opencodex 仍可為了向後相容從 TOML 讀取舊版 `model_fallback` 列, 停用 provider 支撐、標記為不健康、在冷卻中、缺少可用 Pool 化 Codex 帳號,或超過設定配額閾值的 候選。可用性探測會快取 `subagentModelFallbackPollMs`(預設 60 秒)。 -Fallback 不能讓不相容的加密任務變成可讀。當子任務是為 ChatGPT 加密時,即使外部模型在鏈中出現得 -更早,選擇也會限制在規範的原生 ChatGPT 目標。 +Fallback 不能讓不相容的加密任務變成可讀。當子任務是為 ChatGPT 加密時,即使其他外部模型在鏈中 +出現得更早,選擇也只會包含規範的原生 ChatGPT 目標,以及透過 +`allowEncryptedV2AgentTasks: true` 明確信任的直接金鑰驗證 Responses 路由。組合仍只使用規範的原生目標。 ## 加密的 v2 任務傳輸 @@ -99,7 +100,7 @@ Codex 可能只以後端加密的 `encrypted_content` 傳送 v2 原生→路由 opencodex 會安全失敗,而不是轉發空或無法讀取的任務: - 直接的非原生路由回傳 HTTP 400,帶有 `error.code = "unreadable_encrypted_agent_task"`,且不會回顯 - 密文。 + 密文;但其金鑰驗證 Responses provider 透過 `allowEncryptedV2AgentTasks: true` 明確選擇加入時除外。 - 組合只會為該任務考慮規範的原生 ChatGPT 目標,包括重試。若沒有可用目標,回傳相同的 400。 - 可讀取的明文任務保持正常的路由與 fallback 行為。 @@ -117,7 +118,7 @@ opencodex 會安全失敗,而不是轉發空或無法讀取的任務: - **Dashboard** → 第一個狀態單元:選擇 **v1**、**base** 或 **v2**。 - **Models** 頁面 → 使用頂部的分段控制元件。 - 兩個頁面都有 **?** 按鈕,可開啟幫助彈窗並返回本文。 -- **Dashboard** → **子代理委託**:選擇首選模型和可選的推理強度。在 v2 上,注入的指引會要求以 `fork_turns: "none"` 生成,使模型覆蓋得以應用。如果原生→路由子代理只收到加密任務內容,請使用原生目標或 v1;僅外部目標的傳輸現在會明確回傳 `unreadable_encrypted_agent_task`([#92](https://github.com/lidge-jun/opencodex/issues/92))。 +- **Dashboard** → **子代理委託**:選擇首選模型和可選的推理強度。在 v2 上,注入的指引會要求以 `fork_turns: "none"` 生成,使模型覆蓋得以應用。如果原生→路由子代理只收到加密任務內容,請使用原生目標、v1,或明確信任的直接金鑰驗證 Responses relay;其他僅外部目標的傳輸會明確回傳 `unreadable_encrypted_agent_task`([#92](https://github.com/lidge-jun/opencodex/issues/92))。 ### CLI diff --git a/docs-site/src/content/docs/zh-tw/reference/configuration/agents.md b/docs-site/src/content/docs/zh-tw/reference/configuration/agents.md index c909917679..d95b5e1eb0 100644 --- a/docs-site/src/content/docs/zh-tw/reference/configuration/agents.md +++ b/docs-site/src/content/docs/zh-tw/reference/configuration/agents.md @@ -47,7 +47,7 @@ V1 指引僅在 `max` 或 `ultra` 時為主動文字。V2 僅在存在偏好模 2. 來自 `$CODEX_HOME/agents/*.toml` 的角色級 `model_fallback`;然後 3. 全域 `subagentModelFallback` 項目。 -opencodex 會跳過已停用、不可路由、不健康、冷卻中或達到配額閾值的候選項。可用性快取保存 `subagentModelFallbackPollMs`。加密的子任務可將鏈限制為規範的原生 ChatGPT 目標;若無任何目標可讀取加密 payload,請求會失敗,而不會將無法讀取的密文路由到別處。 +opencodex 會跳過已停用、不可路由、不健康、冷卻中或達到配額閾值的候選項。可用性快取保存 `subagentModelFallbackPollMs`。對於加密的子任務,候選鏈僅包含規範的原生 ChatGPT 目標,以及透過 `allowEncryptedV2AgentTasks: true` 明確信任的直接金鑰驗證 Responses 路由。若無任何目標可處理加密 payload,請求會失敗,而不會將無法讀取的密文路由到別處。組合仍只使用規範的原生目標。 ```json { diff --git a/docs-site/src/content/docs/zh-tw/reference/proxy-formats.md b/docs-site/src/content/docs/zh-tw/reference/proxy-formats.md index 5587b88ae2..e77a327776 100644 --- a/docs-site/src/content/docs/zh-tw/reference/proxy-formats.md +++ b/docs-site/src/content/docs/zh-tw/reference/proxy-formats.md @@ -221,7 +221,7 @@ Data-plane 金鑰不是管理憑證。管理 API 使用獨立的管理秘密; | 401 | `authentication_error` | 必填的代理許可憑證缺失或無效 | | 403 | `origin_rejected` | Responses/OpenAI data-plane 請求或 WebSocket 升級來自不允許的來源 | | 503 | `combo_unavailable` | 所選組合中的每個目標都不可用、在冷卻中、停用或因其他原因不合格 | -| 400 | `unreadable_encrypted_agent_task` | 加密的 v2 worker task 沒有可消耗它的合格原生 ChatGPT 目標 | +| 400 | `unreadable_encrypted_agent_task` | 加密的 v2 worker task 沒有可處理它的合格規範 ChatGPT 目標或明確信任的 Responses 目標 | | 426 | `upgrade_required` | Responses WebSocket 傳輸被停用或升級失敗;請使用 HTTP | Anthropic 來源的失敗以 Anthropic 的錯誤封裝渲染,因此該方言上的來源拒絕是 403 `permission_error`,而非 OpenAI 風格的 `origin_rejected` body。 diff --git a/src/codex/subagent-model-fallback.ts b/src/codex/subagent-model-fallback.ts index 6ce9e6914b..c0bcdda15c 100644 --- a/src/codex/subagent-model-fallback.ts +++ b/src/codex/subagent-model-fallback.ts @@ -59,6 +59,8 @@ export type SubagentPoolAccountPreview = ( export type SubagentModelEligibleAccountIds = ( modelId: string | undefined, ) => ReadonlySet | undefined; +/** Additional resolved routes that a restricted fallback caller has independently approved. */ +export type SubagentFallbackRouteEligibility = (route: RouteResult) => boolean; let subagentQuotaPrimeForTests: SubagentQuotaPrimeFn | null = null; let quotaPrimeInFlight: Promise | null = null; @@ -364,13 +366,21 @@ export function selectAvailableSubagentModel( poolAccountPreview?: SubagentPoolAccountPreview, modelEligibleAccountIdsForModel?: SubagentModelEligibleAccountIds, resolvedChain?: readonly string[], + restrictedRouteEligible?: SubagentFallbackRouteEligibility, ): { model: string; rewritten: boolean; skipped: string[] } { const chain = resolvedChain ?? normalizedChain(primary, config, extraFallback, trailingFallback); const skipped: string[] = []; for (const candidate of chain) { if (nativeFallbackOnly) { const route = tryRouteFallbackModel(config, candidate); - if (!route || !isCanonicalOpenAiForwardProvider(route.provider)) { + if ( + !route + || route.combo !== undefined + || ( + !isCanonicalOpenAiForwardProvider(route.provider) + && restrictedRouteEligible?.(route) !== true + ) + ) { skipped.push(candidate); continue; } @@ -615,6 +625,7 @@ export function applySubagentModelFallback( poolAccountPreview?: SubagentPoolAccountPreview, modelEligibleAccountIdsForModel?: SubagentModelEligibleAccountIds, resolvedFallbackChain?: readonly string[] | null, + restrictedRouteEligible?: SubagentFallbackRouteEligibility, ): { from?: string; to?: string; skipped?: string[] } | null { if (!isThreadSpawnRequest(headers)) return null; const fallbackChain = resolvedFallbackChain === undefined @@ -633,6 +644,7 @@ export function applySubagentModelFallback( poolAccountPreview, modelEligibleAccountIdsForModel, fallbackChain, + restrictedRouteEligible, ); if (!selection.rewritten) return selection.skipped.length > 0 ? { from: parsed.modelId, to: parsed.modelId, skipped: selection.skipped } diff --git a/src/server/responses/core.ts b/src/server/responses/core.ts index 366074b49a..a1583788c7 100644 --- a/src/server/responses/core.ts +++ b/src/server/responses/core.ts @@ -1768,6 +1768,7 @@ function canPassThroughEncryptedV2AgentTask( route: RouteResult, inboundWire: InboundWire, ): boolean { + if (route.combo !== undefined) return false; const provider = route.provider; if ( inboundWire !== "responses" @@ -3082,6 +3083,7 @@ async function handleResponsesInner( subagentFallbackAccountPreview, subagentFallbackModelEligibleAccountIdsForModel, fallbackChain, + candidateRoute => canPassThroughEncryptedV2AgentTask(candidateRoute, inboundWire), ); if (fallback) { (logCtx as unknown as Record).subagentModelFallbackFrom = fallback.from; @@ -3251,7 +3253,7 @@ async function handleResponsesInner( const finalRouteCanPassThroughEncryptedTask = !options.comboAttempt && canPassThroughEncryptedV2AgentTask(route, inboundWire); if ( - !isCanonicalOpenAiForwardProvider(route.provider) + (route.combo !== undefined || !isCanonicalOpenAiForwardProvider(route.provider)) && !finalRouteCanPassThroughEncryptedTask && unreadableEncryptedAgentTask ) { diff --git a/tests/routing/subagent-model-fallback.test.ts b/tests/routing/subagent-model-fallback.test.ts index e3e2dd4551..cf255a3b93 100644 --- a/tests/routing/subagent-model-fallback.test.ts +++ b/tests/routing/subagent-model-fallback.test.ts @@ -872,6 +872,52 @@ test("the native-main drain sentinel covers the flagships without widening to gp }); }); + test("restricted fallback can admit an independently trusted resolved route", () => { + resetSubagentModelFallbackStateForTests(); + const config = cfg({ + providers: { + openai: { + adapter: "openai-responses", + baseUrl: "https://chatgpt.com/backend-api/codex", + authMode: "forward", + codexAccountMode: "direct", + }, + relay: { + adapter: "openai-responses", + baseUrl: "https://relay.example.test/v1", + authMode: "key", + apiKey: "test-relay-key", + }, + xai: { + adapter: "openai-chat", + baseUrl: "https://api.x.ai/v1", + authMode: "key", + apiKey: "test-xai-key", + }, + }, + subagentModelFallback: ["relay/gpt-5.5"], + }); + const selected = selectAvailableSubagentModel( + "xai/grok-4.5", + config, + [], + null, + Date.now(), + true, + undefined, + [], + undefined, + undefined, + undefined, + route => route.providerName === "relay", + ); + expect(selected).toEqual({ + model: "relay/gpt-5.5", + rewritten: true, + skipped: ["xai/grok-4.5"], + }); + }); + test("pool quota affects only candidates whose resolved route uses pool mode", () => { resetSubagentModelFallbackStateForTests(); updateAccountQuota("pool-a", 95, undefined, 20); diff --git a/tests/server/agent-task-recovery-combo.test.ts b/tests/server/agent-task-recovery-combo.test.ts index 5caa7f7691..0e6e22a590 100644 --- a/tests/server/agent-task-recovery-combo.test.ts +++ b/tests/server/agent-task-recovery-combo.test.ts @@ -201,6 +201,34 @@ describe("combo path encrypted agent task recovery", () => { expect(forwardedBodies[0]).not.toContain("capture_assignment"); }); + test("keeps fallback combo aliases out of direct encrypted dispatch", async () => { + const config = comboConfig([ + { provider: "relay", model: "relay-model" }, + { provider: "openai", model: "gpt-5.5" }, + ]); + delete config.agentTaskRecovery; + config.subagentModelFallback = ["combo/routed"]; + config.providers.relay = { + adapter: "openai-responses", + baseUrl: "https://relay.example.test/v1", + authMode: "key", + apiKey: "test-relay-key", + allowEncryptedV2AgentTasks: true, + }; + let fetchCalls = 0; + globalThis.fetch = (async () => { + fetchCalls += 1; + return providerResponse(); + }) as typeof fetch; + + const response = await post(config, "xai/grok-4.5", encryptedInput(), codexHeaders()); + const payload = await response.json() as { error?: { code?: string } }; + + expect(response.status).toBe(400); + expect(payload.error?.code).toBe("unreadable_encrypted_agent_task"); + expect(fetchCalls).toBe(0); + }); + test("keeps the canonical target bypass in a mixed combo without running recovery", async () => { const forwardedBodies: string[] = []; globalThis.fetch = (async (_input, init) => { diff --git a/tests/server/agent-task-recovery.test.ts b/tests/server/agent-task-recovery.test.ts index f1f11ae06b..5cc96793ce 100644 --- a/tests/server/agent-task-recovery.test.ts +++ b/tests/server/agent-task-recovery.test.ts @@ -182,6 +182,58 @@ describe("agent task recovery (opt-in, default off)", () => { } }); + test("encrypted fallback selection preserves an eligible trusted relay primary", async () => { + const config = routedConfig(); + config.subagentModelFallback = ["gpt-5.5"]; + config.providers.relay = { + adapter: "openai-responses", + baseUrl: "https://relay.example.test/v1", + authMode: "key", + apiKey: "test-relay-key", + allowEncryptedV2AgentTasks: true, + }; + const input = encryptedInput(); + const fetchedUrls: string[] = []; + let forwardedInput: unknown; + globalThis.fetch = (async (url, init) => { + fetchedUrls.push(String(url)); + forwardedInput = (JSON.parse(String(init?.body)) as { input?: unknown }).input; + return providerResponse(); + }) as typeof fetch; + + const response = await post(config, "relay/gpt-5.6-luna", input, codexHeaders()); + + expect(response.status).toBe(200); + expect(fetchedUrls).toEqual(["https://relay.example.test/v1/responses"]); + expect(forwardedInput).toEqual(input); + }); + + test("encrypted fallback selection can choose an eligible trusted relay candidate", async () => { + const config = routedConfig(); + config.subagentModelFallback = ["relay/gpt-5.5"]; + config.providers.relay = { + adapter: "openai-responses", + baseUrl: "https://relay.example.test/v1", + authMode: "key", + apiKey: "test-relay-key", + allowEncryptedV2AgentTasks: true, + }; + const input = encryptedInput(); + const fetchedUrls: string[] = []; + let forwardedInput: unknown; + globalThis.fetch = (async (url, init) => { + fetchedUrls.push(String(url)); + forwardedInput = (JSON.parse(String(init?.body)) as { input?: unknown }).input; + return providerResponse(); + }) as typeof fetch; + + const response = await post(config, "xai/grok-4.5", input, codexHeaders()); + + expect(response.status).toBe(200); + expect(fetchedUrls).toEqual(["https://relay.example.test/v1/responses"]); + expect(forwardedInput).toEqual(input); + }); + test.each([ ["OAuth authentication", { adapter: "openai-responses" as const, authMode: "oauth" as const }], ["a Chat Completions adapter", { adapter: "openai-chat" as const }], From f014d14cb2c23257400e214c1024542f6aef8dd1 Mon Sep 17 00:00:00 2001 From: Ingwannu Date: Sat, 5 Sep 2026 03:37:41 +0000 Subject: [PATCH 2/2] docs: align encrypted task trust translations --- .../src/content/docs/fr/guides/sub-agent-surface.md | 13 +++++++------ .../src/content/docs/fr/reference/proxy-formats.md | 2 +- .../src/content/docs/guides/sub-agent-surface.md | 7 ++++--- .../src/content/docs/ja/guides/sub-agent-surface.md | 7 +++---- .../src/content/docs/reference/proxy-formats.md | 2 +- .../src/content/docs/ru/reference/proxy-formats.md | 2 +- .../src/content/docs/tr/guides/sub-agent-surface.md | 13 +++++++------ .../src/content/docs/tr/reference/proxy-formats.md | 2 +- .../content/docs/zh-cn/guides/sub-agent-surface.md | 4 ++-- .../docs/zh-tw/reference/configuration/agents.md | 7 +++++-- 10 files changed, 32 insertions(+), 27 deletions(-) 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 46c88dcbf6..e9eaa5219c 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 @@ -128,16 +128,17 @@ 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 : -- Une route directe non native renvoie HTTP 400 avec - `error.code = "unreadable_encrypted_agent_task"` et ne fait pas écho au texte chiffré, sauf si - son fournisseur Responses à authentification par clé active explicitement `allowEncryptedV2AgentTasks: true`. +- Une route directe non native inéligible renvoie HTTP 400 avec + `error.code = "unreadable_encrypted_agent_task"` et ne fait pas écho au texte chiffré. Un + fournisseur Responses direct à authentification par clé qui active explicitement + `allowEncryptedV2AgentTasks: true` reçoit à la place le texte chiffré opaque et évite cette erreur. - Un combo considère uniquement les cibles ChatGPT natives canoniques pour cette tâche, y compris les tentatives. Si aucun est disponible, il renvoie la même erreur 400. - Une tâche lisible en texte clair conserve la route normale et le comportement de repli. -Les options de récupération consistent à sélectionner un enfant ChatGPT natif, à ajouter une cible ChatGPT native au combo, à utiliser -v1 pour la délégation de fournisseurs hétérogènes, ou renvoyer la tâche en texte brut v2 `agent_message` -contenu lorsque vous contrôlez l’appelant. +Les options de récupération consistent à sélectionner un enfant ChatGPT natif, à approuver explicitement un relais Responses direct à +authentification par clé capable de consommer la charge utile opaque, à ajouter une cible ChatGPT native au combo, à utiliser v1 pour la +délégation de fournisseurs hétérogènes, ou à renvoyer la tâche comme contenu `agent_message` v2 en texte brut lorsque vous contrôlez l’appelant. L’option expérimentale `agentTaskRecovery`, désactivée par défaut, peut récupérer cette forme précise de tâche native envoyée vers une route externe. Elle utilise un transfert Responses brut vers le point de diff --git a/docs-site/src/content/docs/fr/reference/proxy-formats.md b/docs-site/src/content/docs/fr/reference/proxy-formats.md index e8023fec3a..f224e61bd2 100644 --- a/docs-site/src/content/docs/fr/reference/proxy-formats.md +++ b/docs-site/src/content/docs/fr/reference/proxy-formats.md @@ -310,7 +310,7 @@ Les erreurs utilisent l'enveloppe du dialecte client lorsque cela est nécessair | 401 | `authentication_error` | Un identifiant requis pour l’admission au proxy est manquant ou invalide | | 403 | `origin_rejected` | Une demande de plan de données Réponses/OpenAI ou une mise à niveau WebSocket provient d'une origine non autorisée | | 503 | `combo_unavailable` | Chaque cible du combo sélectionné est indisponible, en temps de recharge, désactivée ou autrement inéligible | -| 400 | `unreadable_encrypted_agent_task` | Une tâche de travail v2 chiffrée n'a ni cible ChatGPT canonique ni cible Responses explicitement approuvée pouvant la consommer | +| 400 | `unreadable_encrypted_agent_task` | Une tâche de travail v2 chiffrée n’a ni cible ChatGPT canonique éligible ni cible Responses directe à authentification par clé explicitement approuvée avec `allowEncryptedV2AgentTasks: true` pouvant la consommer | | 426 | `upgrade_required` | Le transport Réponses WebSocket est désactivé ou la mise à niveau a échoué ; utiliser HTTP | Les échecs d'origine Anthropic sont restitués dans l'enveloppe d'erreur de Anthropic, donc le rejet d'origine est un 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 23ef2ad891..139c9be408 100644 --- a/docs-site/src/content/docs/guides/sub-agent-surface.md +++ b/docs-site/src/content/docs/guides/sub-agent-surface.md @@ -129,9 +129,10 @@ known [#92 limitation](https://github.com/lidge-jun/opencodex/issues/92). opencodex fails safely instead of forwarding an empty or unreadable task: -- A direct non-native route returns HTTP 400 with - `error.code = "unreadable_encrypted_agent_task"` and does not echo the ciphertext unless its - key-auth Responses provider explicitly opts in with `allowEncryptedV2AgentTasks: true`. +- An ineligible direct non-native route returns HTTP 400 with + `error.code = "unreadable_encrypted_agent_task"` and does not echo the ciphertext. An eligible + direct key-auth Responses provider that explicitly opts in with + `allowEncryptedV2AgentTasks: true` instead receives the opaque ciphertext and bypasses this error. - A combo considers only canonical native ChatGPT targets for that task, including retries. If none is available, it returns the same 400 error. - A readable plaintext task keeps the normal route and fallback behavior. 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 82f1331de5..d4dc59de4c 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 @@ -80,14 +80,13 @@ Codex は、v2 ネイティブからルーティングされた子タスクを opencodex は、空のタスクまたは読み取り不可能なタスクを転送するのではなく、安全に失敗します。 -- 直接の非ネイティブ ルートは HTTP 400 と -`error.code = "unreadable_encrypted_agent_task"` を返し、暗号文をエコーしません。ただし、 -キー認証 Responses プロバイダーが `allowEncryptedV2AgentTasks: true` を明示的に有効にした場合を除きます。 +- 対象外の直接非ネイティブルートは HTTP 400 と `error.code = "unreadable_encrypted_agent_task"` を返し、暗号文をエコーしません。 + `allowEncryptedV2AgentTasks: true` を明示的に有効にした対象の直接キー認証 Responses プロバイダーは、代わりに不透明な暗号文を受け取り、このエラーを回避します。 - コンボでは、再試行を含む、そのタスクの正規のネイティブ ChatGPT ターゲットのみが考慮されます。何もない場合 が利用可能な場合は、同じ 400 エラーが返されます。 - 読み取り可能なプレーンテキストのタスクは、通常のルートとフォールバック動作を維持します。 -回復オプションは、ネイティブ ChatGPT 子の選択、コンボへのネイティブ ChatGPT ターゲットの追加、異種プロバイダーの委任に v1 を使用する、または呼び出し元を制御するときにタスクをプレーンテキスト v2 `agent_message` コンテンツとして再送信することです。 +回復オプションは、ネイティブ ChatGPT 子の選択、不透明なペイロードを処理できる直接キー認証 Responses リレーの明示的な信頼、コンボへのネイティブ ChatGPT ターゲットの追加、異種プロバイダーの委任に v1 を使用する、または呼び出し元を制御するときにタスクをプレーンテキスト v2 `agent_message` コンテンツとして再送信することです。 実験的な `agentTaskRecovery` はデフォルトで無効です。明示的に有効にすると、固定された ChatGPT エンドポイントへの追加の認証済みリクエストでこの形式を回復できますが、クォータと待ち時間が増え、非公開のバックエンド動作に依存します。失敗時は従来の `unreadable_encrypted_agent_task` を維持します。詳細は[英語版の設定リファレンス](/reference/configuration/agents/#encrypted-v2-task-recovery)を参照してください。 diff --git a/docs-site/src/content/docs/reference/proxy-formats.md b/docs-site/src/content/docs/reference/proxy-formats.md index 60c74adb4a..00ea0947ca 100644 --- a/docs-site/src/content/docs/reference/proxy-formats.md +++ b/docs-site/src/content/docs/reference/proxy-formats.md @@ -356,7 +356,7 @@ Errors use the client dialect's envelope where needed, but these status/code mea | 401 | `authentication_error` | A required proxy admission credential is missing or invalid | | 403 | `origin_rejected` | A Responses/OpenAI data-plane request or WebSocket upgrade came from a disallowed origin | | 503 | `combo_unavailable` | Every target in the selected combo is unavailable, in cooldown, disabled, or otherwise ineligible | -| 400 | `unreadable_encrypted_agent_task` | An encrypted v2 worker task has no eligible canonical ChatGPT or explicitly trusted Responses target that can consume it | +| 400 | `unreadable_encrypted_agent_task` | An encrypted v2 worker task has no eligible canonical ChatGPT target or direct key-auth Responses target explicitly trusted with `allowEncryptedV2AgentTasks: true` that can consume it | | 426 | `upgrade_required` | The Responses WebSocket transport is disabled or the upgrade failed; use HTTP | Anthropic-origin failures are rendered in Anthropic's error envelope, so the origin rejection is a diff --git a/docs-site/src/content/docs/ru/reference/proxy-formats.md b/docs-site/src/content/docs/ru/reference/proxy-formats.md index f7a61f41b2..573c5ff32c 100644 --- a/docs-site/src/content/docs/ru/reference/proxy-formats.md +++ b/docs-site/src/content/docs/ru/reference/proxy-formats.md @@ -290,7 +290,7 @@ Direct, поэтому remote proxy key здесь обязан идти чер | 401 | `authentication_error` | Отсутствует обязательный credential для proxy-admission или он неверен | | 403 | `origin_rejected` | Data-plane запрос или WebSocket-upgrade Responses/OpenAI пришёл с запрещённого origin | | 503 | `combo_unavailable` | Все цели выбранной combo недоступны, в cooldown, отключены или иным образом не подходят | -| 400 | `unreadable_encrypted_agent_task` | У шифрованной задачи воркера v2 нет ни подходящей канонической цели ChatGPT, ни явно доверенной цели Responses, способной её обработать | +| 400 | `unreadable_encrypted_agent_task` | У шифрованной задачи воркера v2 нет ни подходящей канонической цели ChatGPT, ни прямой Responses-цели с аутентификацией по ключу, явно доверенной через `allowEncryptedV2AgentTasks: true` и способной её обработать | | 426 | `upgrade_required` | Транспорт Responses WebSocket выключен или upgrade не удался; используйте HTTP | Сбои, пришедшие с Anthropic-side, отрисовываются в error envelope Anthropic, поэтому отклонение 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 a4f919e420..3ce565d2cf 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 @@ -148,18 +148,19 @@ bilinen [#92 sınırlamasıdır](https://github.com/lidge-jun/opencodex/issues/9 opencodex boş veya okunamayan bir görevi iletmek yerine güvenli bir şekilde başarısız olur: -- Doğrudan yerel olmayan bir rota, anahtar kimlik doğrulamalı Responses sağlayıcısı - `allowEncryptedV2AgentTasks: true` ile açıkça etkinleştirilmedikçe `error.code = +- Uygun olmayan doğrudan yerel olmayan bir rota `error.code = "unreadable_encrypted_agent_task"` ile HTTP 400 döndürür ve şifreli metni yankılamaz. + `allowEncryptedV2AgentTasks: true` ile açıkça etkinleştirilen uygun bir doğrudan anahtar + kimlik doğrulamalı Responses sağlayıcısı bunun yerine opak şifreli metni alır ve bu hatayı atlar. - Bir kombo, yeniden denemeler de dahil olmak üzere bu görev için yalnızca kurallı yerel ChatGPT hedeflerini değerlendirir. Hiçbiri yoksa aynı 400 hatasını döndürür. - Okunabilir bir düz metin görevi normal rota ve geri dönüş davranışını korur. -Kurtarma seçenekleri, yerel bir ChatGPT çocuğu seçmek, komboya yerel bir ChatGPT -hedefi eklemek, heterojen sağlayıcı yetkilendirmesi için v1 kullanmak veya -arayanı denetlediğinizde görevi düz metin v2 `agent_message` içeriği olarak -yeniden göndermektir. +Kurtarma seçenekleri, yerel bir ChatGPT çocuğu seçmek, opak yükü tüketebilen doğrudan anahtar +kimlik doğrulamalı bir Responses geçidine açıkça güvenmek, komboya yerel bir ChatGPT hedefi +eklemek, heterojen sağlayıcı yetkilendirmesi için v1 kullanmak veya arayanı denetlediğinizde +görevi düz metin v2 `agent_message` içeriği olarak yeniden göndermektir. Deneysel, varsayılan olarak devre dışı bırakılmış bir `agentTaskRecovery` seçeneği, `authMode: "forward"` ile kurallı `openai` sağlayıcısı tarafından diff --git a/docs-site/src/content/docs/tr/reference/proxy-formats.md b/docs-site/src/content/docs/tr/reference/proxy-formats.md index 9c647f436b..13d921719e 100644 --- a/docs-site/src/content/docs/tr/reference/proxy-formats.md +++ b/docs-site/src/content/docs/tr/reference/proxy-formats.md @@ -324,7 +324,7 @@ anlamları kararlıdır: | 401 | `authentication_error` | Gerekli bir proxy kabul kimlik bilgisi eksik veya geçersiz | | 403 | `origin_rejected` | Bir Responses/OpenAI veri düzlemi isteği veya WebSocket yükseltmesi izin verilmeyen bir kaynaktan geldi | | 503 | `combo_unavailable` | Seçilen komdodaki her hedef kullanılamaz, soğumada, devre dışı veya başka şekilde uygun değil | -| 400 | `unreadable_encrypted_agent_task` | Şifrelenmiş bir v2 çalışan görevinin onu işleyebilecek uygun kurallı ChatGPT veya açıkça güvenilen Responses hedefi yok | +| 400 | `unreadable_encrypted_agent_task` | Şifrelenmiş bir v2 çalışan görevinin onu işleyebilecek uygun kurallı ChatGPT hedefi veya `allowEncryptedV2AgentTasks: true` ile açıkça güvenilen doğrudan anahtar kimlik doğrulamalı Responses hedefi yok | | 426 | `upgrade_required` | Responses WebSocket aktarımı devre dışı bırakıldı veya yükseltme başarısız oldu; HTTP kullanın | Anthropic kaynaklı arızalar Anthropic'in hata zarfında işlenir, bu nedenle 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 8471ee9f38..fae4b5a7e1 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 @@ -80,11 +80,11 @@ Codex 只能把 v2 原生到路由的子任务作为后端加密的 `encrypted_c opencodex 会安全失败,而不是转发空任务或不可读任务: -- 直接的非原生路由会返回 HTTP 400,并且 `error.code = "unreadable_encrypted_agent_task"`,不会回显密文;但其密钥认证 Responses provider 通过 `allowEncryptedV2AgentTasks: true` 明确选择加入时除外。 +- 不符合条件的直接非原生路由会返回 HTTP 400,并且 `error.code = "unreadable_encrypted_agent_task"`,不会回显密文。符合条件且通过 `allowEncryptedV2AgentTasks: true` 明确选择加入的直接密钥认证 Responses provider 会改为接收不透明密文,并绕过此错误。 - 对于该任务,combo 只会考虑规范的原生 ChatGPT 目标,包括重试。如果没有可用目标,则返回相同的 400 错误。 - 可读的明文任务会保持正常的路由和 fallback 行为。 -恢复选项是选择原生 ChatGPT 子级、在 combo 中添加原生 ChatGPT 目标、在异构 provider 委派中使用 v1,或者在你控制调用方时将任务作为明文 v2 `agent_message` 内容重新发送。 +恢复选项是选择原生 ChatGPT 子级、明确信任能够处理不透明载荷的直接密钥认证 Responses 中继、在 combo 中添加原生 ChatGPT 目标、在异构 provider 委派中使用 v1,或者在你控制调用方时将任务作为明文 v2 `agent_message` 内容重新发送。 实验性的 `agentTaskRecovery` 默认关闭。显式启用后,它可以通过向固定 ChatGPT 端点发送额外的认证请求来恢复这种格式,但会消耗配额、增加延迟,并依赖非公开的后端行为。任何失败都会保留原有的 `unreadable_encrypted_agent_task` 错误。详见[英文配置参考](/reference/configuration/agents/#encrypted-v2-task-recovery)。 diff --git a/docs-site/src/content/docs/zh-tw/reference/configuration/agents.md b/docs-site/src/content/docs/zh-tw/reference/configuration/agents.md index d95b5e1eb0..ddb20bd1f5 100644 --- a/docs-site/src/content/docs/zh-tw/reference/configuration/agents.md +++ b/docs-site/src/content/docs/zh-tw/reference/configuration/agents.md @@ -44,8 +44,11 @@ V1 指引僅在 `max` 或 `ultra` 時為主動文字。V2 僅在存在偏好模 生成子任務的 fallback 順序為: 1. 請求的主模型; -2. 來自 `$CODEX_HOME/agents/*.toml` 的角色級 `model_fallback`;然後 -3. 全域 `subagentModelFallback` 項目。 +2. 以請求的主模型為索引的 `subagentModelFallbackByModel` 每模型項目; +3. 全域 `subagentModelFallback` 項目;然後 +4. 為向後相容而讀取的 `$CODEX_HOME/agents/*.toml` 舊版角色級 `model_fallback`。 + +Codex 0.146+ 會將角色檔案中的 `model_fallback` 視為未知欄位並略過整個角色;`ocx doctor` 也會對此發出警告。因此新的角色級 fallback 應設定在 opencodex,而不是角色 TOML 中。 opencodex 會跳過已停用、不可路由、不健康、冷卻中或達到配額閾值的候選項。可用性快取保存 `subagentModelFallbackPollMs`。對於加密的子任務,候選鏈僅包含規範的原生 ChatGPT 目標,以及透過 `allowEncryptedV2AgentTasks: true` 明確信任的直接金鑰驗證 Responses 路由。若無任何目標可處理加密 payload,請求會失敗,而不會將無法讀取的密文路由到別處。組合仍只使用規範的原生目標。