diff --git a/docs-site/src/content/docs/fr/reference/configuration/providers.md b/docs-site/src/content/docs/fr/reference/configuration/providers.md index 57440547b7b..456983da841 100644 --- a/docs-site/src/content/docs/fr/reference/configuration/providers.md +++ b/docs-site/src/content/docs/fr/reference/configuration/providers.md @@ -193,7 +193,7 @@ sauvegarde dont le contenu diffère, puis réécrit en identifiants sans préfix | `unsafeAllowNativeLocalExec?` | `boolean` | Ancien booléen de Cursor, équivalent à `nativeLocalExec: "on"` uniquement lorsque le champ plus récent n'est pas défini. | | `nativeLocalExec?` | `"off" \| "codex-sandbox" \| "on"` | Politique d'exécution locale de Cursor. `off` est la valeur par défaut ; actuellement, `codex-sandbox` échoue de manière sûre comme `off`. | -Pour Responses natif, la même option couvre aussi une fin de flux normale après les seuls événements de cycle de vie. Les limites de requête autonome et de remplacement restent applicables. Les requêtes hors de ces limites ne sont pas inspectées et leur flux n'est jamais retenu. Un flux direct reçoit l'en-tête de réponse original dans les 200 millisecondes, même si l'amont est encore silencieux. Si la réinitialisation ou la fin de flux survient avant le renvoi de cet en-tête, le client reçoit le remplacement avec son propre statut et ses propres en-têtes, après avoir attendu l'en-tête du remplacement au plus 15 secondes, ou le délai d'inactivité s'il est plus court. Les requêtes non diffusées collectées en JSON et les cibles de combo peuvent attendre aussi longtemps avant de choisir un en-tête, car leur client ne reçoit aucun en-tête avant la collecte ou la sélection de la réponse. Une fois l'en-tête renvoyé, ce que le remplacement doit respecter dépend de la fin du flux. Une erreur de lecture conserve le comportement existant de la voie de réinitialisation : le corps du remplacement est publié derrière l'en-tête d'origine comme auparavant. Une fin de flux propre après les seuls événements de cycle de vie est plus stricte, car elle provient d'une autre tentative répondant au même tour : le remplacement doit concorder avec l'en-tête engagé sur le statut, le texte de statut, le type de média content-type, `openai-model` et `x-codex-turn-state`. Les en-têtes volatils et de saut (`date`, identifiants de requête, `cf-ray`, `server-timing`, `x-ratelimit-*`, `openai-processing-ms`, `content-length`, `transfer-encoding`, `connection`, `keep-alive`) n'ont pas à concorder, car le client détient déjà les valeurs de l'en-tête d'origine et une véritable origine les fait varier à chaque tentative. Une divergence conserve le flux original et son erreur. Les flux directs encore inspectés après ce point reçoivent un commentaire SSE keepalive avec l'en-tête, puis toutes les 15 secondes ; la vérification préalable du combo retient ces commentaires jusqu'à ce qu'elle sélectionne une réponse. +Pour Responses natif, la même option couvre aussi une fin de flux normale après les seuls événements de cycle de vie. Les limites de requête autonome et de remplacement restent applicables. Les requêtes hors de ces limites ne sont pas inspectées et leur flux n'est jamais retenu. Un flux direct reçoit l'en-tête de réponse original dans les 200 millisecondes, même si l'amont est encore silencieux. Le remplacement n'apporte son propre statut et ses propres en-têtes que s'il est sélectionné avant le renvoi de cet en-tête : pour un flux direct, la réinitialisation ou la fin de flux doit survenir dans ces 200 millisecondes, et l'en-tête du remplacement doit arriver dans les 15 secondes suivant la réponse originale, ou dans le délai d'inactivité s'il est plus court. Les requêtes non diffusées collectées en JSON et les cibles de combo n'ont pas de fenêtre de 200 millisecondes et peuvent attendre aussi longtemps avant de choisir un en-tête, car leur client ne reçoit aucun en-tête avant la collecte ou la sélection de la réponse. Une fois l'en-tête renvoyé, ce que le remplacement doit respecter dépend de la fin du flux. Une erreur de lecture conserve le comportement existant de la voie de réinitialisation : le corps du remplacement est publié derrière l'en-tête d'origine comme auparavant. Une fin de flux propre après les seuls événements de cycle de vie est plus stricte, car elle provient d'une autre tentative répondant au même tour : le remplacement doit concorder avec l'en-tête engagé sur le statut, le texte de statut, le type de média content-type, `openai-model` et `x-codex-turn-state`. Les en-têtes volatils et de saut (`date`, identifiants de requête, `cf-ray`, `server-timing`, `x-ratelimit-*`, `openai-processing-ms`, `content-length`, `transfer-encoding`, `connection`, `keep-alive`) n'ont pas à concorder, car le client détient déjà les valeurs de l'en-tête d'origine et une véritable origine les fait varier à chaque tentative. Une divergence conserve le flux original et son erreur. Les flux directs encore inspectés après ce point reçoivent un commentaire SSE keepalive avec l'en-tête, puis toutes les 15 secondes ; la vérification préalable du combo retient ces commentaires jusqu'à ce qu'elle sélectionne une réponse. LM Studio instruction compatibility: `singleLeadingSystemMessage: true` overrides chronological Chat instruction placement by merging text-only system/developer messages into one leading system message. The LM Studio preset enables it by default; set it to `false` to disable merging. diff --git a/docs-site/src/content/docs/ja/reference/configuration/providers.md b/docs-site/src/content/docs/ja/reference/configuration/providers.md index 8f006cb4f69..95f93ed597e 100644 --- a/docs-site/src/content/docs/ja/reference/configuration/providers.md +++ b/docs-site/src/content/docs/ja/reference/configuration/providers.md @@ -185,7 +185,7 @@ account を削除しても mapping は保持され、同じ id を再追加す | `unsafeAllowNativeLocalExec?` | `boolean` |カーソルのレガシー ブール値。新しいフィールドが設定されていない場合のみ、`nativeLocalExec: "on"` と同等です。 | | `nativeLocalExec?` | `"off" \| "codex-sandbox" \| "on"` |カーソルのローカル実行ポリシー。 `off` がデフォルトです。 `codex-sandbox` は現在、`off` と同様にフェールクローズされます。 | -ネイティブ Responses では、ライフサイクルイベントだけを受信して正常 EOF で終了した場合にも同じオプトインが適用されます。自己完結したリクエストと置換回数の制限は変わりません。これらの制限外のリクエストは検査されず、ストリームが保留されることはありません。直接ストリームは、上流がまだ無応答でも 200 ミリ秒以内に元の応答ヘッダーを受け取ります。そのヘッダーを返す前にリセットまたは EOF が起きた場合、置換応答のヘッダーを最大 15 秒(ストールタイムアウトの方が短い場合はその時間)待ち、クライアントは置換応答をそのステータスとヘッダーのまま受け取ります。JSON に収集する非ストリーミングリクエストとコンボのターゲットは、応答の収集または選択までクライアントにヘッダーが返らないため、ヘッダーの選択を同じ時間まで待つことがあります。ヘッダーを返した後の置換可否は、ストリームがどう終了したかで決まります。読み取りエラーではリセット経路の既存動作をそのまま維持し、置換本文を元のヘッダーの後ろに公開します。ライフサイクルイベントだけを受信して正常 EOF で終了した場合は同じターンへの別の試行なので、より厳格です。置換応答はコミット済みのヘッダーとステータス、ステータステキスト、content-type メディアタイプ、`openai-model`、`x-codex-turn-state` で一致しなければなりません。変動するヘッダーとホップバイホップヘッダー(`date`、リクエスト id、`cf-ray`、`server-timing`、`x-ratelimit-*`、`openai-processing-ms`、`content-length`、`transfer-encoding`、`connection`、`keep-alive`)は一致不要です。クライアントはすでに元のヘッダーの値を持っており、実際の上流は試行ごとにこれらを変えるためです。不一致の場合は元のストリームとそのエラーを保持します。その後も検査中の直接ストリームにはヘッダーとともに SSE keepalive コメントが送られ、その後は 15 秒ごとに送られます。コンボのプリフライトは応答を選択するまでこれらのコメントを保留します。 +ネイティブ Responses では、ライフサイクルイベントだけを受信して正常 EOF で終了した場合にも同じオプトインが適用されます。自己完結したリクエストと置換回数の制限は変わりません。これらの制限外のリクエストは検査されず、ストリームが保留されることはありません。直接ストリームは、上流がまだ無応答でも 200 ミリ秒以内に元の応答ヘッダーを受け取ります。置換応答が独自のステータスとヘッダーで返るのは、そのヘッダーを返す前に置換応答が選択された場合だけです。直接ストリームではリセットまたは EOF がその 200 ミリ秒以内に起きる必要があり、置換応答のヘッダーは元の応答から 15 秒以内(ストールタイムアウトの方が短い場合はその時間内)に届く必要があります。JSON に収集する非ストリーミングリクエストとコンボのターゲットには 200 ミリ秒の枠がなく、応答の収集または選択までクライアントにヘッダーが返らないため、ヘッダーの選択を同じ時間まで待つことがあります。ヘッダーを返した後の置換可否は、ストリームがどう終了したかで決まります。読み取りエラーではリセット経路の既存動作をそのまま維持し、置換本文を元のヘッダーの後ろに公開します。ライフサイクルイベントだけを受信して正常 EOF で終了した場合は同じターンへの別の試行なので、より厳格です。置換応答はコミット済みのヘッダーとステータス、ステータステキスト、content-type メディアタイプ、`openai-model`、`x-codex-turn-state` で一致しなければなりません。変動するヘッダーとホップバイホップヘッダー(`date`、リクエスト id、`cf-ray`、`server-timing`、`x-ratelimit-*`、`openai-processing-ms`、`content-length`、`transfer-encoding`、`connection`、`keep-alive`)は一致不要です。クライアントはすでに元のヘッダーの値を持っており、実際の上流は試行ごとにこれらを変えるためです。不一致の場合は元のストリームとそのエラーを保持します。その後も検査中の直接ストリームにはヘッダーとともに SSE keepalive コメントが送られ、その後は 15 秒ごとに送られます。コンボのプリフライトは応答を選択するまでこれらのコメントを保留します。 LM Studio instruction compatibility: `singleLeadingSystemMessage: true` overrides chronological Chat instruction placement by merging text-only system/developer messages into one leading system message. The LM Studio preset enables it by default; set it to `false` to disable merging. diff --git a/docs-site/src/content/docs/ko/reference/configuration/providers.md b/docs-site/src/content/docs/ko/reference/configuration/providers.md index fe0068fd79b..2222cb8f2ed 100644 --- a/docs-site/src/content/docs/ko/reference/configuration/providers.md +++ b/docs-site/src/content/docs/ko/reference/configuration/providers.md @@ -185,7 +185,7 @@ managed map을 활성화하면 privacy-safe selector를 만들고, 이후 계정 | `unsafeAllowNativeLocalExec?` | `boolean` | Cursor 레거시 불리언입니다. 더 새로운 필드가 설정되지 않았을 때만 `nativeLocalExec: "on"`과 같습니다. | | `nativeLocalExec?` | `"off" \| "codex-sandbox" \| "on"` | Cursor 로컬 실행 정책입니다. 기본값은 `off`입니다. `codex-sandbox`는 현재 `off`처럼 실패를 닫습니다. | -네이티브 Responses에서는 같은 선택 설정이 라이프사이클 이벤트만 받은 뒤 정상 EOF로 끝난 경우에도 적용됩니다. 자기완결 요청과 교체 횟수 제한은 그대로 적용됩니다. 이 제한을 벗어난 요청은 검사하지 않으므로 스트림이 보류되지 않습니다. 직접 스트림은 업스트림이 아직 조용하더라도 200밀리초 안에 원본 응답 헤더를 받습니다. 그 헤더를 반환하기 전에 리셋이나 EOF가 발생하면 교체 응답의 헤더를 최대 15초(정지 시간 제한이 더 짧으면 그 시간)까지 기다리며, 클라이언트는 교체 응답을 그 응답의 상태와 헤더 그대로 받습니다. JSON으로 모으는 비스트리밍 요청과 콤보 대상은 응답을 모으거나 선택하기 전까지 클라이언트에 헤더가 전달되지 않으므로 헤더 선택을 같은 시간까지 기다릴 수 있습니다. 헤더를 반환한 뒤 교체 여부는 스트림이 어떻게 끝났는지에 따라 달라집니다. 읽기 오류는 리셋 경로의 기존 동작을 그대로 유지하여 교체 본문을 원본 헤더 뒤에 발행합니다. 라이프사이클 이벤트만 받은 뒤 정상 EOF로 끝난 경우는 같은 턴에 대한 다른 시도이므로 더 엄격합니다. 교체 응답은 커밋된 헤더와 상태, 상태 텍스트, content-type 미디어 타입, `openai-model`, `x-codex-turn-state`에서 일치해야 합니다. 변동성 및 홉 단위 헤더(`date`, 요청 id, `cf-ray`, `server-timing`, `x-ratelimit-*`, `openai-processing-ms`, `content-length`, `transfer-encoding`, `connection`, `keep-alive`)는 일치할 필요가 없습니다. 클라이언트가 이미 원본 헤더의 값을 갖고 있고 실제 업스트림은 시도마다 이 값을 바꾸기 때문입니다. 일치하지 않으면 원본 스트림과 그 오류를 유지합니다. 그 뒤에도 검사 중인 직접 스트림은 헤더와 함께 SSE keepalive 주석을 받고 그 뒤 15초마다 다시 받으며, 콤보 사전 검사는 응답을 선택할 때까지 이 주석을 보류합니다. +네이티브 Responses에서는 같은 선택 설정이 라이프사이클 이벤트만 받은 뒤 정상 EOF로 끝난 경우에도 적용됩니다. 자기완결 요청과 교체 횟수 제한은 그대로 적용됩니다. 이 제한을 벗어난 요청은 검사하지 않으므로 스트림이 보류되지 않습니다. 직접 스트림은 업스트림이 아직 조용하더라도 200밀리초 안에 원본 응답 헤더를 받습니다. 교체 응답이 자체 상태와 헤더로 전달되는 것은 그 헤더를 반환하기 전에 교체 응답이 선택된 경우뿐입니다. 직접 스트림에서는 리셋이나 EOF가 그 200밀리초 안에 발생해야 하고, 교체 응답의 헤더는 원본 응답으로부터 15초(정지 시간 제한이 더 짧으면 그 시간) 안에 도착해야 합니다. JSON으로 모으는 비스트리밍 요청과 콤보 대상은 200밀리초 창이 없으며, 응답을 모으거나 선택하기 전까지 클라이언트에 헤더가 전달되지 않으므로 헤더 선택을 같은 시간까지 기다릴 수 있습니다. 헤더를 반환한 뒤 교체 여부는 스트림이 어떻게 끝났는지에 따라 달라집니다. 읽기 오류는 리셋 경로의 기존 동작을 그대로 유지하여 교체 본문을 원본 헤더 뒤에 발행합니다. 라이프사이클 이벤트만 받은 뒤 정상 EOF로 끝난 경우는 같은 턴에 대한 다른 시도이므로 더 엄격합니다. 교체 응답은 커밋된 헤더와 상태, 상태 텍스트, content-type 미디어 타입, `openai-model`, `x-codex-turn-state`에서 일치해야 합니다. 변동성 및 홉 단위 헤더(`date`, 요청 id, `cf-ray`, `server-timing`, `x-ratelimit-*`, `openai-processing-ms`, `content-length`, `transfer-encoding`, `connection`, `keep-alive`)는 일치할 필요가 없습니다. 클라이언트가 이미 원본 헤더의 값을 갖고 있고 실제 업스트림은 시도마다 이 값을 바꾸기 때문입니다. 일치하지 않으면 원본 스트림과 그 오류를 유지합니다. 그 뒤에도 검사 중인 직접 스트림은 헤더와 함께 SSE keepalive 주석을 받고 그 뒤 15초마다 다시 받으며, 콤보 사전 검사는 응답을 선택할 때까지 이 주석을 보류합니다. LM Studio instruction compatibility: `singleLeadingSystemMessage: true` overrides chronological Chat instruction placement by merging text-only system/developer messages into one leading system message. The LM Studio preset enables it by default; set it to `false` to disable merging. diff --git a/docs-site/src/content/docs/reference/configuration/providers.md b/docs-site/src/content/docs/reference/configuration/providers.md index fbb0145411b..98e03c58aa4 100644 --- a/docs-site/src/content/docs/reference/configuration/providers.md +++ b/docs-site/src/content/docs/reference/configuration/providers.md @@ -449,7 +449,7 @@ Providers can expose a built-in shorthand, such as `agy` for `google-antigravity | `unsafeAllowNativeLocalExec?` | `boolean` | Cursor legacy boolean, equivalent to `nativeLocalExec: "on"` only when the newer field is unset. | | `nativeLocalExec?` | `"off" \| "codex-sandbox" \| "on"` | Cursor local-exec policy. `off` is default; `codex-sandbox` currently fails closed like `off`. | -For native Responses, the same opt-in also covers a clean EOF after only lifecycle events. The self-contained-request and replacement limits still apply. Requests outside those limits are not inspected, so their streams are never held. A direct stream receives the original response head within 200 milliseconds while the upstream is still quiet. If the reset or EOF happens before that head is returned, the client receives the replacement with its own status and headers, after waiting at most 15 seconds, or the stall timeout if that is shorter, for the replacement's head. Non-streaming requests collected into JSON and combo targets may wait that long before choosing a head, because their client receives no head until the response is collected or selected. After the head is returned, what a replacement must match depends on how the stream ended. A read error keeps the reset lane's existing behaviour: the replacement's body is published behind the original head as it always has been. A clean prelude-only EOF is stricter, because it is a different attempt answering the same turn: the replacement must agree with the committed head on status, status text, content-type media type, \`openai-model\` and \`x-codex-turn-state\`. Volatile and hop-by-hop headers (\`date\`, request ids, \`cf-ray\`, \`server-timing\`, \`x-ratelimit-*\`, \`openai-processing-ms\`, \`content-length\`, \`transfer-encoding\`, \`connection\`, \`keep-alive\`) never have to match, since the client already holds the original head's values and a real origin varies them per attempt. A mismatch retains the original stream and its error. Direct streams still being inspected after that point receive an SSE keepalive comment with the head and then every 15 seconds; combo preflight holds these comments until it selects a response. +For native Responses, the same opt-in also covers a clean EOF after only lifecycle events. The self-contained-request and replacement limits still apply. Requests outside those limits are not inspected, so their streams are never held. A direct stream receives the original response head within 200 milliseconds while the upstream is still quiet. The replacement supplies its own status and headers only if it is selected before that head is returned: a direct stream's reset or EOF must happen within those 200 milliseconds, and the replacement's head must arrive within 15 seconds of the original response, or the stall timeout if that is shorter. Non-streaming requests collected into JSON and combo targets have no 200-millisecond window and may wait that long before choosing a head, because their client receives no head until the response is collected or selected. After the head is returned, what a replacement must match depends on how the stream ended. A read error keeps the reset lane's existing behaviour: the replacement's body is published behind the original head as it always has been. A clean prelude-only EOF is stricter, because it is a different attempt answering the same turn: the replacement must agree with the committed head on status, status text, content-type media type, \`openai-model\` and \`x-codex-turn-state\`. Volatile and hop-by-hop headers (\`date\`, request ids, \`cf-ray\`, \`server-timing\`, \`x-ratelimit-*\`, \`openai-processing-ms\`, \`content-length\`, \`transfer-encoding\`, \`connection\`, \`keep-alive\`) never have to match, since the client already holds the original head's values and a real origin varies them per attempt. A mismatch retains the original stream and its error. Direct streams still being inspected after that point receive an SSE keepalive comment with the head and then every 15 seconds; combo preflight holds these comments until it selects a response. Command Code's shipped per-model effort defaults include live API measurements. DeepSeek v4/v4.1 Flash (including v4 Flash Vision), GLM-5.3 and GLM-5.3-Flash, Qwen3.8-Flash, and Gemini-3.7-Flash support `low`, `medium`, `high`, `xhigh`, and `max`. Ladders remain model-specific: `poolside/laguna-s-2.1-free` offers only `medium`, while Gemini-3.8-Flash and MiMo-v2.5-Pro offer `low`, `medium`, and `high`. To override a pinned Command Code row, set `modelReasoningEffortsAuthoritative: true` together with that model's `modelReasoningEfforts` list. diff --git a/docs-site/src/content/docs/ru/reference/configuration/providers.md b/docs-site/src/content/docs/ru/reference/configuration/providers.md index 65c36cac634..d3b36f4599e 100644 --- a/docs-site/src/content/docs/ru/reference/configuration/providers.md +++ b/docs-site/src/content/docs/ru/reference/configuration/providers.md @@ -198,7 +198,7 @@ cross-route credential fallback не существует. Строки API GPT- | `unsafeAllowNativeLocalExec?` | `boolean` | Legacy boolean Cursor, эквивалентен `nativeLocalExec: "on"` только если новое поле не задано. | | `nativeLocalExec?` | `"off" \| "codex-sandbox" \| "on"` | Политика local-exec для Cursor. `off` — дефолт; `codex-sandbox` сейчас ведёт себя fail-closed как `off`. | -Для нативного Responses эта настройка также охватывает обычный EOF после одних событий жизненного цикла. Ограничения на самодостаточный запрос и число замен сохраняются. Запросы вне этих ограничений не проверяются, и их поток не задерживается. Прямой поток получает исходные заголовки ответа в течение 200 миллисекунд, даже если вышестоящий сервер ещё молчит. Если сброс или EOF происходит до возврата этих заголовков, клиент получает замену с её собственными статусом и заголовками; заголовков замены ждут не дольше 15 секунд или тайм-аута простоя, если он короче. Непотоковые запросы, собираемые в JSON, и цели комбо могут ждать столько же перед выбором заголовков, потому что их клиент не получает заголовков до сбора или выбора ответа. После возврата заголовков требование к замене зависит от того, как завершился поток. Ошибка чтения сохраняет прежнее поведение ветки сброса: тело замены публикуется за исходным заголовком, как и раньше. Чистый EOF после одних событий жизненного цикла строже, потому что это другая попытка ответить на тот же ход: замена должна совпадать с зафиксированным заголовком по статусу, тексту статуса, типу носителя content-type, `openai-model` и `x-codex-turn-state`. Переменные и hop-by-hop заголовки (`date`, идентификаторы запросов, `cf-ray`, `server-timing`, `x-ratelimit-*`, `openai-processing-ms`, `content-length`, `transfer-encoding`, `connection`, `keep-alive`) совпадать не обязаны: клиент уже хранит значения исходного заголовка, а реальный источник меняет их при каждой попытке. При несовпадении сохраняются исходный поток и его ошибка. Прямые потоки, которые после этого ещё проверяются, получают SSE-комментарий keepalive вместе с заголовками, а затем каждые 15 секунд; предварительная проверка комбо удерживает эти комментарии до выбора ответа. +Для нативного Responses эта настройка также охватывает обычный EOF после одних событий жизненного цикла. Ограничения на самодостаточный запрос и число замен сохраняются. Запросы вне этих ограничений не проверяются, и их поток не задерживается. Прямой поток получает исходные заголовки ответа в течение 200 миллисекунд, даже если вышестоящий сервер ещё молчит. Замена передаёт собственные статус и заголовки, только если она выбрана до возврата этих заголовков: в прямом потоке сброс или EOF должен произойти в эти 200 миллисекунд, а заголовки замены должны прийти не позднее 15 секунд после исходного ответа или тайм-аута простоя, если он короче. Непотоковые запросы, собираемые в JSON, и цели комбо не имеют окна в 200 миллисекунд и могут ждать столько же перед выбором заголовков, потому что их клиент не получает заголовков до сбора или выбора ответа. После возврата заголовков требование к замене зависит от того, как завершился поток. Ошибка чтения сохраняет прежнее поведение ветки сброса: тело замены публикуется за исходным заголовком, как и раньше. Чистый EOF после одних событий жизненного цикла строже, потому что это другая попытка ответить на тот же ход: замена должна совпадать с зафиксированным заголовком по статусу, тексту статуса, типу носителя content-type, `openai-model` и `x-codex-turn-state`. Переменные и hop-by-hop заголовки (`date`, идентификаторы запросов, `cf-ray`, `server-timing`, `x-ratelimit-*`, `openai-processing-ms`, `content-length`, `transfer-encoding`, `connection`, `keep-alive`) совпадать не обязаны: клиент уже хранит значения исходного заголовка, а реальный источник меняет их при каждой попытке. При несовпадении сохраняются исходный поток и его ошибка. Прямые потоки, которые после этого ещё проверяются, получают SSE-комментарий keepalive вместе с заголовками, а затем каждые 15 секунд; предварительная проверка комбо удерживает эти комментарии до выбора ответа. LM Studio instruction compatibility: `singleLeadingSystemMessage: true` overrides chronological Chat instruction placement by merging text-only system/developer messages into one leading system message. The LM Studio preset enables it by default; set it to `false` to disable merging. diff --git a/docs-site/src/content/docs/tr/reference/configuration/providers.md b/docs-site/src/content/docs/tr/reference/configuration/providers.md index 4cadf40a9ca..0d4579440f2 100644 --- a/docs-site/src/content/docs/tr/reference/configuration/providers.md +++ b/docs-site/src/content/docs/tr/reference/configuration/providers.md @@ -197,7 +197,7 @@ alanlı seçilmiş kimlikleri yalın kimliklere yeniden yazar. | `unsafeAllowNativeLocalExec?` | `boolean` | Cursor eski boolean değeri, yalnızca daha yeni alan ayarlanmadığında `nativeLocalExec: "on"` değerine eşdeğerdir. | | `nativeLocalExec?` | `"off" \| "codex-sandbox" \| "on"` | Cursor yerel yürütme politikası. `off` varsayılandır; `codex-sandbox` şu anda `off` gibi kapalı olarak başarısız olur. | -Yerel Responses için aynı tercih, yalnızca yaşam döngüsü olaylarından sonra gelen normal EOF durumunu da kapsar. Kendi kendine yeterli istek ve değiştirme sınırları geçerlidir. Bu sınırların dışındaki istekler denetlenmez, bu yüzden akışları bekletilmez. Doğrudan akış, üst sunucu henüz sessiz olsa bile orijinal yanıt başlığını 200 milisaniye içinde alır. Sıfırlama veya EOF bu başlık döndürülmeden önce olursa istemci yedek yanıtı kendi durumu ve başlıklarıyla alır; yedek yanıtın başlığı en fazla 15 saniye ya da daha kısaysa takılma zaman aşımı kadar beklenir. JSON olarak toplanan akışsız istekler ve combo hedefleri, istemcileri yanıt toplanana veya seçilene kadar başlık almadığı için başlık seçmeden önce aynı süre bekleyebilir. Başlık döndürüldükten sonra yedeğin neyle eşleşmesi gerektiği akışın nasıl bittiğine bağlıdır: okuma hatası sıfırlama yolunun mevcut davranışını korur ve yedek gövde her zamanki gibi orijinal başlığın arkasında yayımlanır; yalnızca yaşam döngüsü olaylarından sonra gelen temiz EOF daha katıdır, çünkü aynı turu yanıtlayan farklı bir denemedir ve yedek, taahhüt edilmiş başlıkla durum, durum metni, content-type ortam türü, `openai-model` ve `x-codex-turn-state` üzerinde anlaşmalıdır. Değişken ve atlama bazlı başlıkların (`date`, istek kimlikleri, `cf-ray`, `server-timing`, `x-ratelimit-*`, `openai-processing-ms`, `content-length`, `transfer-encoding`, `connection`, `keep-alive`) eşleşmesi gerekmez; istemci orijinal başlığın değerlerini zaten taşır ve gerçek bir kaynak bunları her denemede değiştirir. Uyuşmazlıkta orijinal akış ve hatası korunur. Bundan sonra hâlâ denetlenen doğrudan akışlar başlıkla birlikte ve ardından her 15 saniyede bir SSE keepalive yorumu alır; combo ön denetimi bir yanıt seçene kadar bu yorumları tutar. +Yerel Responses için aynı tercih, yalnızca yaşam döngüsü olaylarından sonra gelen normal EOF durumunu da kapsar. Kendi kendine yeterli istek ve değiştirme sınırları geçerlidir. Bu sınırların dışındaki istekler denetlenmez, bu yüzden akışları bekletilmez. Doğrudan akış, üst sunucu henüz sessiz olsa bile orijinal yanıt başlığını 200 milisaniye içinde alır. Yedek yanıt kendi durumunu ve başlıklarını yalnızca bu başlık döndürülmeden önce seçilirse getirir: doğrudan akışta sıfırlama veya EOF bu 200 milisaniye içinde olmalı, yedek yanıtın başlığı da orijinal yanıttan sonra en fazla 15 saniye ya da daha kısaysa takılma zaman aşımı içinde gelmelidir. JSON olarak toplanan akışsız istekler ve combo hedefleri 200 milisaniyelik pencereye tabi değildir ve, istemcileri yanıt toplanana veya seçilene kadar başlık almadığı için başlık seçmeden önce aynı süre bekleyebilir. Başlık döndürüldükten sonra yedeğin neyle eşleşmesi gerektiği akışın nasıl bittiğine bağlıdır: okuma hatası sıfırlama yolunun mevcut davranışını korur ve yedek gövde her zamanki gibi orijinal başlığın arkasında yayımlanır; yalnızca yaşam döngüsü olaylarından sonra gelen temiz EOF daha katıdır, çünkü aynı turu yanıtlayan farklı bir denemedir ve yedek, taahhüt edilmiş başlıkla durum, durum metni, content-type ortam türü, `openai-model` ve `x-codex-turn-state` üzerinde anlaşmalıdır. Değişken ve atlama bazlı başlıkların (`date`, istek kimlikleri, `cf-ray`, `server-timing`, `x-ratelimit-*`, `openai-processing-ms`, `content-length`, `transfer-encoding`, `connection`, `keep-alive`) eşleşmesi gerekmez; istemci orijinal başlığın değerlerini zaten taşır ve gerçek bir kaynak bunları her denemede değiştirir. Uyuşmazlıkta orijinal akış ve hatası korunur. Bundan sonra hâlâ denetlenen doğrudan akışlar başlıkla birlikte ve ardından her 15 saniyede bir SSE keepalive yorumu alır; combo ön denetimi bir yanıt seçene kadar bu yorumları tutar. LM Studio instruction compatibility: `singleLeadingSystemMessage: true` overrides chronological Chat instruction placement by merging text-only system/developer messages into one leading system message. The LM Studio preset enables it by default; set it to `false` to disable merging. diff --git a/docs-site/src/content/docs/zh-cn/reference/configuration/providers.md b/docs-site/src/content/docs/zh-cn/reference/configuration/providers.md index 8216dcd1d65..ef858f27f21 100644 --- a/docs-site/src/content/docs/zh-cn/reference/configuration/providers.md +++ b/docs-site/src/content/docs/zh-cn/reference/configuration/providers.md @@ -187,7 +187,7 @@ selector,而不是分配一个新名称。 | `unsafeAllowNativeLocalExec?` | `boolean` | Cursor 旧布尔值;仅当更新字段未设置时,等同于 `nativeLocalExec: "on"`。 | | `nativeLocalExec?` | `"off" \| "codex-sandbox" \| "on"` | Cursor 本地执行策略。`off` 是默认值;`codex-sandbox` 目前会像 `off` 一样失败关闭。 | -对于原生 Responses,同一开关也涵盖仅收到生命周期事件后正常结束的 EOF。自包含请求和替换次数限制仍然适用。超出这些限制的请求不会被检查,其流也不会被暂扣。直接流即使上游仍无响应,也会在 200 毫秒内收到原始响应头。如果重置或 EOF 发生在返回该响应头之前,客户端会收到带有其自身状态和响应头的替换响应;等待替换响应头的时间最多为 15 秒(若停滞超时更短则以其为准)。汇总为 JSON 的非流式请求和组合目标在响应汇总或选定之前不会向客户端返回响应头,因此选择响应头前可能等待同样的时间。返回响应头之后,是否替换取决于流如何结束:读取错误保留重置通道的既有行为,替换正文照旧发布在原始响应头之后;只有生命周期事件后正常结束的 EOF 更严格,因为它是以另一次尝试回答同一轮请求,替换响应必须与已提交的响应头在状态、状态文本、content-type 媒体类型、`openai-model` 和 `x-codex-turn-state` 上一致。易变和逐跳标头(`date`、请求 id、`cf-ray`、`server-timing`、`x-ratelimit-*`、`openai-processing-ms`、`content-length`、`transfer-encoding`、`connection`、`keep-alive`)无需一致,因为客户端已经持有原始响应头的值,而真实上游每次尝试都会变动这些标头。不一致时保留原始流及其错误。此后仍在检查的直接流会随响应头收到一条 SSE keepalive 注释,此后每 15 秒再收到一条;组合预检会在选定响应前暂扣这些注释。 +对于原生 Responses,同一开关也涵盖仅收到生命周期事件后正常结束的 EOF。自包含请求和替换次数限制仍然适用。超出这些限制的请求不会被检查,其流也不会被暂扣。直接流即使上游仍无响应,也会在 200 毫秒内收到原始响应头。只有在返回该响应头之前选定替换响应时,替换响应才会带有其自身的状态和响应头:直接流的重置或 EOF 必须发生在这 200 毫秒内,且替换响应头必须在原始响应到达后 15 秒内(若停滞超时更短则以其为准)到达。汇总为 JSON 的非流式请求和组合目标没有 200 毫秒窗口,在响应汇总或选定之前不会向客户端返回响应头,因此选择响应头前可能等待同样的时间。返回响应头之后,是否替换取决于流如何结束:读取错误保留重置通道的既有行为,替换正文照旧发布在原始响应头之后;只有生命周期事件后正常结束的 EOF 更严格,因为它是以另一次尝试回答同一轮请求,替换响应必须与已提交的响应头在状态、状态文本、content-type 媒体类型、`openai-model` 和 `x-codex-turn-state` 上一致。易变和逐跳标头(`date`、请求 id、`cf-ray`、`server-timing`、`x-ratelimit-*`、`openai-processing-ms`、`content-length`、`transfer-encoding`、`connection`、`keep-alive`)无需一致,因为客户端已经持有原始响应头的值,而真实上游每次尝试都会变动这些标头。不一致时保留原始流及其错误。此后仍在检查的直接流会随响应头收到一条 SSE keepalive 注释,此后每 15 秒再收到一条;组合预检会在选定响应前暂扣这些注释。 LM Studio instruction compatibility: `singleLeadingSystemMessage: true` overrides chronological Chat instruction placement by merging text-only system/developer messages into one leading system message. The LM Studio preset enables it by default; set it to `false` to disable merging. diff --git a/docs-site/src/content/docs/zh-tw/reference/configuration/providers.md b/docs-site/src/content/docs/zh-tw/reference/configuration/providers.md index 2e4640db766..1111e1d630c 100644 --- a/docs-site/src/content/docs/zh-tw/reference/configuration/providers.md +++ b/docs-site/src/content/docs/zh-tw/reference/configuration/providers.md @@ -158,7 +158,7 @@ ocx models provider openrouter on | `unsafeAllowNativeLocalExec?` | `boolean` | Cursor 舊版布林值,僅在較新欄位未設定時等同於 `nativeLocalExec: "on"`。 | | `nativeLocalExec?` | `"off" \| "codex-sandbox" \| "on"` | Cursor 本機執行政策。`off` 為預設;`codex-sandbox` 目前像 `off` 般 fail closed。 | -對原生 Responses 而言,相同開關也涵蓋只收到生命週期事件後正常結束的 EOF。自包含請求與替換次數限制仍然適用。超出這些限制的請求不會被檢查,其串流也不會被暫扣。直接串流即使上游仍無回應,也會在 200 毫秒內收到原始回應標頭。如果重設或 EOF 發生在回傳該回應標頭之前,用戶端會收到帶有其自身狀態和回應標頭的替換回應;等待替換回應標頭的時間最多為 15 秒(若停滯逾時更短則以其為準)。彙整為 JSON 的非串流請求與組合目標在回應彙整或選定之前不會向用戶端回傳標頭,因此選擇標頭前可能等待同樣的時間。回傳回應標頭之後,是否替換取決於串流如何結束:讀取錯誤保留重設通道的既有行為,替換內文照舊發佈在原始回應標頭之後;只有生命週期事件後正常結束的 EOF 更嚴格,因為它是以另一次嘗試回答同一輪請求,替換回應必須與已提交的標頭在狀態、狀態文字、content-type 媒體類型、`openai-model` 和 `x-codex-turn-state` 上一致。易變與逐跳標頭(`date`、請求 id、`cf-ray`、`server-timing`、`x-ratelimit-*`、`openai-processing-ms`、`content-length`、`transfer-encoding`、`connection`、`keep-alive`)無需一致,因為用戶端已持有原始標頭的值,而真實上游每次嘗試都會變動這些標頭。不一致時保留原始串流及其錯誤。此後仍在檢查的直接串流會隨回應標頭收到一則 SSE keepalive 註解,此後每 15 秒再收到一則;組合預檢會在選定回應前暫扣這些註解。 +對原生 Responses 而言,相同開關也涵蓋只收到生命週期事件後正常結束的 EOF。自包含請求與替換次數限制仍然適用。超出這些限制的請求不會被檢查,其串流也不會被暫扣。直接串流即使上游仍無回應,也會在 200 毫秒內收到原始回應標頭。只有在回傳該回應標頭之前選定替換回應時,替換回應才會帶有其自身的狀態和回應標頭:直接串流的重設或 EOF 必須發生在這 200 毫秒內,且替換回應標頭必須在原始回應到達後 15 秒內(若停滯逾時更短則以其為準)到達。彙整為 JSON 的非串流請求與組合目標沒有 200 毫秒視窗,在回應彙整或選定之前不會向用戶端回傳標頭,因此選擇標頭前可能等待同樣的時間。回傳回應標頭之後,是否替換取決於串流如何結束:讀取錯誤保留重設通道的既有行為,替換內文照舊發佈在原始回應標頭之後;只有生命週期事件後正常結束的 EOF 更嚴格,因為它是以另一次嘗試回答同一輪請求,替換回應必須與已提交的標頭在狀態、狀態文字、content-type 媒體類型、`openai-model` 和 `x-codex-turn-state` 上一致。易變與逐跳標頭(`date`、請求 id、`cf-ray`、`server-timing`、`x-ratelimit-*`、`openai-processing-ms`、`content-length`、`transfer-encoding`、`connection`、`keep-alive`)無需一致,因為用戶端已持有原始標頭的值,而真實上游每次嘗試都會變動這些標頭。不一致時保留原始串流及其錯誤。此後仍在檢查的直接串流會隨回應標頭收到一則 SSE keepalive 註解,此後每 15 秒再收到一則;組合預檢會在選定回應前暫扣這些註解。 LM Studio instruction compatibility: `singleLeadingSystemMessage: true` overrides chronological Chat instruction placement by merging text-only system/developer messages into one leading system message. The LM Studio preset enables it by default; set it to `false` to disable merging. diff --git a/src/server/responses/passthrough-completion.ts b/src/server/responses/passthrough-completion.ts index 7a767afbd52..6344df1f6df 100644 --- a/src/server/responses/passthrough-completion.ts +++ b/src/server/responses/passthrough-completion.ts @@ -17,6 +17,16 @@ export { parseOutboundRequestBody } from "./outbound-request-body"; // A guarded published reset response, mapped to when its selection began holding the head. const guardedResetResponses = new WeakMap(); +// A canonical JSON turn's published head, mapped to the wall-clock time its selection began (#8343). +const bufferedSelectionStarts = new WeakMap(); + +/** + * When reset selection began holding this canonical JSON turn's head, if it ran. The collector's + * whole-turn deadline starts there, so the time selection held the head counts against it. + */ +export function bufferedResetSelectionStartedAt(response: Response): number | undefined { + return bufferedSelectionStarts.get(response); +} /** * How long a direct stream's head may wait on the original's own inspection. @@ -76,6 +86,7 @@ export function selectPassthroughResetResponse( const originalOwner = quotaOwner(); let replacementOwner: MainQuotaDispatch | undefined; const heldSince = performance.now(); + const selectionStartedAt = Date.now(); return selectProtocolSafeResetResponse(protect(response), logCtx, async (error, stage, signal, accepts) => { // Recover returns only a validated, fresh body; wrapping earlier would hide its lock state. const replacement = await recover(error, stage, signal, accepts); @@ -91,6 +102,7 @@ export function selectPassthroughResetResponse( maxSelectionMs: stallMs > 0 ? stallMs : undefined, onCommit: (published, owner) => { if (openGateway) guardedResetResponses.set(published, heldSince); + if (options.delivery === "buffered-json") bufferedSelectionStarts.set(published, selectionStartedAt); bindPublishedMainQuotaDispatch(published, owner === "replacement" ? replacementOwner : originalOwner); }, }); diff --git a/src/server/responses/passthrough-delivery.ts b/src/server/responses/passthrough-delivery.ts index f06bf581219..704718b800b 100644 --- a/src/server/responses/passthrough-delivery.ts +++ b/src/server/responses/passthrough-delivery.ts @@ -174,11 +174,13 @@ import { restoreRoutedToolSearchCallsInJson } from "../../responses/tool-search- import { responsesJsonToSseStream } from "../responses-json-events"; import { isCanonicalOpenAiForwardProvider } from "../../providers/openai-tiers"; import { + BUFFERED_RESPONSES_TOTAL_TIMEOUT_MS, bufferedResponsesReadOptions, collectBufferedResponsesSse, type BufferedResponsesSseFailure, type BufferedResponsesSseResult, } from "./buffered-sse-json"; +import { bufferedResetSelectionStartedAt } from "./passthrough-completion"; const PLAINTEXT_V2_SSE_PREFIX_LIMIT = 4096; @@ -977,10 +979,11 @@ export async function deliverPassthroughResponse( if (canonicalBufferedJson) { const signal = options.abortSignal ?? req.signal; + // A turn whose head waited on reset selection keeps the deadline that wait already spent. const bufferedRead = bufferedResponsesReadOptions(resolveStallTimeoutMs( config.stallTimeoutSec, { localUpstream: nativeExchange.localUpstream }, - )); + ), BUFFERED_RESPONSES_TOTAL_TIMEOUT_MS, bufferedResetSelectionStartedAt(nativeExchange.upstreamResponse) ?? Date.now()); const failBufferedTurn = ( message: string, failure?: BufferedResponsesSseFailure, diff --git a/structure/transports/responses-combo-boundaries.md b/structure/transports/responses-combo-boundaries.md index 0a969820911..a9e428a7676 100644 --- a/structure/transports/responses-combo-boundaries.md +++ b/structure/transports/responses-combo-boundaries.md @@ -195,7 +195,7 @@ comment, cannot extend it, and the reset gate never resends a guard timeout. For JSON, the collector reports the guard's failure as a stall timeout. The hold emits a comment only when it reads non-empty upstream bytes or a replacement head lands behind a committed head, so the collector's own clock, which starts after selection and sees only delivered bytes, never ends a turn before the guard would. The byte and chunk -caps and the collector's whole-turn ceiling remain in force. +caps and the collector's whole-turn ceiling remain in force. That ceiling runs from the moment selection began holding the head (`bufferedResetSelectionStartedAt` in `src/server/responses/passthrough-completion.ts`), so the selection wait counts against it while sends before selection do not (#8343). Downstream cancellation or the request's abort signal ends the selection or hold at once, aborts an in-flight replacement, and never awaits upstream cleanup. diff --git a/tests/responses/responses-canonical-nonstream.test.ts b/tests/responses/responses-canonical-nonstream.test.ts index b073c1a5901..73f3b3823a8 100644 --- a/tests/responses/responses-canonical-nonstream.test.ts +++ b/tests/responses/responses-canonical-nonstream.test.ts @@ -812,6 +812,39 @@ describe("canonical ChatGPT transport for non-streaming Responses callers (#6162 expect(sends).toBe(2); expect(replacement.cancels()).toBeGreaterThanOrEqual(1); })); + + test("the whole-turn ceiling counts the time selection held the head (#8343)", () => withFakeClock(async () => { + const original = scripted(); + let sends = 0; + let sentAt = 0; + globalThis.fetch = (async () => { + sends++; + sentAt = Date.now(); + original.push(created); + // Real upstream activity inside every stall budget, for longer than the whole-turn ceiling. + const beat = () => { original.push(heartbeat); setTimeout(beat, 4_000); }; + setTimeout(beat, 4_000); + return original.response; + }) as typeof fetch; + // settle() gives up after 30 s of fake time; this turn has to reach its 15-minute ceiling. + const turn: { response?: Response } = {}; + void call(requestBody(false, false), {}, stallConfig).then(response => { turn.response = response; }, () => undefined); + for (;;) { + await flushMicrotasks(); + await new Promise(resolve => setImmediate(resolve)); + await flushMicrotasks(); + if (turn.response) break; + if (sentAt > 0 && Date.now() - sentAt > BUFFERED_RESPONSES_TOTAL_TIMEOUT_MS + 30_000) throw new Error("buffered turn outlived its ceiling"); + jest.advanceTimersByTime(1_000); + } + const elapsed = Date.now() - sentAt; + expect(turn.response.status).toBe(502); + // Selection held the head for one stall budget before the collector started; the ceiling + // still ends the turn one total timeout after the head arrived, not after that wait. + expect(elapsed).toBeGreaterThan(BUFFERED_RESPONSES_TOTAL_TIMEOUT_MS - 1_000); + expect(elapsed).toBeLessThanOrEqual(BUFFERED_RESPONSES_TOTAL_TIMEOUT_MS + 1_000); + expect(sends).toBe(1); + })); }); for (const ending of ["eof", "read-error"] as const) {