diff --git a/docs-site/src/content/docs/fr/guides/combos.md b/docs-site/src/content/docs/fr/guides/combos.md index 44992d7d1f..9785135d53 100644 --- a/docs-site/src/content/docs/fr/guides/combos.md +++ b/docs-site/src/content/docs/fr/guides/combos.md @@ -171,6 +171,25 @@ Les poids sont relatifs et non en pourcentage. Les poids `2,1` et `200,100` expr petites valeurs qui communiquent l’intention. ::: +### `random` : tirage pondéré à chaque requête + +`random` tire une cible éligible par requête, avec une probabilité proportionnelle à `weight`. Chaque requête +constitue un tirage indépendant, de sorte que le trafic se répartit entre les cibles sans le schéma déterministe ni +la persistance de `round-robin`. `stickyLimit` n’affecte pas cette stratégie. + +### `least-used` : privilégier la cible ayant le moins de réussites + +`least-used` achemine chaque requête vers la cible éligible pour laquelle ce processus opencodex a enregistré le moins +de requêtes réussies. Les compteurs repartent de zéro au redémarrage et, en cas d’égalité, l’ordre de configuration est +conservé. `weight` et `stickyLimit` n’affectent pas cette stratégie. + +### `reset-window` : suivre la réinitialisation de quota la plus proche + +`reset-window` achemine chaque requête vers la cible éligible dont l’instantané mis en cache du quota du fournisseur +indique la réinitialisation de fenêtre à venir la plus proche (cinq heures, hebdomadaire, mensuelle ou personnalisée). +Le fournisseur dont le quota se renouvelle en premier est ainsi sollicité. Les cibles dépourvues de données de quota +récentes et les égalités conservent l’ordre de configuration. `weight` et `stickyLimit` n’affectent pas cette stratégie. + ## Que se passe-t-il lorsqu'une cible échoue Les échecs d’un combo se répartissent entre ceux qui entraînent un **basculement** et les échecs **terminaux**. @@ -314,9 +333,9 @@ Les combos sont stockés dans l'objet `combos` de niveau supérieur, saisi par l | Champ | Obligatoire | Par défaut | Règles | | --- | --- | --- | --- | | `targets` | Oui | — | Tableau ordonné non vide de `{ provider, model, weight? }` cibles configurées. Les paires provider/model en double sont rejetées. | -| `targets[].weight` | Non | `1` | Entier de 1 à 10 000. Utilisé en round-robin ; ignoré par le basculement. | -| `strategy` | Non | `"failover"` | `"failover"` ou `"round-robin"`. | -| `stickyLimit` | Non | `1` | Nombre entier de 1 à 100 requêtes réussies par sélection à tour de rôle. | +| `targets[].weight` | Non | `1` | Entier de 1 à 10 000. Utilisé par `round-robin` et `random` ; ignoré par `failover`, `least-used` et `reset-window`. | +| `strategy` | Non | `"failover"` | Valeurs autorisées : `"failover"`, `"round-robin"`, `"random"`, `"least-used"` et `"reset-window"`. | +| `stickyLimit` | Non | `1` | Nombre entier de 1 à 100 requêtes réussies par sélection à tour de rôle. S’applique uniquement à `round-robin`. | | `defaultEffort` | Non | `null` | `low`, `medium`, `high`, `xhigh`, `max` ou `ultra` ; appliqué uniquement lorsque l'appelant omet ses efforts et que la cible annonce son soutien. | | `imageInput` | Non | `"auto"` | `"auto"` ou `"disabled"`. `"auto"` publie les images uniquement si toutes les cibles les prennent en charge ; `"disabled"` impose le texte seul, retire les images des modalités publiées et rejette les requêtes qui en contiennent avant leur distribution. | | `alias` | Non | aucun | Identifiant de modèle public tronqué facultatif ; utilisez les règles d'alias ci-dessus. Une valeur vide est stockée sans alias. | diff --git a/docs-site/src/content/docs/fr/reference/cli/providers-accounts.md b/docs-site/src/content/docs/fr/reference/cli/providers-accounts.md index 4b9a4b710f..9f865c7f0d 100644 --- a/docs-site/src/content/docs/fr/reference/cli/providers-accounts.md +++ b/docs-site/src/content/docs/fr/reference/cli/providers-accounts.md @@ -148,8 +148,8 @@ Sans fournisseur, répertorie le groupe de comptes Codex, les comptes OAuth et l sont ignorés à moins que `--all` soit présent. Avec un fournisseur, répertorie uniquement cette famille d’informations d’identification. La sortie destinée aux utilisateurs utilise `PROVIDER TYPE ID PLAN/LABEL PRIORITY STATUS` ; une ligne Codex sélectionnée manuellement porte la mention `selected`. `PRIORITY` est l'ordre de sélection Codex signé (`0` lorsqu'il n'est pas défini) et affiche `-` pour les lignes -où l'ordre ne s'applique pas, comme les comptes OAuth et les clés API. Lorsqu'un compte Kiro stocké existe, la sortie indique que Kiro dispose d'un emplacement de connexion et -que la reconnexion remplace le compte courant. Un résultat vide est toujours un succès. `--json` +où l'ordre ne s'applique pas, comme les comptes OAuth et les clés API. Avec au moins deux comptes Kiro enregistrés et éligibles, par défaut une réponse 429 entraîne automatiquement une rotation vers un autre +compte, en privilégiant celui dont l'allocation restante connue est la plus élevée ; la rotation est activée par la présence de plusieurs comptes et peut être désactivée avec `oauthAccountFailover.enabled: false` ; `ocx account login kiro` ajoute les comptes au pool un par un. Un résultat vide est toujours un succès. `--json` renvoie : ```text 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 2c3197da0b..f8a67cef3f 100644 --- a/docs-site/src/content/docs/fr/reference/configuration/providers.md +++ b/docs-site/src/content/docs/fr/reference/configuration/providers.md @@ -91,6 +91,7 @@ sauvegarde dont le contenu diffère, puis réécrit en identifiants sans préfix | `headers?` | `Record` | En-têtes supplémentaires en amont. L'autorisation, les cookies, les en-têtes de clé API, les nouvelles lignes intégrées et les noms invalides sont rejetés. | | `openRouterRouting?` | `OpenRouterProviderRouting` | Préférences OpenRouter `order`, `only` et `allowFallbacks` par défaut ; valable uniquement pour les OpenRouter canoniques avec `openai-chat`. | | `modelOpenRouterRouting?` | `Record` | Remplacements exacts de l'ID de modèle qui remplacent la préférence OpenRouter à l'échelle du fournisseur. | +| `vercelGatewayRouting?` | `VercelGatewayRouting` | Préférences Vercel AI Gateway par défaut pour `order`, `only` et `sort` (`"cost"` \| `"ttft"` \| `"tps"`) ; valables uniquement pour le fournisseur Vercel AI Gateway canonique avec `openai-chat`. | | `authMode?` | `"key" \| "forward" \| "oauth" \| "local"` | Mode d'authentification (`key` par défaut). Les identifiants OAuth ou d'abonnement sont stockés hors de `config.json` ; `local` est réservé aux fournisseurs dont l'entrée de registre l'autorise. | | `codexAccountMode?` | `"pool" \| "direct"` | Réservé au fournisseur canonique `openai` ; la valeur par défaut est Pool. Le mode Direct contourne l'état du pool. | | `refreshPolicy?` | `"proactive" \| "lazy-only" \| "disabled"` | Remplace la politique Token Guardian de ce fournisseur OAuth. | @@ -100,6 +101,7 @@ sauvegarde dont le contenu diffère, puis réécrit en identifiants sans préfix | `modelReasoningSummaryDelivery?` | `Record` | Énumération de livraison des réponses par modèle ; réécrit un champ de livraison existant. | | `modelAdapters?` | `Record` | Remplacement du protocole `openai-chat` ou `openai-responses` par modèle pour les passerelles multiprotocoles. Les entrées explicites priment sur les valeurs par défaut du registre. Le préréglage OpenCode Go sélectionne Responses pour `gpt-5.6-luna` tout en laissant les modèles apparentés sur leurs protocoles documentés ; DeepSeek peut sélectionner Responses natif pour `deepseek-v4-flash` ; GitHub Copilot déclare des valeurs par défaut limitées à Responses pour sa famille GPT-5 (`gpt-5.3-codex`, `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`), car ces modèles rejettent `/chat/completions` pour le trafic des agents. Les modèles sans valeur intégrée par défaut, comme `gpt-5.4-nano`, peuvent être activés ici. Les services en amont à protocole unique et le transfert canonique ChatGPT rejettent ces remplacements. | | Activation Responses xAI (tableau de bord) | interrupteur | Pour `xai` uniquement, définit ou efface atomiquement les entrées `modelAdapters` de `grok-4.5` et `grok-4.6`. Une seule entrée apparaît comme un état mixte jusqu’à la prochaine écriture. Les autres remplacements et le comportement des tiers restent inchangés. | +| `xaiResponsesXSearch?` | `boolean` | Désactivé par défaut. Sur une destination xAI Responses, ajoute la déclaration `x_search` hébergée par le fournisseur uniquement lorsqu’un outil `web_search` actif subsiste après la normalisation finale de la requête. Les déclarations existantes ne sont pas dupliquées, les sélecteurs `tool_choice`/`allowed_tools` de l’appelant ne sont jamais élargis, et cette option est distincte des options `search.xSearch` du service auxiliaire de recherche web. | | `modelPreferHostedTools?` | `Record` | Activation explicite par modèle exact pour les passerelles Responses hors transfert qui réservent un espace de noms aux outils hébergés. Seul `["image_generation"]` est actuellement accepté ; le modèle correspondant doit utiliser le protocole `openai-responses` et prendre en charge cet outil hébergé. Le proxy supprime les déclarations clientes `image_gen` en conflit et réécrit leurs sélecteurs afin de préserver le choix d'outil de l'appelant. Pour les modèles virtuels `-pro` de l'API OpenAI, l'identifiant public sélectionné est comparé en premier et l'identifiant résolu du modèle de base sur le protocole sert de repli. `modelAdapters` résout d'abord l'identifiant public, puis celui de base ; la seconde résolution détermine le protocole final. Les autres modèles conservent le comportement normal des alias. | | `annotateEmptyToolOutputs?` | `boolean` | Remplace un résultat d’outil présent mais vide par un court marqueur avant qu’il n’atteigne le modèle, afin qu’un résultat vide ne soit pas interprété comme manquant. S’applique aux chaînes vides et aux tableaux de parties contenant uniquement du texte ; les parties d’image, de fichier et chiffrées ne sont jamais modifiées. La valeur par défaut issue du registre intégré est `true` pour DeepSeek ; dans les autres cas, elle n’est pas définie. Définissez `false` pour exclure un fournisseur : une valeur `false` explicite est conservée lors des modifications ultérieures qui omettent ce champ. `PATCH /api/providers?name=` accepte `true`, `false` ou `null` pour effacer le remplacement et revenir au comportement par défaut du registre. | | `reasoningEffortMap?` | `Record` | Alias ​​de fil à l’échelle du fournisseur pour les étiquettes de raisonnement. | @@ -373,6 +375,45 @@ Les clés de modèle sont les identifiants OpenRouter natifs exacts, sans le pr `openrouter/anthropic-claude-sonnet-5` restaure l'identifiant natif `anthropic/claude-sonnet-5` avant d'appliquer la règle du modèle. +## Routage des fournisseurs Vercel AI Gateway + +Vercel AI Gateway peut router un modèle entre plusieurs fournisseurs d'inférence sous-jacents. +`vercelGatewayRouting` configure les préférences à l'échelle du fournisseur ; `modelVercelGatewayRouting` les remplace +pour les identifiants de modèle exacts. Lorsque les deux sont omis, `resolveVercelGatewayRouting()` renvoie `undefined`. +Les générateurs de requêtes Chat omettent alors le champ `provider`, et Vercel AI Gateway conserve son comportement de +routage dynamique par défaut. + +- `order` : identifiants courts des fournisseurs en amont de Vercel AI Gateway, par ordre de priorité. +- `only` : liste d'autorisation explicite limitant les fournisseurs en amont de Vercel AI Gateway admissibles. +- `sort` : trie automatiquement les fournisseurs admissibles par `"cost"` (coût le plus faible), `"ttft"` (délai + avant le premier jeton) ou `"tps"` (jetons par seconde). + +```json +{ + "providers": { + "vercel-ai-gateway": { + "adapter": "openai-chat", + "baseUrl": "https://ai-gateway.vercel.sh/v1", + "apiKey": "${VERCEL_AI_GATEWAY_KEY}", + "vercelGatewayRouting": { + "sort": "ttft" + }, + "modelVercelGatewayRouting": { + "zai/glm-5.2": { + "only": ["novita", "deepinfra"], + "order": ["novita", "deepinfra"] + } + } + } + } +} +``` + +Les clés de modèle sont les sélecteurs de modèle publics de Vercel, sans le préfixe externe du fournisseur OpenCodex. +La sélection de `vercel-ai-gateway/zai-glm-5.2` restaure l'identifiant natif `zai/glm-5.2` avant d'appliquer la règle du +modèle. Le même mappage s'applique à un sélecteur natif `vercel/` : utilisez le sélecteur encodé +`vercel-ai-gateway/vercel-` dans OpenCodex et conservez `vercel/` comme clé de modèle. + ## Listes autorisées de modèles statiques Réglez `liveModels: false` pour exposer uniquement `models`. Si `models` est vide ou omis, le fournisseur n'expose diff --git a/docs-site/src/content/docs/fr/reference/configuration/routing.md b/docs-site/src/content/docs/fr/reference/configuration/routing.md index ab0b1718ca..110d2fcd66 100644 --- a/docs-site/src/content/docs/fr/reference/configuration/routing.md +++ b/docs-site/src/content/docs/fr/reference/configuration/routing.md @@ -29,6 +29,16 @@ opencodex résout le modèle demandé dans l’ordre suivant : Les fournisseurs désactivés sont exclus. Un espace de noms explicite qui désigne un fournisseur désactivé échoue au lieu de passer aux règles suivantes. Pour les règles susceptibles de correspondre à plusieurs fournisseurs, les entrées sont examinées dans leur ordre d’insertion JSON. Utilisez donc un espace de noms explicite lorsqu’un modèle non qualifié peut être ambigu. +### Redirections des modèles bloqués + +`blockedModelRedirects` est un `Record` facultatif de premier niveau associant des remplacements exacts d’identifiants de modèle résolus ; il est non défini par défaut. Il s’applique après l’ordre de résolution ci-dessus : une correspondance conserve la route du fournisseur et du compte déjà sélectionnée, ne remplace que l’identifiant du modèle en amont et enregistre le motif de routage `blocked-model-redirect`. L’omission de la clé ne modifie pas le routage. + +```json +{ + "blockedModelRedirects": { "gpt-5.6-terra": "gpt-5.6-luna" } +} +``` + ## Sélecteurs exacts de comptes Codex `codexAccountNamespaces` associe un sélecteur public, par exemple `side`, à un compte Codex enregistré. Une requête pour `side/gpt-5.6-sol` utilise uniquement ce compte, même lorsque le fournisseur canonique `openai` fonctionne en mode Direct, et envoie en amont l’identifiant non qualifié `gpt-5.6-sol`. Seuls les identifiants natifs non qualifiés de la famille OpenAI sont valides après le sélecteur. @@ -46,7 +56,7 @@ Chaque clé de combinaison est un identifiant conforme à `[A-Za-z0-9][A-Za-z0-9 | Clé | Type | Valeur par défaut | Signification | | --- | --- | --- | --- | | `targets` | `{ provider: string; model: string; weight?: number }[]` | requis | Routes concrètes ordonnées. `weight` est compris entre 1 et 10000 et vaut `1` par défaut. | -| `strategy?` | `"failover" \| "round-robin"` | `"failover"` | Stratégie de sélection. L’ordre des cibles définit la priorité de repli ; les poids produisent une rotation pondérée régulière. | +| `strategy?` | `"failover" \| "round-robin" \| "random" \| "least-used" \| "reset-window"` | `"failover"` | Stratégie de sélection. L’ordre des cibles définit la priorité de `failover` ; les poids déterminent les sélections de `round-robin` et de `random` ; `least-used` suit les réussites enregistrées ; `reset-window` suit la réinitialisation de quota la plus proche. | | `stickyLimit?` | `number` | `1` | Nombre de requêtes réussies conservées dans un même lot de rotation. Plage de 1 à 100. | | `defaultEffort?` | `"low" \| "medium" \| "high" \| "xhigh" \| "max" \| "ultra" \| null` | non défini | Appliqué uniquement lorsque l’appelant ne précise aucun effort et que la cible sélectionnée annonce le niveau demandé. | | `imageInput?` | `"auto" \| "disabled"` | `"auto"` | `"auto"` publie les images uniquement lorsque toutes les cibles les prennent en charge ; `"disabled"` impose le texte seul, retire les images des modalités publiées et rejette les requêtes qui en contiennent avant leur distribution. | @@ -127,7 +137,7 @@ Les preuves de quota ne modifient jamais la sélection du compte, l’affinité ### Combinaisons et profils de politique -- Une **combinaison** applique un routage explicite, ordonné ou pondéré, avec repli : l’ordre configuré — ou la rotation pondérée régulière — détermine la cible, et les échecs font avancer dans la liste. +- Une **combinaison** applique un routage explicite des cibles avec une stratégie configurable (`failover` ordonné, répartition pondérée avec `round-robin`, répartition aléatoire avec `random`, `least-used` ou `reset-window`) : la stratégie configurée détermine la cible, et les échecs pouvant être relancés font avancer dans la liste. - Un **profil de politique** sélectionne un candidat configuré selon les preuves disponibles : les exigences strictes de capacité filtrent d’abord les candidats, puis une notation déterministe classe ceux qui restent. Les deux mécanismes sont des espaces de noms virtuels, avec des alias et une validation des collisions ; ils diffèrent par la méthode de sélection. La notation d’un profil combine la composante de priorité configurée avec les dimensions de santé (RI-06), de quota (RI-07) et de coût (RI-08) lorsque les preuves existent. Le poids `latency` est intégré à la part de priorité plutôt que noté séparément. diff --git a/docs-site/src/content/docs/fr/reference/management-api.md b/docs-site/src/content/docs/fr/reference/management-api.md index 46a0eb0278..cde2aa143c 100644 --- a/docs-site/src/content/docs/fr/reference/management-api.md +++ b/docs-site/src/content/docs/fr/reference/management-api.md @@ -143,6 +143,12 @@ réestimée d'après la tarification active au moment de la lecture du résumé. et non de frais d'abonnement. Les nouvelles requêtes du pool principal utilisent le libellé réservé `main` ; les anciennes lignes `openai` sans qualification restent dans une catégorie ambiguë au lieu d'être réaffectées d'après la configuration actuelle. +Les lignes de `models`, `providers` et `days[].models` comportent également `cacheHitRate` : la part des jetons +d'entrée servis depuis le cache d'invites du fournisseur, limitée à `[0, 1]`. Cette valeur est `null` — jamais `0` — +lorsque le fournisseur n'a transmis aucune télémétrie de cache ou que la ligne ne contient aucun jeton d'entrée, car +« aucune donnée de cache » et « un véritable taux de succès de 0 % » sont deux faits distincts, et un graphique qui +les représente de la même manière est trompeur. + :::caution Les points de terminaison de nettoyage du stockage peuvent déplacer ou supprimer définitivement les données de session archivées. Toujours prévisualiser d’abord et soumettez le résumé renvoyé. Préférez la quarantaine lorsqu’une récupération peut être nécessaire. 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 4886a05926..38bb350903 100644 --- a/docs-site/src/content/docs/fr/reference/proxy-formats.md +++ b/docs-site/src/content/docs/fr/reference/proxy-formats.md @@ -96,6 +96,22 @@ Lorsqu'il est disponible, `input_tokens_details` peut également inclure `cache_ les objets de détail constituent une garantie de compatibilité pour les clients Responses stricts ; zéro peut signifier « non signalé », pas nécessairement « le prestataire n’a effectué aucun travail de ce type ». +### Corréler une réponse avec son journal de requête + +Chaque réponse HTTP Responses admise comporte un en-tête `x-opencodex-request-id` contenant un identifiant généré +par le proxy sous la forme `ocx-<32 hex>`. C'est la clé qui relie une réponse à sa ligne dans le journal des requêtes +et dans les rapports d'utilisation. + +Le proxy génère toujours cette valeur et remplace tout identifiant fourni par l'appelant ou renvoyé par le service en +amont. Elle est donc propre à ce proxy et peut être utilisée en toute confiance comme clé de corrélation. L'en-tête est +nommé dans `Access-Control-Expose-Headers`, ce qui permet au JavaScript du navigateur de le lire entre différentes +origines : sans cela, un en-tête `x-` personnalisé reste invisible pour `response.headers.get()`, même lorsqu'il est +présent sur le réseau. + +Les réponses rejetées lors de l'authentification ou de l'admission de l'origine n'atteignent jamais cette couche +d'encapsulation et ne comportent aucun identifiant. L'absence de cet en-tête signifie donc que la requête a été refusée +avant sa journalisation. + ### Mise à niveau WebSocket sur le même chemin Lorsque `websockets` est activé, un client peut mettre à niveau `/v1/responses` au lieu d’ouvrir une requête HTTP POST. diff --git a/docs-site/src/content/docs/ja/guides/combos.md b/docs-site/src/content/docs/ja/guides/combos.md index e60e31b938..068689bf8c 100644 --- a/docs-site/src/content/docs/ja/guides/combos.md +++ b/docs-site/src/content/docs/ja/guides/combos.md @@ -101,6 +101,18 @@ ocx combo set balanced \ 重みはパーセンテージではなく相対的なものです。重み `2,1` と `200,100` は同じ比率を表します。意図を伝える小さな値を好みます。 ::: +### `random`: リクエストごとの加重抽選 + +`random` は、リクエストごとに適格なターゲットを 1 つ、`weight` に比例する確率で抽選します。各リクエストは独立した抽選となるため、`round-robin` の決定論的なパターンや固定性なしに、複数のターゲットへトラフィックが分散されます。`stickyLimit` はこの戦略に影響しません。 + +### `least-used`: 成功数が最も少ないターゲットを優先 + +`least-used` は、この opencodex プロセスに記録された成功リクエスト数が最も少ない適格なターゲットへ、各リクエストをルーティングします。再起動時にカウントはゼロから始まり、同数の場合は構成順序が維持されます。`weight` と `stickyLimit` はこの戦略に影響しません。 + +### `reset-window`: 最も早いクォータリセットに従う + +`reset-window` は、キャッシュされたプロバイダーのクォータスナップショットで、次回のウィンドウリセット(5 時間、週次、月次、またはカスタム)が最も早い適格なターゲットへ、各リクエストをルーティングします。これにより、最初にクォータが補充されるプロバイダーを先に使用します。新しいクォータデータがないターゲットと、リセット時刻が同じターゲットでは、構成順序が維持されます。`weight` と `stickyLimit` はこの戦略に影響しません。 + ## ターゲットが失敗すると何が起こるか コンボ障害は、**ホップ** 障害と **ターミナル** 障害に分類されます。 @@ -218,9 +230,9 @@ ocx combo remove --yes |フィールド |必須 |デフォルト |ルール | | --- | --- | --- | --- | | `targets` |はい | — |構成された `{ provider, model, weight? }` ターゲットの空でない順序付けされた配列。重複するプロバイダーとモデルのペアは拒否されます。 | -| `targets[].weight` |いいえ | `1` | 1 ~ 10,000 の整数。ラウンドロビンで使用されます。フェイルオーバーによって無視されます。 | -| `strategy` |いいえ | `"failover"` | `"failover"` または `"round-robin"`。 | -| `stickyLimit` |いいえ | `1` |ラウンドロビン選択ごとの成功したリクエストの数は 1 ~ 100 の整数です。 | +| `targets[].weight` |いいえ | `1` | 1 ~ 10,000 の整数。`round-robin` と `random` で使用され、`failover`、`least-used`、`reset-window` では無視されます。 | +| `strategy` |いいえ | `"failover"` | `"failover"`、`"round-robin"`、`"random"`、`"least-used"`、`"reset-window"`。 | +| `stickyLimit` |いいえ | `1` | `round-robin` の 1 回の選択あたり、成功したリクエスト数を指定する 1 ~ 100 の整数。`round-robin` にのみ適用されます。 | | `defaultEffort` |いいえ | `null` | `low`、`medium`、`high`、`xhigh`、`max`、または `ultra`;呼び出し元が努力を省略し、ターゲットがサポートをアドバタイズした場合にのみ適用されます。 | | `alias` |いいえ |なし |オプションのトリミングされたパブリック モデル ID。上記のエイリアス ルールを使用します。空の値はエイリアスなしで保存されます。 | | `nativeAlias` |いいえ | `false` | 現在サポートされている bare native alias に routing/catalog の優先権を明示的に与えます。 | diff --git a/docs-site/src/content/docs/ja/reference/cli/providers-accounts.md b/docs-site/src/content/docs/ja/reference/cli/providers-accounts.md index cab525623a..babd71c61f 100644 --- a/docs-site/src/content/docs/ja/reference/cli/providers-accounts.md +++ b/docs-site/src/content/docs/ja/reference/cli/providers-accounts.md @@ -111,9 +111,9 @@ Codex pool selection applies to the next request after clearing existing affinit } ``` -### `ocx account list [provider] [--json] [--all]` +### `ocx account list [provider] [--json] [--all] [--quota [--refresh]]` -プロバイダーを使用しない場合、Codex プール、OAuth アカウント、および設定された API キー プールが一覧表示されます。 `--all` が存在しない限り、空のプロバイダーはスキップされます。プロバイダーを使用すると、その資格情報ファミリーのみがリストされます。人間の出力では `PROVIDER TYPE ID PLAN/LABEL PRIORITY STATUS` を使用します。手動で選択した Codex 行には `selected` というマークが付けられます。保存された Kiro アカウントが存在する場合、出力には、Kiro には 1 つのログイン スロットがあり、再度サインインすると現在のアカウントが置き換えられることが示されます。結果が空であっても成功です。 `--json` は次を返します: +プロバイダーを使用しない場合、Codex プール、OAuth アカウント、および設定された API キー プールが一覧表示されます。 `--all` が存在しない限り、空のプロバイダーはスキップされます。プロバイダーを使用すると、その資格情報ファミリーのみがリストされます。人間の出力では `PROVIDER TYPE ID PLAN/LABEL PRIORITY STATUS` を使用します。手動で選択した Codex 行には `selected` というマークが付けられます。利用可能な Kiro アカウントが 2 つ以上保存されている場合、既定では 429 を受けると別のアカウントへ自動的に切り替え、既知の残り利用枠が最も多いアカウントを優先します。この切り替えはアカウントの存在によって有効になり、`oauthAccountFailover.enabled: false` で無効にできます。`ocx account login kiro` はアカウントを 1 件ずつプールへ追加します。結果が空であっても成功です。 `--json` は次を返します: ```text { accounts: AccountRow[], notes: string[] } 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 cbb6e5754f..fd369105d9 100644 --- a/docs-site/src/content/docs/ja/reference/configuration/providers.md +++ b/docs-site/src/content/docs/ja/reference/configuration/providers.md @@ -79,6 +79,7 @@ account を削除しても mapping は保持され、同じ id を再追加す | `headers?` | `Record` |追加の上流ヘッダー。認証、Cookie、API キー ヘッダー、埋め込まれた改行、および無効な名前は拒否されます。 | | `openRouterRouting?` | `OpenRouterProviderRouting` |デフォルトの OpenRouter `order`、`only`、および `allowFallbacks` 設定。 `openai-chat` を持つ正規 OpenRouter に対してのみ有効です。 | | `modelOpenRouterRouting?` | `Record` |プロバイダー全体の OpenRouter 設定を置き換える正確なモデル ID のオーバーライド。 | +| `vercelGatewayRouting?` | `VercelGatewayRouting` |デフォルトの Vercel AI Gateway `order`、`only`、および `sort` (`"cost"` \| `"ttft"` \| `"tps"`) 設定。`openai-chat` を使用する正規の Vercel AI Gateway に対してのみ有効です。 | | `authMode?` | `"key" \| "forward" \| "oauth" \| "local"` |認証モード (デフォルトは `key`)。 OAuth/サブスクリプション認証情報は `config.json` の外部に保存されます。 `local` は、レジストリ エントリで許可されているプロバイダーに限定されます。 | | `codexAccountMode?` | `"pool" \| "direct"` |正規の `openai` のみ。デフォルトはプールです。直接はプール状態をバイパスします。 | | `refreshPolicy?` | `"proactive" \| "lazy-only" \| "disabled"` |この OAuth プロバイダーの Token Guardian ポリシーをオーバーライドします。 | @@ -88,6 +89,7 @@ account を削除しても mapping は保持され、同じ id を再追加す | `modelReasoningSummaryDelivery?` | `Record` |モデルごとの応答配信列挙型。既存の配信フィールドを書き換えます。 | | `modelAdapters?` | `Record` | 混合配線ゲートウェイのモデルごとの `openai-chat` または `openai-responses` 配線オーバーライド。明示的なエントリはレジストリのデフォルトを破ります。DeepSeek のプリセットは `deepseek-v4-flash` のネイティブ Responses を選択でき、GitHub Copilot は GPT-5 ファミリー (`gpt-5.3-codex`, `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`) を Responses 専用デフォルトとして宣言します。これらのモデルはエージェント トラフィックで `/chat/completions` を拒否するためです。`gpt-5.4-nano` のようなビルトイン デフォルトのないモデルはここでオプトインできます。単線アップストリーム ピンと正規の ChatGPT 転送はオーバーライドを拒否します。 | | xAI Responses オプトイン(ダッシュボード) | スイッチ | `xai` のみで、`grok-4.5` と `grok-4.6` の `modelAdapters` エントリを原子的に設定または削除します。片方だけの場合は、次のスイッチ操作で両方が正規化されるまで混合状態を表示します。他のオーバーライドと tier 動作は変わりません。 | +| `xaiResponsesXSearch?` | `boolean` | デフォルトでは無効です。xAI Responses の宛先では、最終的なリクエスト正規化後もライブの `web_search` ツールが残っている場合にのみ、プロバイダーがホストする `x_search` 宣言を追加します。既存の宣言は重複させず、呼び出し元の `tool_choice` / `allowed_tools` セレクターの範囲を拡張することもありません。また、これは `search.xSearch` オプションを持つウェブ検索サイドカーとは別です。 | | `modelPreferHostedTools?` | `Record` | hosted tool namespace を予約する非 forward Responses gateway 向けの完全一致モデル opt-in。現在は `["image_generation"]` のみを受け付けます。一致したモデルは `openai-responses` wire を使い、その hosted tool をサポートする必要があります。競合するクライアント `image_gen` 宣言を除去し、呼び出し元の tool choice を維持するため selector も書き換えます。OpenAI API の仮想 `-pro` モデルでは、まず選択した公開 ID に一致させ、解決後のベース wire-model ID をフォールバックとして使用します。`modelAdapters` は公開 ID、次にベース ID の順に解決し、後者の結果が最終 wire を決めます。未設定のモデルは通常の alias 動作を維持します。 | | `annotateEmptyToolOutputs?` | `boolean` | 存在するものの空であるツール結果を、モデルに届く前に短いマーカーへ置き換え、空白の結果が欠落した結果として解釈されないようにします。空文字列とテキストのみのパーツ配列に適用されます。画像、ファイル、暗号化されたパーツには一切手を加えません。組み込みレジストリでは `DeepSeek` のデフォルトが `true` で、それ以外は未設定です。プロバイダーを対象外にするには `false` を設定します。明示的な `false` は、後続の編集でこのフィールドが省略されても保持されます。`PATCH /api/providers?name=` は `true`、`false`、またはオーバーライドを消去してレジストリのデフォルト動作へ戻すための `null` を受け付けます。 | | `reasoningEffortMap?` | `Record` |ラベルを推論するためのプロバイダー全体のワイヤ エイリアス。 | @@ -299,6 +301,37 @@ OpenRouter は、複数の推論プロバイダーを通じて 1 つのモデル モデル キーは、外部の opencodex プロバイダー プレフィックスを除いた、正確なネイティブ OpenRouter ID です。 `openrouter/anthropic-claude-sonnet-5` を選択すると、モデル ルールを適用する前のネイティブ `anthropic/claude-sonnet-5` が復元されます。 +## Vercel AI Gateway プロバイダーのルーティング + +Vercel AI Gateway は、1 つのモデルを複数の基盤となる推論プロバイダーへルーティングできます。`vercelGatewayRouting` はプロバイダー全体の設定を構成し、`modelVercelGatewayRouting` は正確なモデル ID ごとにそれを置き換えます。両方とも未設定の場合、`resolveVercelGatewayRouting()` は `undefined` を返すため、Chat リクエスト ビルダーは `provider` フィールドを省略し、Vercel AI Gateway のデフォルトの動的ルーティング動作が維持されます。 + +- `order`: 優先順位順の Vercel AI Gateway アップストリーム プロバイダー スラッグ。 +- `only`: 対象となる Vercel AI Gateway アップストリーム プロバイダーを制限する明示的な許可リスト。 +- `sort`: 対象となるプロバイダーを `"cost"` (最安コスト)、`"ttft"` (最初のトークンまでの時間)、または `"tps"` (1 秒あたりのトークン数) で自動的に並べ替えます。 + +```json +{ + "providers": { + "vercel-ai-gateway": { + "adapter": "openai-chat", + "baseUrl": "https://ai-gateway.vercel.sh/v1", + "apiKey": "${VERCEL_AI_GATEWAY_KEY}", + "vercelGatewayRouting": { + "sort": "ttft" + }, + "modelVercelGatewayRouting": { + "zai/glm-5.2": { + "only": ["novita", "deepinfra"], + "order": ["novita", "deepinfra"] + } + } + } + } +} +``` + +モデル キーは、外側の opencodex プロバイダー プレフィックスを除いた Vercel の公開モデル セレクターです。`vercel-ai-gateway/zai-glm-5.2` を選択すると、モデル ルールを適用する前にネイティブの `zai/glm-5.2` が復元されます。ネイティブの `vercel/` セレクターにも同じマッピングが適用されます。opencodex ではエンコードされた `vercel-ai-gateway/vercel-` セレクターを使用し、モデル キーには `vercel/` を指定してください。 + ## 静的モデルのホワイトリスト `models` のみを公開するように `liveModels: false` を設定します。 `models` が空であるか省略されている場合、プロバイダーはルーティングされたモデルを公開しません。ライブ ディスカバリは、キャッシュする前に 4 MiB または 2,000 を超える生のモデル行を拒否します。組み込みのプリセットは下限を使用し、チャットに適した行にフィルターをかけることができます。サイズが大きすぎる、または形式が正しくない結果は、古い/構成されたフォールバックに続きます。ゼロに適格な有効な結果は引き続き権威を持ち、暗黙的に置き換えられたり切り捨てられたりすることはありません。 diff --git a/docs-site/src/content/docs/ja/reference/configuration/routing.md b/docs-site/src/content/docs/ja/reference/configuration/routing.md index de0cb31ab6..18b238c8bf 100644 --- a/docs-site/src/content/docs/ja/reference/configuration/routing.md +++ b/docs-site/src/content/docs/ja/reference/configuration/routing.md @@ -29,6 +29,16 @@ opencodex は、要求されたモデルを次の順序で解決します。 無効なプロバイダーは除外されます。無効なプロバイダーの明示的な名前空間は、フォールスルーではなく失敗します。プロバイダー エントリは、複数のプロバイダーに一致する可能性のあるルールの JSON 挿入順序でチェックされるため、ベア モデルがあいまいな可能性がある場合は明示的な名前空間を使用します。 +### ブロック対象モデルのリダイレクト + +`blockedModelRedirects` は、完全一致する解決済みモデル ID の置換を指定する任意のトップレベル `Record` で、デフォルトでは未設定です。上記の解決順序の後に適用されます。一致した場合、すでに選択されたプロバイダーとアカウントのルートは維持され、上流モデル ID のみが置き換えられ、ルート理由として `blocked-model-redirect` が記録されます。このキーを省略すると、ルーティングは変更されません。 + +```json +{ + "blockedModelRedirects": { "gpt-5.6-terra": "gpt-5.6-luna" } +} +``` + ## Codex アカウントの明示的な selector `codexAccountNamespaces` は `side` のような公開 selector を保存済み Codex アカウント 1 つに @@ -57,7 +67,7 @@ picker catalog の convergence だけが保留中で routing change は失われ |キー |タイプ |デフォルト |意味 | | --- | --- | --- | --- | | `targets` | `{ provider: string; model: string; weight?: number }[]` |必須 |具体的なルートを指示しました。 `weight` は 1 ~ 10000 で、デフォルトは `1` です。 | -| `strategy?` | `"failover" \| "round-robin"` | `"failover"` |選択戦略。ターゲットの順序はフェイルオーバーの優先順位です。重みはスムーズな重み付きラウンドロビンを形成します。 | +| `strategy?` | `"failover" \| "round-robin" \| "random" \| "least-used" \| "reset-window"` | `"failover"` |選択戦略。ターゲットの順序は `failover` の優先順位となり、`weight` は `round-robin` と `random` の抽選に影響し、`least-used` は記録された成功数に従い、`reset-window` は最も早いクォータリセットに従います。 | | `stickyLimit?` | `number` | `1` |成功したリクエストは 1 つのラウンドロビン バッチに保持されます。範囲は 1 ~ 100。 | | `defaultEffort?` | `"low" \| "medium" \| "high" \| "xhigh" \| "max" \| "ultra" \| null` |設定を解除する |呼び出し元が努力を省略し、選択されたターゲットが要求されたラングをアドバタイズする場合にのみ適用されます。 | | `alias?` | `string` | — |正規のピッカー スラグの代わりのオプションのパブリック モデル ID。 | @@ -99,7 +109,7 @@ picker catalog の convergence だけが保留中で routing change は失われ CLI: `ocx route policy list`、`ocx route policy show `、`ocx route policy dry-run --model-context --tools`、`ocx route policy evaluate `。 -コンボは明示的な順序・重み付きターゲットのルーティングとフェイルオーバーです。ポリシープロファイルは、候補間の証拠に基づく選択です。 +コンボでは、明示的なターゲットを `failover`、`round-robin`、`random`、`least-used`、`reset-window` のいずれかでルーティングします。設定された戦略がターゲットを決定し、再試行可能な失敗時にはリスト内の次のターゲットへ進みます。ポリシープロファイルは、候補間の証拠に基づく選択です。 ## リクエスト履歴とルーティング分析 diff --git a/docs-site/src/content/docs/ja/reference/management-api.md b/docs-site/src/content/docs/ja/reference/management-api.md index 7982a6341c..7024b2ef45 100644 --- a/docs-site/src/content/docs/ja/reference/management-api.md +++ b/docs-site/src/content/docs/ja/reference/management-api.md @@ -120,6 +120,8 @@ Authorization: Bearer | `POST /api/storage/cleanup-policy/run` |手動クリーンアップ ポリシーの実行を開始します。 409 `already_running`; 500`cleanup_failed` | | `GET /api/storage/cleanup-policy/test-stream` |テスト専用ポリシー ストリーム フック | 404 `not_found` 利用できない場合 | +`models`、`providers`、および `days[].models` の各行にも `cacheHitRate` が含まれます。これは、プロバイダーのプロンプト キャッシュから供給された入力トークンの割合で、`[0, 1]` の範囲に制限されます。プロバイダーがキャッシュ テレメトリを報告しなかった場合、または行に入力トークンがない場合は、`0` ではなく `null` になります。「キャッシュ データなし」と「実際のヒット率 0%」は異なる事実であり、それらを同じように描画するチャートは誤解を招くためです。 + :::caution ストレージ クリーンアップ エンドポイントは、アーカイブされたセッション データを移動または完全に削除できます。必ず最初にプレビューして、返されたダイジェストを送信してください。回復が必要な場合は隔離を優先します。 ::: 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 ff329cf29f..aaff91eb9f 100644 --- a/docs-site/src/content/docs/ja/reference/proxy-formats.md +++ b/docs-site/src/content/docs/ja/reference/proxy-formats.md @@ -73,6 +73,14 @@ provider events → internal adapter events → client dialect 利用可能な場合、`input_tokens_details` には `cache_write_tokens` も含めることができます。常に存在する詳細オブジェクトは、厳密な応答クライアントに対する互換性を保証します。ゼロは「報告されていない」ことを意味する場合がありますが、必ずしも「プロバイダーがそのような作業を実行していない」とは限りません。 +### 応答とリクエストログの関連付け + +アドミッションを通過したすべての HTTP Responses 応答には、プロキシが生成した `ocx-<32 hex>` 形式の ID を格納する `x-opencodex-request-id` ヘッダーが付与されます。この値は、応答をリクエストログおよび使用状況レポート内の対応する行に結び付けるキーです。 + +プロキシは常にこの値を生成し、呼び出し元が指定した ID やアップストリームが返した ID を上書きします。そのため、このプロキシに固有であり、相関キーとして安全に信頼できます。このヘッダーは `Access-Control-Expose-Headers` に列挙されているため、ブラウザーの JavaScript からクロスオリジンで読み取れます。カスタムの `x-` ヘッダーは、実際にワイヤ上に存在していても、そうしなければ `response.headers.get()` からは見えません。 + +認証またはオリジンのアドミッションで拒否されたリクエストはこのラッパーに到達せず、ID も付与されません。そのため、ヘッダーがない場合は、リクエストがログに記録される前に拒否されたことを意味します。 + ### 同じパスでの WebSocket のアップグレード `websockets` が有効な場合、クライアントは HTTP POST を開く代わりに `/v1/responses` をアップグレードできます。認証とオリジンの許可は、WebSocket ハンドシェイク中に行われます。それらは各フレーム内で繰り返されません。 diff --git a/docs-site/src/content/docs/ko/guides/combos.md b/docs-site/src/content/docs/ko/guides/combos.md index ebaddd0801..6028e337cd 100644 --- a/docs-site/src/content/docs/ko/guides/combos.md +++ b/docs-site/src/content/docs/ko/guides/combos.md @@ -101,6 +101,18 @@ ocx combo set balanced \ 가중치는 비율이며 퍼센트가 아닙니다. `2,1`과 `200,100`은 같은 비율을 뜻합니다. 의도를 분명히 보여 주는 작은 값을 쓰는 편이 좋습니다. ::: +### `random`: 요청마다 가중 추첨 + +`random`은 요청마다 적합한 대상 하나를 `weight`에 비례한 확률로 추첨합니다. 각 요청은 독립적으로 추첨되므로 `round-robin`의 결정적 패턴이나 고정성 없이 트래픽이 대상 전체에 분산됩니다. `stickyLimit`은 이 전략에 영향을 주지 않습니다. + +### `least-used`: 성공 횟수가 가장 적은 대상 우선 + +`least-used`는 이 opencodex 프로세스가 기록한 성공 요청 수가 가장 적은 적합한 대상으로 각 요청을 라우팅합니다. 재시작하면 횟수는 0부터 시작하며, 동률이면 설정 순서를 유지합니다. `weight`와 `stickyLimit`은 이 전략에 영향을 주지 않습니다. + +### `reset-window`: 가장 가까운 할당량 재설정 따르기 + +`reset-window`는 캐시된 공급자 할당량 스냅샷에서 가장 가까운 다음 기간 재설정(5시간, 주간, 월간 또는 사용자 지정)이 표시되는 적합한 대상으로 각 요청을 라우팅합니다. 이렇게 하면 가장 먼저 새로 충전되는 공급자를 사용합니다. 최신 할당량 데이터가 없는 대상과 동률인 대상은 설정 순서를 유지합니다. `weight`와 `stickyLimit`은 이 전략에 영향을 주지 않습니다. + ## 대상 실패 시 동작 콤보 실패는 **홉** 실패와 **종결** 실패로 나뉩니다. @@ -217,9 +229,9 @@ ocx combo remove --yes | 필드 | 필수 | 기본값 | 규칙 | | --- | --- | --- | --- | | `targets` | 예 | — | 설정된 `{ provider, model, weight? }` 대상의 비어 있지 않은 순서가 있는 배열이어야 합니다. 중복된 provider/model 쌍은 거부됩니다. | -| `targets[].weight` | 아니요 | `1` | 1에서 10,000 사이의 정수입니다. round-robin에서 사용되며 failover에서는 무시됩니다. | -| `strategy` | 아니요 | `"failover"` | `"failover"` 또는 `"round-robin"`입니다. | -| `stickyLimit` | 아니요 | `1` | round-robin 선택 한 번당 성공 요청 1에서 100회 사이의 정수입니다. | +| `targets[].weight` | 아니요 | `1` | 1에서 10,000 사이의 정수입니다. `round-robin`과 `random`에서 사용되며, `failover`, `least-used`, `reset-window`에서는 무시됩니다. | +| `strategy` | 아니요 | `"failover"` | 허용되는 값은 `"failover"`, `"round-robin"`, `"random"`, `"least-used"`, `"reset-window"`입니다. | +| `stickyLimit` | 아니요 | `1` | 한 번의 `round-robin` 선택에 유지되는 성공 요청 수로, 1에서 100 사이의 정수입니다. `round-robin`에만 적용됩니다. | | `defaultEffort` | 아니요 | `null` | `low`, `medium`, `high`, `xhigh`, `max`, 또는 `ultra`입니다. 호출자가 effort를 생략하고 대상이 지원을 광고할 때만 적용됩니다. | | `alias` | 아니요 | 없음 | 선택적으로 앞뒤 공백을 제거한 공개 모델 ID입니다. 위의 alias 규칙을 따릅니다. 빈 값은 alias 없음으로 저장됩니다. | | `nativeAlias` | 아니요 | `false` | 현재 지원되는 bare native alias가 routing/catalog 우선권을 갖도록 명시적으로 허용합니다. | diff --git a/docs-site/src/content/docs/ko/reference/cli/providers-accounts.md b/docs-site/src/content/docs/ko/reference/cli/providers-accounts.md index 5b7bd66ca9..67f4562617 100644 --- a/docs-site/src/content/docs/ko/reference/cli/providers-accounts.md +++ b/docs-site/src/content/docs/ko/reference/cli/providers-accounts.md @@ -111,9 +111,9 @@ Codex pool selection applies to the next request after clearing existing affinit } ``` -### `ocx account list [provider] [--json] [--all]` +### `ocx account list [provider] [--json] [--all] [--quota [--refresh]]` -제공자를 지정하지 않으면 Codex 풀, OAuth 계정, 설정된 API 키 풀을 나열합니다. `--all`이 없으면 비어 있는 제공자는 건너뜁니다. 제공자를 지정하면 해당 자격 증명 계열만 나열합니다. 사람이 보는 출력은 `PROVIDER TYPE ID PLAN/LABEL PRIORITY STATUS` 형식을 사용하며, 수동으로 선택한 Codex 행에는 `selected`가 표시됩니다. 저장된 Kiro 계정이 있으면 출력에 Kiro에는 로그인 슬롯이 하나뿐이고 다시 로그인하면 현재 계정을 바꾼다는 점이 표시됩니다. 빈 결과도 성공입니다. `--json`은 다음을 반환합니다: +제공자를 지정하지 않으면 Codex 풀, OAuth 계정, 설정된 API 키 풀을 나열합니다. `--all`이 없으면 비어 있는 제공자는 건너뜁니다. 제공자를 지정하면 해당 자격 증명 계열만 나열합니다. 사람이 보는 출력은 `PROVIDER TYPE ID PLAN/LABEL PRIORITY STATUS` 형식을 사용하며, 수동으로 선택한 Codex 행에는 `selected`가 표시됩니다. 사용 가능한 Kiro 계정이 두 개 이상 저장되어 있으면 기본적으로 429 응답 시 다른 계정으로 자동 전환하며, 알려진 잔여 할당량이 가장 많은 계정을 우선합니다. 이 전환은 계정 존재만으로 활성화되며 `oauthAccountFailover.enabled: false`로 끌 수 있습니다. `ocx account login kiro`는 계정을 한 번에 하나씩 풀에 추가합니다. 빈 결과도 성공입니다. `--json`은 다음을 반환합니다: ```text { accounts: AccountRow[], notes: string[] } 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 2b5223466f..7c599e9b8f 100644 --- a/docs-site/src/content/docs/ko/reference/configuration/providers.md +++ b/docs-site/src/content/docs/ko/reference/configuration/providers.md @@ -79,6 +79,7 @@ managed map을 활성화하면 privacy-safe selector를 만들고, 이후 계정 | `headers?` | `Record` | 추가 상위 헤더입니다. Authorization, cookies, API-key 헤더, 내장 개행, 잘못된 이름은 허용하지 않습니다. | | `openRouterRouting?` | `OpenRouterProviderRouting` | 기본 OpenRouter `order`, `only`, `allowFallbacks` 선호도입니다. 정식 OpenRouter와 `openai-chat`에서만 유효합니다. | | `modelOpenRouterRouting?` | `Record` | 공급자 전반의 OpenRouter 선호도를 덮어쓰는 정확한 모델 id별 재정의입니다. | +| `vercelGatewayRouting?` | `VercelGatewayRouting` | 기본 Vercel AI Gateway `order`, `only`, `sort`(`"cost"` \| `"ttft"` \| `"tps"`) 선호도입니다. 정식 Vercel AI Gateway와 `openai-chat`에서만 유효합니다. | | `authMode?` | `"key" \| "forward" \| "oauth" \| "local"` | 인증 모드입니다. 기본값은 `key`입니다. OAuth/구독 자격 증명은 `config.json` 밖에 저장되며, `local`은 레지스트리 항목이 허용하는 공급자에서만 사용할 수 있습니다. | | `codexAccountMode?` | `"pool" \| "direct"` | 정식 `openai` 전용입니다. 기본값은 Pool입니다. Direct는 풀 상태를 우회합니다. | | `refreshPolicy?` | `"proactive" \| "lazy-only" \| "disabled"` | 이 OAuth 공급자의 Token Guardian 정책을 덮어씁니다. | @@ -88,6 +89,7 @@ managed map을 활성화하면 privacy-safe selector를 만들고, 이후 계정 | `modelReasoningSummaryDelivery?` | `Record` | 모델별 Responses 전달 enum입니다. 기존 delivery 필드를 다시 씁니다. | | `modelAdapters?` | `Record` | 혼합 와이어 게이트웨이를 위한 모델별 `openai-chat` 또는 `openai-responses` 와이어 재정의입니다. 명시적 항목이 레지스트리 기본값보다 우선합니다. DeepSeek 프리셋은 `deepseek-v4-flash`에 네이티브 Responses를 선택할 수 있고, GitHub Copilot은 GPT-5 계열(`gpt-5.3-codex`, `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`)을 Responses 전용 기본값으로 선언합니다. 이 모델들은 에이전트 트래픽에서 `/chat/completions`를 거부하기 때문입니다. `gpt-5.4-nano`처럼 기본값이 없는 모델은 여기서 직접 옵트인할 수 있습니다. 단일 와이어 상위 항목과 정식 ChatGPT forward는 재정의를 거부합니다. | | xAI Responses 옵트인(대시보드) | 스위치 | `xai`에서만 `grok-4.5`와 `grok-4.6`의 `modelAdapters` 항목을 원자적으로 설정하거나 지웁니다. 한 항목만 있으면 다음 스위치 쓰기가 둘을 정규화할 때까지 혼합 상태로 표시됩니다. 다른 재정의와 티어 동작은 바뀌지 않습니다. | +| `xaiResponsesXSearch?` | `boolean` | 기본적으로 비활성화됩니다. xAI Responses 대상에서는 최종 요청 정규화 후에도 실제 `web_search` 도구가 남아 있을 때만 공급자가 호스팅하는 `x_search` 선언을 추가합니다. 기존 선언은 중복하지 않고, 호출자의 `tool_choice`/`allowed_tools` 선택기 범위를 확장하지 않으며, 웹 검색 사이드카의 `search.xSearch` 옵션과는 별개입니다. | | `modelPreferHostedTools?` | `Record` | hosted tool namespace를 예약하는 non-forward Responses gateway용 정확한 모델 ID opt-in입니다. 현재 `["image_generation"]`만 허용하며, 일치하는 모델은 `openai-responses` wire를 사용하고 해당 hosted tool을 지원해야 합니다. 충돌하는 클라이언트 `image_gen` 선언을 제거하고 호출자의 tool choice를 유지하도록 selector도 다시 씁니다. OpenAI API 가상 `-pro` 모델은 선택한 공개 ID를 먼저 일치시키고, 해석된 기본 wire-model ID를 대체값으로 사용합니다. `modelAdapters`는 공개 ID를 먼저, 그 다음 기본 ID를 해석하며, 두 번째 결과가 최종 wire를 결정합니다. 설정하지 않은 모델은 일반 alias 동작을 유지합니다. | | `annotateEmptyToolOutputs?` | `boolean` | 존재하지만 비어 있는 도구 결과가 모델에 도달하기 전에 짧은 표시로 바꿔, 빈 결과를 누락된 결과로 해석하지 않도록 합니다. 빈 문자열과 텍스트 전용 파트 배열에 적용되며, 이미지·파일·암호화된 파트는 절대 변경하지 않습니다. 기본 제공 레지스트리에 따라 DeepSeek의 기본값은 `true`이며, 그 외에는 설정되지 않습니다. 공급자를 이 동작에서 제외하려면 `false`로 설정합니다. 명시적인 `false`는 이후 해당 필드를 생략한 편집에서도 유지됩니다. `PATCH /api/providers?name=`는 `true`, `false`, 또는 `null`을 받아 재정의를 지우고 레지스트리 기본 동작으로 되돌릴 수 있습니다. | | `reasoningEffortMap?` | `Record` | reasoning 레이블의 공급자 전반 와이어 별칭입니다. | @@ -300,6 +302,43 @@ OpenRouter는 하나의 모델을 여러 추론 공급자로 제공할 수 있 모델 키는 외부 opencodex 공급자 접두사 없이, 정확한 네이티브 OpenRouter id여야 합니다. `openrouter/anthropic-claude-sonnet-5`를 선택하면 모델 규칙을 적용하기 전에 네이티브 `anthropic/claude-sonnet-5`로 되돌아갑니다. +## Vercel AI Gateway 공급자 라우팅 + +Vercel AI Gateway는 하나의 모델을 여러 기반 추론 공급자에 걸쳐 라우팅할 수 있습니다. `vercelGatewayRouting`은 +공급자 전반의 선호도를 구성하고, `modelVercelGatewayRouting`은 정확한 모델 ID에 대해 이를 대체합니다. 둘 다 +설정하지 않으면 `resolveVercelGatewayRouting()`이 `undefined`를 반환하므로 Chat 요청 빌더는 `provider` 필드를 +생략하고 Vercel AI Gateway의 기본 동적 라우팅 동작이 유지됩니다. + +- `order`: Vercel AI Gateway 업스트림 공급자 slug를 우선순위 순으로 지정합니다. +- `only`: 사용할 수 있는 Vercel AI Gateway 업스트림 공급자를 제한하는 명시적 허용 목록입니다. +- `sort`: 사용할 수 있는 공급자를 `"cost"`(최저 비용), `"ttft"`(첫 토큰까지 걸리는 시간), `"tps"`(초당 토큰 수) 기준으로 자동 정렬합니다. + +```json +{ + "providers": { + "vercel-ai-gateway": { + "adapter": "openai-chat", + "baseUrl": "https://ai-gateway.vercel.sh/v1", + "apiKey": "${VERCEL_AI_GATEWAY_KEY}", + "vercelGatewayRouting": { + "sort": "ttft" + }, + "modelVercelGatewayRouting": { + "zai/glm-5.2": { + "only": ["novita", "deepinfra"], + "order": ["novita", "deepinfra"] + } + } + } + } +} +``` + +모델 키는 외부 OpenCodex 공급자 접두사가 없는 Vercel 공개 모델 선택자입니다. +`vercel-ai-gateway/zai-glm-5.2`를 선택하면 모델 규칙 적용 전에 네이티브 `zai/glm-5.2`가 복원됩니다. 네이티브 +`vercel/` 선택자에도 동일한 매핑이 적용됩니다. OpenCodex에서는 인코딩된 +`vercel-ai-gateway/vercel-` 선택자를 사용하고, 모델 키에는 `vercel/`를 유지하십시오. + ## 정적 모델 허용 목록 `liveModels: false`로 두면 `models`만 노출합니다. `models`가 비어 있거나 생략되면 공급자는 어떤 라우팅 모델도 노출하지 않습니다. 라이브 발견은 캐싱 전에 4 MiB 또는 원시 모델 행 2,000개를 넘으면 거부합니다. 내장 프리셋은 더 낮은 한도를 쓰고 chat 가능한 행만 필터링할 수 있습니다. 너무 크거나 형식이 잘못된 결과는 오래된/설정된 폴백을 따릅니다. 유효하지만 선택 가능한 항목이 0개인 결과는 그대로 권위가 있으며, 조용히 다른 값으로 바꾸거나 잘라내지 않습니다. diff --git a/docs-site/src/content/docs/ko/reference/configuration/routing.md b/docs-site/src/content/docs/ko/reference/configuration/routing.md index c22a13d07d..cfc20d07fc 100644 --- a/docs-site/src/content/docs/ko/reference/configuration/routing.md +++ b/docs-site/src/content/docs/ko/reference/configuration/routing.md @@ -28,6 +28,16 @@ opencodex는 요청된 model을 다음 순서로 해석합니다: 비활성화된 provider는 제외합니다. 비활성화된 provider의 명시적 네임스페이스는 다음 규칙으로 넘어가지 않고 실패합니다. 여러 provider에 걸쳐 일치할 수 있는 규칙은 JSON에 적힌 삽입 순서대로 provider 항목을 검사하므로, bare model이 애매할 수 있으면 명시적 네임스페이스를 사용하십시오. +### 차단된 모델 리디렉션 + +`blockedModelRedirects`는 기본적으로 설정되지 않는 선택적 최상위 `Record`이며, 정확히 일치하는 해석된 모델 ID의 대체값을 정의합니다. 위 해석 순서가 끝난 후 적용됩니다. 일치하면 이미 선택된 공급자와 계정 경로는 유지하고 업스트림 모델 ID만 교체하며, 경로 사유를 `blocked-model-redirect`로 기록합니다. 이 키를 생략하면 라우팅이 바뀌지 않습니다. + +```json +{ + "blockedModelRedirects": { "gpt-5.6-terra": "gpt-5.6-luna" } +} +``` + ## 명시적 Codex 계정 selector `codexAccountNamespaces`는 `side` 같은 공개 selector를 저장된 Codex 계정 하나에 매핑합니다. @@ -56,7 +66,7 @@ Codex Auth 페이지에서 이 picker 동작을 opt-in할 수 있습니다. 비 | Key | Type | Default | Meaning | | --- | --- | --- | --- | | `targets` | `{ provider: string; model: string; weight?: number }[]` | required | 순서가 있는 concrete route입니다. `weight`는 1–10000이며 기본값은 `1`입니다. | -| `strategy?` | `"failover" \| "round-robin"` | `"failover"` | 선택 전략입니다. 대상 순서는 failover 우선순위이며, weight는 smooth weighted round-robin의 모양을 결정합니다. | +| `strategy?` | `"failover" \| "round-robin" \| "random" \| "least-used" \| "reset-window"` | `"failover"` | 선택 전략입니다. 대상 순서는 `failover` 우선순위이고, 가중치는 `round-robin`과 `random` 추첨 비율을 결정하며, `least-used`는 기록된 성공 횟수를 따르고, `reset-window`는 가장 가까운 할당량 재설정을 따릅니다. | | `stickyLimit?` | `number` | `1` | 한 round-robin 배치에서 유지되는 성공 요청 수입니다. 범위는 1–100입니다. | | `defaultEffort?` | `"low" \| "medium" \| "high" \| "xhigh" \| "max" \| "ultra" \| null` | unset | 호출자가 effort를 생략했고 선택된 대상이 요청한 rung를 광고할 때만 적용됩니다. | | `alias?` | `string` | — | 정규화된 picker slug 대신 쓰는 선택적 공개 model id입니다. | @@ -97,7 +107,7 @@ context metadata가 없는 bare relay id이거나 modalities가 서로 겹치지 CLI: `ocx route policy list`, `ocx route policy show `, `ocx route policy dry-run --model-context --tools`, `ocx route policy evaluate `. -콤보는 명시적인 순서·가중치 대상 라우팅 및 장애 조치입니다. 정책 프로필은 후보 간 증거 기반 선택입니다. +콤보는 선택 가능한 전략(순서가 있는 `failover`, 부드러운 가중 `round-robin` 또는 `random` 분산, `least-used`, `reset-window`)을 사용하는 명시적인 대상 라우팅입니다. 구성된 전략이 대상을 결정하고, 재시도 가능한 실패가 발생하면 목록의 다음 대상으로 넘어갑니다. 정책 프로필은 후보 간 증거 기반 선택입니다. ## 요청 기록 및 라우팅 분석 diff --git a/docs-site/src/content/docs/ko/reference/management-api.md b/docs-site/src/content/docs/ko/reference/management-api.md index b0ed3dac31..5280b31cd4 100644 --- a/docs-site/src/content/docs/ko/reference/management-api.md +++ b/docs-site/src/content/docs/ko/reference/management-api.md @@ -120,6 +120,11 @@ Authorization: Bearer | `POST /api/storage/cleanup-policy/run` | 수동 cleanup-policy 실행을 시작합니다 | 409 `already_running`; 500 `cleanup_failed` | | `GET /api/storage/cleanup-policy/test-stream` | 테스트 전용 policy stream 훅입니다 | 사용할 수 없으면 404 `not_found` | +`models`, `providers`, `days[].models`의 행에도 `cacheHitRate`가 포함됩니다. 이 값은 공급자의 프롬프트 캐시에서 +제공된 입력 토큰의 비율이며 `[0, 1]` 범위로 제한됩니다. 공급자가 캐시 텔레메트리를 보고하지 않았거나 행에 입력 +토큰이 없으면 `0`이 아니라 항상 `null`입니다. "캐시 데이터 없음"과 "실제 적중률 0%"는 서로 다른 사실이며, +이를 똑같이 표시하는 차트는 오해를 부르기 때문입니다. + :::caution 저장소 cleanup 엔드포인트는 archived session 데이터를 이동하거나 영구적으로 제거할 수 있습니다. 항상 먼저 미리 보고, 반환된 digest를 제출하십시오. 복구가 필요할 수 있으면 quarantine를 우선하십시오. ::: 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 1f000d992b..69f9077c23 100644 --- a/docs-site/src/content/docs/ko/reference/proxy-formats.md +++ b/docs-site/src/content/docs/ko/reference/proxy-formats.md @@ -92,6 +92,19 @@ queue overflow 시 downstream에는 terminal `response.failed` 이벤트와 `[DO 엄격한 Responses 클라이언트를 위한 호환성 보장입니다. 0은 "보고되지 않음"을 뜻할 수 있으며, 반드시 "제공자가 그런 작업을 하지 않았다"는 의미는 아닙니다. +### 응답과 요청 로그 연결 + +허용된 모든 HTTP Responses 응답에는 프록시가 생성한 `ocx-<32 hex>` 형식의 ID를 담은 +`x-opencodex-request-id` 헤더가 있습니다. 이 값은 응답을 요청 로그 및 사용량 보고의 해당 행과 연결하는 키입니다. + +프록시는 이 값을 항상 직접 생성하고 호출자가 제공하거나 업스트림이 반환한 ID를 덮어쓰므로, 이 프록시에서 +고유하며 상관관계 키로 신뢰할 수 있습니다. 이 헤더는 `Access-Control-Expose-Headers`에 명시되어 있어 브라우저 +JavaScript가 교차 출처에서도 읽을 수 있습니다. 사용자 지정 `x-` 헤더는 실제 전송 데이터에 있더라도 그렇지 않으면 +`response.headers.get()`에서 보이지 않습니다. + +인증 또는 출처 허용 단계에서 거부된 Responses 요청은 이 래퍼에 도달하지 않으며 ID가 없습니다. 따라서 헤더가 +없다는 것은 요청이 로그에 기록되기 전에 거부되었다는 뜻입니다. + ### 같은 경로에서의 WebSocket 업그레이드 `websockets`가 활성화되어 있으면 클라이언트는 HTTP POST를 여는 대신 `/v1/responses`로 업그레이드할 수 diff --git a/docs-site/src/content/docs/reference/cli/providers-accounts.md b/docs-site/src/content/docs/reference/cli/providers-accounts.md index 898befa943..becf94c5d3 100644 --- a/docs-site/src/content/docs/reference/cli/providers-accounts.md +++ b/docs-site/src/content/docs/reference/cli/providers-accounts.md @@ -146,8 +146,10 @@ Without a provider, lists the Codex pool, OAuth accounts, and configured API-key providers are skipped unless `--all` is present. With a provider, lists only that credential family. Human output uses `PROVIDER TYPE ID PLAN/LABEL PRIORITY STATUS`; a manually chosen Codex row is marked `selected`. `PRIORITY` is the signed Codex selection order (`0` when unset) and shows `-` for rows -where ordering does not apply, such as OAuth accounts and API keys. When a stored Kiro account exists, the output notes that Kiro has one login slot and -that signing in again replaces the current account. An empty result is still success. `--json` +where ordering does not apply, such as OAuth accounts and API keys. By default, with two or more eligible stored Kiro accounts, a 429 rotates automatically to +another account and prefers the one with the most known remaining allowance; rotation is +presence-driven and can be turned off with `oauthAccountFailover.enabled: false`; `ocx account login kiro` +adds accounts to the pool one at a time. An empty result is still success. `--json` returns: ```text diff --git a/docs-site/src/content/docs/reference/configuration/providers.md b/docs-site/src/content/docs/reference/configuration/providers.md index 74f2933535..d666ca972d 100644 --- a/docs-site/src/content/docs/reference/configuration/providers.md +++ b/docs-site/src/content/docs/reference/configuration/providers.md @@ -104,6 +104,7 @@ differing backup and rewrites known legacy namespaced selected ids to bare ids. | `modelReasoningSummaryDelivery?` | `Record` | Per-model Responses delivery enum; rewrites an existing delivery field. | | `modelAdapters?` | `Record` | Per-model `openai-chat` or `openai-responses` wire override for mixed-wire gateways. Explicit entries beat registry defaults. The OpenCode Go preset selects Responses for `gpt-5.6-luna` while leaving sibling models on their documented wires; DeepSeek can select native Responses for `deepseek-v4-flash`; and GitHub Copilot declares Responses-only defaults for its GPT-5 family (`gpt-5.3-codex`, `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`) because those models reject `/chat/completions` for agent traffic. Models without a built-in default (for example `gpt-5.4-nano`) can be opted in here. Single-wire upstream pins and canonical ChatGPT forward reject overrides. | | xAI Responses opt-in (dashboard) | switch | For `xai` only, atomically sets or clears the `grok-4.5` and `grok-4.6` `modelAdapters` entries. A hand-edited single entry appears as mixed until the next switch write normalizes both. Other overrides and tier behavior are unchanged. | +| `xaiResponsesXSearch?` | `boolean` | Disabled by default. On an xAI Responses destination, append the provider-hosted `x_search` declaration only when a live `web_search` tool survives final request normalization. Existing declarations are not duplicated, caller `tool_choice`/`allowed_tools` selectors are never widened, and this is separate from the web-search sidecar's `search.xSearch` options. | | `modelPreferHostedTools?` | `Record` | Exact-model opt-in for non-forward Responses gateways that reserve a hosted-tool namespace. Currently accepts only `["image_generation"]`; a matching model must use the `openai-responses` wire and support that hosted tool. It removes colliding client `image_gen` declarations and rewrites their selectors to preserve caller tool choice. For OpenAI API virtual `-pro` models, the selected public ID is matched first and the resolved base wire-model ID is a fallback. `modelAdapters` resolves the public ID first, then the base ID; the second resolution determines the final wire. Other models retain normal alias behavior. | | `annotateEmptyToolOutputs?` | `boolean` | Replace a present-but-empty tool result with a short marker before it reaches the model, so a blank result is not read as a missing one. Applies to blank strings and text-only part arrays; image, file, and encrypted parts are never touched. Defaults to `true` for DeepSeek from the built-in registry and is otherwise unset. Set `false` to opt a provider out — an explicit `false` is preserved across later edits that omit the field. `PATCH /api/providers?name=` accepts `true`, `false`, or `null` to clear the override and return to registry-default behavior. | | `reasoningEffortMap?` | `Record` | Provider-wide wire aliases for reasoning labels. | diff --git a/docs-site/src/content/docs/reference/configuration/routing.md b/docs-site/src/content/docs/reference/configuration/routing.md index 7429371c5e..f254b54708 100644 --- a/docs-site/src/content/docs/reference/configuration/routing.md +++ b/docs-site/src/content/docs/reference/configuration/routing.md @@ -34,6 +34,19 @@ Disabled providers are excluded. An explicit namespace for a disabled provider f falling through. Provider entries are checked in their JSON insertion order for rules that can match more than one provider, so use explicit namespaces when a bare model could be ambiguous. +### Blocked-model redirects + +`blockedModelRedirects` is an optional top-level `Record` of exact resolved +model-id replacements, unset by default. It runs **after** the resolution order above: a match +keeps the provider and account route already selected, replaces only the upstream model id, and +records the route reason `blocked-model-redirect`. Omitting the key leaves routing unchanged. + +```json +{ + "blockedModelRedirects": { "gpt-5.6-terra": "gpt-5.6-luna" } +} +``` + ## Exact Codex account selectors `codexAccountNamespaces` maps a public selector such as `side` to one stored Codex account. A diff --git a/docs-site/src/content/docs/reference/management-api.md b/docs-site/src/content/docs/reference/management-api.md index 25fedb6020..1bfedb0bd6 100644 --- a/docs-site/src/content/docs/reference/management-api.md +++ b/docs-site/src/content/docs/reference/management-api.md @@ -143,6 +143,12 @@ re-estimated from the pricing active when the summary is read. This is an API-eq not a subscription charge. New main-pool requests use the reserved `main` label; legacy bare `openai` rows remain in an ambiguous bucket instead of being reassigned from current configuration. +Rows in `models`, `providers`, and `days[].models` also carry `cacheHitRate`: the share of input +tokens served from the provider's prompt cache, clamped to `[0, 1]`. It is `null` — never `0` — +when the provider reported no cache telemetry or the row has no input tokens, because "no cache +data" and "a genuine 0% hit rate" are different facts and a chart that renders them alike is +misleading. + :::caution Storage cleanup endpoints can move or permanently remove archived session data. Always preview first and submit the returned digest. Prefer quarantine when recovery may be needed. diff --git a/docs-site/src/content/docs/reference/proxy-formats.md b/docs-site/src/content/docs/reference/proxy-formats.md index 1a68e78436..bb4c7afba0 100644 --- a/docs-site/src/content/docs/reference/proxy-formats.md +++ b/docs-site/src/content/docs/reference/proxy-formats.md @@ -114,8 +114,23 @@ report those details: ``` When available, `input_tokens_details` can also include `cache_write_tokens`. The always-present -detail objects are a compatibility guarantee for strict Responses clients; zero can mean “not -reported,” not necessarily “the provider performed no such work.” +detail objects are a compatibility guarantee for strict Responses clients; zero can mean "not +reported," not necessarily "the provider performed no such work." + +### Correlating a response with its request log + +Every admitted HTTP Responses reply carries an `x-opencodex-request-id` header holding a +proxy-generated id of the form `ocx-<32 hex>`. It is the key that ties a response to its row in +the request log and in usage reporting. + +The proxy always generates this value and overwrites any id supplied by the caller or returned by +the upstream, so it is unique to this proxy and safe to trust as a correlation key. The header is +named in `Access-Control-Expose-Headers`, which is what lets browser JavaScript read it +cross-origin — a custom `x-` header is otherwise invisible to `response.headers.get()` even when +it is on the wire. + +Responses rejected at authentication or origin admission never reach this wrapper and carry no id, +so a missing header means the request was refused before it was logged. ### WebSocket upgrade on the same path diff --git a/docs-site/src/content/docs/ru/guides/combos.md b/docs-site/src/content/docs/ru/guides/combos.md index 0f8b0488aa..e025d9cf0e 100644 --- a/docs-site/src/content/docs/ru/guides/combos.md +++ b/docs-site/src/content/docs/ru/guides/combos.md @@ -128,6 +128,28 @@ ocx combo set balanced \ Предпочитайте небольшие значения, которые ясно показывают замысел. ::: +### `random`: взвешенный выбор для каждого запроса + +`random` выбирает для каждого запроса одну подходящую цель с вероятностью, пропорциональной +`weight`. Каждый запрос — независимый выбор, поэтому трафик распределяется между целями без +детерминированной последовательности или закрепления, характерных для `round-robin`. +`stickyLimit` не влияет на эту стратегию. + +### `least-used`: в пользу цели с наименьшим числом успешных запросов + +`least-used` направляет каждый запрос к подходящей цели, для которой этот процесс opencodex +зарегистрировал меньше всего успешных запросов. После перезапуска счётчики начинают с нуля, а при +равенстве сохраняется порядок конфигурации. Значения `weight` и `stickyLimit` не влияют на эту +стратегию. + +### `reset-window`: ближайший сброс квоты + +`reset-window` направляет каждый запрос к подходящей цели, у которой кэшированный снимок квоты +провайдера показывает ближайший предстоящий сброс окна (пятичасового, недельного, месячного или +пользовательского). Так расходуется квота провайдера, которая обновится первой. Цели без свежих +данных о квоте, а также цели с одинаковым временем сброса сохраняют порядок конфигурации. Значения +`weight` и `stickyLimit` не влияют на эту стратегию. + ## Что происходит, когда цель сбоит Сбои в combo делятся на **hop**-сбои и **terminal**-сбои. @@ -268,9 +290,9 @@ Combo хранятся в объекте верхнего уровня `combos`, | Поле | Обязательно | По умолчанию | Правила | | --- | --- | --- | --- | | `targets` | Yes | — | Непустой упорядоченный массив настроенных целей `{ provider, model, weight? }`. Дубли пар provider/model запрещены. | -| `targets[].weight` | No | `1` | Целое число от 1 до 10 000. Используется в round-robin; при failover игнорируется. | -| `strategy` | No | `"failover"` | `"failover"` или `"round-robin"`. | -| `stickyLimit` | No | `1` | Целое число от 1 до 100 успешных запросов на один выбор round-robin. | +| `targets[].weight` | No | `1` | Целое число от 1 до 10 000. Используется стратегиями `round-robin` и `random`; игнорируется стратегиями `failover`, `least-used` и `reset-window`. | +| `strategy` | No | `"failover"` | `"failover"`, `"round-robin"`, `"random"`, `"least-used"` или `"reset-window"`. | +| `stickyLimit` | No | `1` | Целое число от 1 до 100 успешных запросов на один выбор `round-robin`. Применяется только к `round-robin`. | | `defaultEffort` | No | `null` | `low`, `medium`, `high`, `xhigh`, `max` или `ultra`; применяется только когда вызывающая сторона не указала effort, а цель объявляет поддержку. | | `alias` | No | none | Необязательный обрезанный публичный id модели; используйте правила alias выше. Пустое значение хранится как отсутствие alias. | | `nativeAlias` | No | `false` | Явно разрешает поддерживаемому сейчас bare native alias перехватить приоритет routing/catalog только для неквалифицированного id. Bare `gpt-5.6-*` использует учётные данные Codex Pool/Direct; маршруты с квалификатором аккаунта сохраняют свою идентичность, а provider-qualified `openai-apikey/gpt-5.6-*` использует API-ключ и никогда не переходит на native alias. | diff --git a/docs-site/src/content/docs/ru/reference/cli/providers-accounts.md b/docs-site/src/content/docs/ru/reference/cli/providers-accounts.md index c1a27cb057..1dd33a4da4 100644 --- a/docs-site/src/content/docs/ru/reference/cli/providers-accounts.md +++ b/docs-site/src/content/docs/ru/reference/cli/providers-accounts.md @@ -138,8 +138,7 @@ label и masked key. Пустые провайдеры пропускаются, если не задан `--all`. С провайдером выводится только это семейство credential'ов. Human-output использует формат `PROVIDER TYPE ID PLAN/LABEL PRIORITY STATUS`; строка Codex, выбранная вручную, помечается `selected`. -Если существует сохранённый аккаунт Kiro, вывод дополнительно отмечает, что у Kiro один слот -логина и новый вход заменит текущий аккаунт. Пустой результат всё равно считается успехом. +При наличии двух или более подходящих сохранённых аккаунтов Kiro по умолчанию ответ 429 автоматически переключает запрос на другой аккаунт, предпочитая аккаунт с наибольшим известным остатком лимита; ротация включается самим наличием аккаунтов и отключается через `oauthAccountFailover.enabled: false`; `ocx account login kiro` добавляет аккаунты в пул по одному. Пустой результат всё равно считается успехом. `--json` возвращает: ```text 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 3a51387511..c013b96855 100644 --- a/docs-site/src/content/docs/ru/reference/configuration/providers.md +++ b/docs-site/src/content/docs/ru/reference/configuration/providers.md @@ -92,6 +92,7 @@ cross-route credential fallback не существует. Строки API GPT- | `headers?` | `Record` | Дополнительные upstream-header'ы. Заголовки авторизации, cookie, API-key-header'ы, встроенные переводы строк и невалидные имена отклоняются. | | `openRouterRouting?` | `OpenRouterProviderRouting` | Предпочтения по умолчанию для OpenRouter (`order`, `only`, `allowFallbacks`); валидно только для канонического OpenRouter с `openai-chat`. | | `modelOpenRouterRouting?` | `Record` | Exact override по model id, которые полностью заменяют provider-wide preference для OpenRouter. | +| `vercelGatewayRouting?` | `VercelGatewayRouting` | Предпочтения по умолчанию для Vercel AI Gateway: `order`, `only` и `sort` (`"cost"` \| `"ttft"` \| `"tps"`); допустимо только для канонического Vercel AI Gateway с `openai-chat`. | | `authMode?` | `"key" \| "forward" \| "oauth" \| "local"` | Режим аутентификации (по умолчанию `key`). OAuth/subscription credential'ы хранятся вне `config.json`; `local` разрешён только для тех провайдеров, где это допускает registry-entry. | | `codexAccountMode?` | `"pool" \| "direct"` | Только для канонического `openai`; по умолчанию Pool. Direct обходит состояние пула. | | `refreshPolicy?` | `"proactive" \| "lazy-only" \| "disabled"` | Переопределение политики Token Guardian для этого OAuth-провайдера. | @@ -101,6 +102,7 @@ cross-route credential fallback не существует. Строки API GPT- | `modelReasoningSummaryDelivery?` | `Record` | Responses delivery enum по моделям; переписывает уже существующее поле delivery. | | `modelAdapters?` | `Record` | Wire-override по модели для `openai-chat` или `openai-responses` в gateway с несколькими wire-форматами. Явные записи имеют приоритет над default'ами registry; preset DeepSeek может выбирать native Responses для `deepseek-v4-flash`, а GitHub Copilot объявляет Responses-only default'ы для семейства GPT-5 (`gpt-5.3-codex`, `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`), потому что эти модели отклоняют `/chat/completions` для агентного трафика. Модели без встроенного default'а (например, `gpt-5.4-nano`) можно включить здесь. Single-wire upstream pin'ы и canonical ChatGPT forward override не принимают. | | Opt-in xAI Responses (панель) | переключатель | Только для `xai`: атомарно задаёт или удаляет записи `modelAdapters` для `grok-4.5` и `grok-4.6`. Одна запись отображается как смешанное состояние до следующего переключения. Остальные override и поведение tier не меняются. | +| `xaiResponsesXSearch?` | `boolean` | По умолчанию отключено. Для назначения xAI Responses декларация `x_search`, размещённая у провайдера, добавляется только тогда, когда действующий инструмент `web_search` сохраняется после окончательной нормализации запроса. Существующие декларации не дублируются, селекторы вызывающей стороны `tool_choice`/`allowed_tools` никогда не расширяются, и эта настройка не связана с параметрами `search.xSearch` сайдкара веб-поиска. | | `modelPreferHostedTools?` | `Record` | Opt-in для точного model ID в non-forward Responses gateway, который резервирует namespace hosted tool. Сейчас допускается только `["image_generation"]`; совпавшая модель должна использовать wire `openai-responses` и поддерживать этот hosted tool. Прокси удаляет конфликтующие клиентские объявления `image_gen` и переписывает их selectors, сохраняя caller tool choice. Для виртуальных моделей OpenAI API `-pro` сначала сопоставляется выбранный публичный ID, а затем в качестве fallback используется ID базовой wire-модели. `modelAdapters` сначала разрешается по публичному ID, затем по базовому ID; второй результат определяет итоговый wire. Остальные модели сохраняют обычное alias-поведение. | | `annotateEmptyToolOutputs?` | `boolean` | Заменяет присутствующий, но пустой результат вызова инструмента короткой меткой до его передачи модели, чтобы пустой результат не воспринимался как отсутствующий. Применяется к пустым строкам и массивам частей, содержащим только текст; части с изображениями, файлами и зашифрованными данными никогда не изменяются. Во встроенном реестре по умолчанию имеет значение `true` для DeepSeek, а для остальных провайдеров не задано. Укажите `false`, чтобы отключить эту возможность для провайдера: явное значение `false` сохраняется при последующих изменениях без этого поля. `PATCH /api/providers?name=` принимает `true`, `false` или `null`, чтобы удалить переопределение и вернуться к поведению по умолчанию из реестра. | | `reasoningEffortMap?` | `Record` | Provider-wide wire-alias'ы для reasoning-label'ов. | @@ -374,6 +376,47 @@ OpenRouter может обслуживать одну и ту же модель opencodex. При выборе `openrouter/anthropic-claude-sonnet-5` система сначала восстанавливает native-id `anthropic/claude-sonnet-5`, а уже затем применяет model rule. +## Маршрутизация провайдеров Vercel AI Gateway + +Vercel AI Gateway может маршрутизировать одну модель между несколькими нижележащими +inference-провайдерами. `vercelGatewayRouting` задаёт предпочтения для всего провайдера, а +`modelVercelGatewayRouting` полностью заменяет их для точных идентификаторов моделей. Если обе +настройки отсутствуют, `resolveVercelGatewayRouting()` возвращает `undefined`, поэтому построители +Chat-запросов не добавляют поле `provider`, а Vercel AI Gateway сохраняет стандартное динамическое +поведение маршрутизации. + +- `order`: slug'и upstream-провайдеров Vercel AI Gateway в порядке приоритета. +- `only`: явный allowlist допустимых upstream-провайдеров Vercel AI Gateway. +- `sort`: автоматическая сортировка допустимых провайдеров по `"cost"` (минимальная стоимость), + `"ttft"` (время до первого токена) или `"tps"` (токенов в секунду). + +```json +{ + "providers": { + "vercel-ai-gateway": { + "adapter": "openai-chat", + "baseUrl": "https://ai-gateway.vercel.sh/v1", + "apiKey": "${VERCEL_AI_GATEWAY_KEY}", + "vercelGatewayRouting": { + "sort": "ttft" + }, + "modelVercelGatewayRouting": { + "zai/glm-5.2": { + "only": ["novita", "deepinfra"], + "order": ["novita", "deepinfra"] + } + } + } + } +} +``` + +Ключи моделей — это публичные селекторы моделей Vercel без внешнего префикса провайдера OpenCodex. +При выборе `vercel-ai-gateway/zai-glm-5.2` перед применением правила модели восстанавливается нативный +идентификатор `zai/glm-5.2`. То же преобразование применяется к нативному селектору +`vercel/`: в OpenCodex используйте кодированный селектор +`vercel-ai-gateway/vercel-`, а в качестве ключа модели оставьте `vercel/`. + ## Статические allowlist'ы моделей Задайте `liveModels: false`, чтобы показывать только `models`. Если `models` пуст или отсутствует, diff --git a/docs-site/src/content/docs/ru/reference/configuration/routing.md b/docs-site/src/content/docs/ru/reference/configuration/routing.md index 7249bd8ecf..dbc7181044 100644 --- a/docs-site/src/content/docs/ru/reference/configuration/routing.md +++ b/docs-site/src/content/docs/ru/reference/configuration/routing.md @@ -35,6 +35,20 @@ opencodex разрешает запрошенную модель в следую провайдерами, записи проверяются в порядке их добавления в JSON. Поэтому используйте явные пространства имён, если голая модель может быть неоднозначной. +### Перенаправления заблокированных моделей + +`blockedModelRedirects` — необязательный верхнеуровневый `Record` точных замен +разрешённых идентификаторов моделей; по умолчанию не задан. Он применяется после описанного выше +порядка разрешения: при совпадении уже выбранный маршрут провайдера и аккаунта сохраняется, заменяется +только идентификатор вышестоящей модели, а причиной маршрута записывается `blocked-model-redirect`. +Если ключ отсутствует, маршрутизация не меняется. + +```json +{ + "blockedModelRedirects": { "gpt-5.6-terra": "gpt-5.6-luna" } +} +``` + ## Точные селекторы аккаунтов Codex `codexAccountNamespaces` сопоставляет публичный селектор, например `side`, с одним сохранённым @@ -71,7 +85,7 @@ selector-qualified строки и возвращает обычные GPT-ст | Ключ | Тип | По умолчанию | Значение | | --- | --- | --- | --- | | `targets` | `{ provider: string; model: string; weight?: number }[]` | required | Упорядоченные конкретные маршруты. `weight` находится в диапазоне 1–10000 и по умолчанию равен `1`. | -| `strategy?` | `"failover" \| "round-robin"` | `"failover"` | Стратегия выбора. Порядок целей задаёт приоритет failover; веса формируют плавный взвешенный round-robin. | +| `strategy?` | `"failover" \| "round-robin" \| "random" \| "least-used" \| "reset-window"` | `"failover"` | Стратегия выбора. Порядок целей задаёт приоритет `failover`; значения `weight` определяют взвешивание выборов `round-robin` и `random`; `least-used` следует числу зарегистрированных успешных запросов; `reset-window` следует ближайшему сбросу квоты. | | `stickyLimit?` | `number` | `1` | Число успешных запросов, удерживаемых в одной партии round-robin. Диапазон 1–100. | | `defaultEffort?` | `"low" \| "medium" \| "high" \| "xhigh" \| "max" \| "ultra" \| null` | unset | Применяется, только если вызывающая сторона не задала effort, а выбранная цель объявляет эту ступень. | | `alias?` | `string` | — | Необязательный публичный id модели вместо канонического slug в селекторе. | @@ -120,7 +134,7 @@ Combo остаётся доступной для прямой маршрутиз CLI: `ocx route policy list`, `ocx route policy show `, `ocx route policy dry-run --model-context --tools`, `ocx route policy evaluate `. -Комбо — это явная маршрутизация с порядком/весами и отказоустойчивостью. Профиль — это выбор на основе доказательств среди кандидатов. +Комбо — это явная маршрутизация по целям с выбираемой стратегией (`failover` в заданном порядке, сглаженная взвешенная балансировка `round-robin`, случайная балансировка `random`, `least-used` или `reset-window`): выбор определяет настроенная стратегия, а retryable-сбои переводят запрос к следующей цели в списке. Профиль — это выбор на основе доказательств среди кандидатов. ## История запросов и аналитика маршрутизации diff --git a/docs-site/src/content/docs/ru/reference/management-api.md b/docs-site/src/content/docs/ru/reference/management-api.md index 860fb742d6..5ab5788beb 100644 --- a/docs-site/src/content/docs/ru/reference/management-api.md +++ b/docs-site/src/content/docs/ru/reference/management-api.md @@ -136,6 +136,12 @@ GUI-сессия в стиле loopback не выпускается. | `POST /api/storage/cleanup-policy/run` | Запустить manual cleanup-policy run | 409 `already_running`; 500 `cleanup_failed` | | `GET /api/storage/cleanup-policy/test-stream` | Тестовый policy-stream hook | 404 `not_found`, когда недоступен | +Строки в `models`, `providers` и `days[].models` также содержат `cacheHitRate` — долю входных +токенов, полученных из кэша промптов провайдера и ограниченную диапазоном `[0, 1]`. Значение равно +`null`, а не `0`, если провайдер не передал телеметрию кэша или в строке нет входных токенов: отсутствие +данных о кэше и фактическая доля попаданий 0 % — разные сведения, и диаграмма, отображающая их +одинаково, вводит в заблуждение. + :::caution Endpoint'ы storage cleanup могут перемещать или навсегда удалять архивные данные сессий. Всегда сначала выполняйте preview и отправляйте возвращённый digest. Если может понадобиться восстановление, 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 9163bec4f2..5d0cd6b98a 100644 --- a/docs-site/src/content/docs/ru/reference/proxy-formats.md +++ b/docs-site/src/content/docs/ru/reference/proxy-formats.md @@ -90,6 +90,22 @@ Responses. Обе формы сохраняют выбранную модель, объекты присутствуют всегда ради совместимости со strict-клиентами Responses; ноль может означать «не сообщено», а не обязательно «провайдер такой работы не делал». +### Сопоставление ответа с записью запроса в журнале + +Каждый допущенный HTTP-ответ Responses содержит заголовок `x-opencodex-request-id` с созданным +прокси идентификатором вида `ocx-<32 hex>`. Это ключ, связывающий ответ с соответствующей строкой +в журнале запросов и отчётах об использовании. + +Прокси всегда создаёт это значение сам и перезаписывает любой идентификатор, переданный вызывающей +стороной или возвращённый вышестоящим сервером, поэтому оно уникально для этого прокси и ему можно +доверять как ключу сопоставления. Заголовок указан в `Access-Control-Expose-Headers`, благодаря чему +браузерный JavaScript может читать его при междоменных запросах: без этого пользовательский +заголовок с префиксом `x-` невидим для `response.headers.get()`, даже если передаётся по сети. + +Ответы, отклонённые на этапе аутентификации или проверки допустимости источника, не доходят до этой +обёртки и не содержат идентификатора. Поэтому отсутствие заголовка означает, что запрос был +отклонён до записи в журнал. + ### WebSocket-upgrade на том же пути Когда включён `websockets`, клиент может выполнить upgrade для `/v1/responses`, а не открывать diff --git a/docs-site/src/content/docs/tr/guides/combos.md b/docs-site/src/content/docs/tr/guides/combos.md index db7c73390e..8b67170068 100644 --- a/docs-site/src/content/docs/tr/guides/combos.md +++ b/docs-site/src/content/docs/tr/guides/combos.md @@ -195,6 +195,29 @@ Ağırlıklar görecelidir, yüzde değildir. `2,1` ve `200,100` ağırlıkları oranı ifade eder. Niyeti ileten küçük değerleri tercih edin. ::: +### `random`: istek başına ağırlıklı seçim + +`random`, her istek için uygun hedeflerden birini `weight` ile orantılı +olasılıkla seçer. Her istek bağımsız bir seçimdir; bu nedenle trafik, +`round-robin` stratejisinin belirleyici düzeni veya yapışkanlığı olmadan +hedeflere dağılır. `stickyLimit` bu stratejiyi etkilemez. + +### `least-used`: en az başarılı isteğe sahip hedefi tercih et + +`least-used`, her isteği bu opencodex sürecinin kaydettiği en az başarılı istek +sayısına sahip uygun hedefe yönlendirir. Sayaçlar yeniden başlatmada sıfırdan +başlar ve eşitliklerde yapılandırma sırası korunur. `weight` değerleri ve +`stickyLimit` bu stratejiyi etkilemez. + +### `reset-window`: en yakın kota sıfırlamasını izle + +`reset-window`, her isteği önbelleğe alınmış sağlayıcı kota anlık görüntüsünde +yaklaşan en yakın pencere sıfırlaması (beş saatlik, haftalık, aylık veya özel) +görünen uygun hedefe yönlendirir. Böylece ilk yenilenecek sağlayıcının kotası +kullanılır. Güncel kota verisi bulunmayan hedeflerde ve eşitliklerde +yapılandırma sırası korunur. `weight` değerleri ve `stickyLimit` bu stratejiyi +etkilemez. + ## Bir hedef başarısız olduğunda ne olur? Kombo hataları **atlama (hop)** hataları ve **uç (terminal)** hatalar olarak @@ -346,9 +369,9 @@ saklanır: | Alan | Gerekli | Varsayılan | Kurallar | | --- | --- | --- | --- | | `targets` | Evet | — | Yapılandırılmış `{ provider, model, weight? }` hedeflerinin boş olmayan sıralı dizisi. Yinelenen sağlayıcı/model çiftleri reddedilir. | -| `targets[].weight` | Hayır | `1` | 1 ile 10.000 arasında tam sayı. Round-robin tarafından kullanılır; yük devretme tarafından yok sayılır. | -| `strategy` | Hayır | `"failover"` | `"failover"` veya `"round-robin"`. | -| `stickyLimit` | Hayır | `1` | Round-robin seçimi başına 1 ile 100 arasında başarılı istek tam sayısı. | +| `targets[].weight` | Hayır | `1` | 1 ile 10.000 arasında tam sayı. `round-robin` ve `random` tarafından kullanılır; `failover`, `least-used` ve `reset-window` tarafından yok sayılır. | +| `strategy` | Hayır | `"failover"` | İzin verilen değerler: `"failover"`, `"round-robin"`, `"random"`, `"least-used"`, `"reset-window"`. | +| `stickyLimit` | Hayır | `1` | Yalnızca `round-robin` için geçerlidir; seçim başına 1 ile 100 arasında başarılı istek tam sayısı. | | `defaultEffort` | Hayır | `null` | `low`, `medium`, `high`, `xhigh`, `max` veya `ultra`; yalnızca arayan çabayı atladığında ve hedef desteği bildirdiğinde uygulanır. | | `alias` | Hayır | yok | İsteğe bağlı kırpılmış genel model kimliği; yukarıdaki takma ad kurallarını kullanın. Boş bir değer takma ad yok olarak saklanır. | | `nativeAlias` | Hayır | `false` | Şu anda desteklenen yalın bir yerel `alias`'ın yönlendirme ve katalog önceliği almasına açıkça izin verin. Asla takma addan çıkarılmaz. | diff --git a/docs-site/src/content/docs/tr/reference/cli/providers-accounts.md b/docs-site/src/content/docs/tr/reference/cli/providers-accounts.md index e8018aeeab..d9881286b3 100644 --- a/docs-site/src/content/docs/tr/reference/cli/providers-accounts.md +++ b/docs-site/src/content/docs/tr/reference/cli/providers-accounts.md @@ -162,9 +162,9 @@ Bir sağlayıcı ile yalnızca bu kimlik bilgisi ailesini listeler. İnsan çık `PROVIDER TYPE ID PLAN/LABEL PRIORITY STATUS` kullanır; manuel olarak seçilen bir Codex satırı `selected` olarak işaretlenir. `PRIORITY`, imzalı Codex seçim sırasıdır (ayarlanmadığında `0`) ve OAuth hesapları ve API anahtarları gibi -sıralamanın geçerli olmadığı satırlar için `-` gösterir. Saklanan bir Kiro -hesabı mevcut olduğunda çıktı Kiro'nun tek bir giriş yuvasına sahip olduğunu ve -tekrar oturum açmanın geçerli hesabın yerini alacağını belirtir. Boş bir sonuç +sıralamanın geçerli olmadığı satırlar için `-` gösterir. İki veya daha fazla uygun Kiro hesabı +saklandığında, varsayılan olarak 429 yanıtı otomatik olarak başka bir hesaba geçer ve bilinen kalan +kotası en yüksek hesabı tercih eder; rotasyon hesapların varlığıyla etkinleşir ve `oauthAccountFailover.enabled: false` ile kapatılabilir; `ocx account login kiro` hesapları havuza teker teker ekler. Boş bir sonuç yine de başarıdır. `--json` şunu döndürür: ```text 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 c87bf984fc..bba5ca850f 100644 --- a/docs-site/src/content/docs/tr/reference/configuration/providers.md +++ b/docs-site/src/content/docs/tr/reference/configuration/providers.md @@ -98,6 +98,7 @@ alanlı seçilmiş kimlikleri yalın kimliklere yeniden yazar. | `headers?` | `Record` | Ek yukarı akış başlıkları. Yetkilendirme, çerezler, API anahtarı başlıkları, gömülü yeni satırlar ve geçersiz adlar reddedilir. | | `openRouterRouting?` | `OpenRouterProviderRouting` | Varsayılan OpenRouter `order`, `only` ve `allowFallbacks` tercihleri; yalnızca `openai-chat` ile kurallı OpenRouter için geçerlidir. | | `modelOpenRouterRouting?` | `Record` | Sağlayıcı genelindeki OpenRouter tercihinin yerini alan tam model kimliği geçersiz kılmaları. | +| `vercelGatewayRouting?` | `VercelGatewayRouting` | Varsayılan Vercel AI Gateway `order`, `only` ve `sort` (`"cost"` \| `"ttft"` \| `"tps"`) tercihleri; yalnızca `openai-chat` ile kurallı Vercel AI Gateway için geçerlidir. | | `authMode?` | `"key" \| "forward" \| "oauth" \| "local"` | Kimlik doğrulama modu (varsayılan `key`). OAuth/abonelik kimlik bilgileri `config.json` dışında saklanır; `local`, kayıt defteri girdisi izin veren sağlayıcılarla sınırlıdır. | | `codexAccountMode?` | `"pool" \| "direct"` | Yalnızca kurallı `openai`; varsayılan olarak Pool. Direct havuz durumunu atlar. | | `refreshPolicy?` | `"proactive" \| "lazy-only" \| "disabled"` | Bu OAuth sağlayıcısının Token Guardian politikasını geçersiz kılın. | @@ -107,6 +108,7 @@ alanlı seçilmiş kimlikleri yalın kimliklere yeniden yazar. | `modelReasoningSummaryDelivery?` | `Record` | Model başına Responses teslim enum'ı; mevcut bir teslim alanını yeniden yazar. | | `modelAdapters?` | `Record` | Karışık hatlı ağ geçitleri için model başına `openai-chat` veya `openai-responses` hat geçersiz kılma. Açık girdiler kayıt defteri varsayılanlarını yener. OpenCode Go önayarı, kardeş modelleri belgelenmiş hatlarında bırakırken `gpt-5.6-luna` için Responses'ı seçer; DeepSeek, `deepseek-v4-flash` için yerel Responses seçebilir; ve GitHub Copilot, GPT-5 ailesi (`gpt-5.3-codex`, `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`) için yalnızca Responses varsayılanlarını bildirir çünkü bu modeller ajan trafiği için `/chat/completions`'ı reddeder. Yerleşik varsayılanı olmayan modeller (örneğin `gpt-5.4-nano`) burada dahil edilebilir. Tek hatlı yukarı akış pinleri ve kurallı ChatGPT iletme geçersiz kılmaları reddeder. | | xAI Responses katılımı (panel) | anahtar | Yalnızca `xai` için `grok-4.5` ve `grok-4.6` `modelAdapters` girdilerini atomik olarak ayarlar veya temizler. Tek girdi, sonraki anahtar yazımı ikisini eşitleyene kadar karma durum olarak görünür. Diğer geçersiz kılmalar ve katman davranışı değişmez. | +| `xaiResponsesXSearch?` | `boolean` | Varsayılan olarak devre dışıdır. Bir xAI Responses hedefinde, yalnızca canlı bir `web_search` aracı son istek normalleştirmesinden sağ çıktığında sağlayıcı tarafından barındırılan `x_search` bildirimini ekler. Mevcut bildirimler yinelenmez, çağıranın `tool_choice`/`allowed_tools` seçicileri hiçbir zaman genişletilmez ve bu, web araması yardımcı hizmetinin `search.xSearch` seçeneklerinden ayrıdır. | | `modelPreferHostedTools?` | `Record` | Barındırılan bir araç ad alanı ayıran iletme harici Responses ağ geçitleri için tam model dahil etme. Şu anda yalnızca `["image_generation"]` kabul eder; eşleşen bir model `openai-responses` hattını kullanmalı ve bu barındırılan aracı desteklemelidir. Çakışan istemci `image_gen` bildirimlerini kaldırır ve arayan araç seçimini korumak için seçicilerini yeniden yazar. OpenAI API sanal `-pro` modelleri için önce seçilen genel kimlik eşleştirilir ve çözümlenen temel hat model kimliği bir geri dönüştür. `modelAdapters` önce genel kimliği, ardından temel kimliği çözer; ikinci çözümleme son hattı belirler. Diğer modeller normal takma ad davranışını korur. | | `annotateEmptyToolOutputs?` | `boolean` | Mevcut fakat boş bir araç sonucunu modele ulaşmadan önce kısa bir işaretle değiştirir; böylece boş sonuç eksik sonuç olarak yorumlanmaz. Boş dizelere ve yalnızca metin parçalarından oluşan dizilere uygulanır; görsel, dosya ve şifrelenmiş parçalara hiçbir zaman dokunulmaz. Yerleşik kayıt defterindeki DeepSeek için varsayılan değer `true`dur; diğer durumlarda ayarlanmamıştır. Bir sağlayıcıyı kapsam dışında bırakmak için `false` olarak ayarlayın — açık bir `false` değeri, alanı içermeyen sonraki düzenlemelerde korunur. `PATCH /api/providers?name=`, geçersiz kılmayı temizleyip kayıt defteri varsayılanı davranışına dönmek üzere `true`, `false` veya `null` kabul eder. | | `reasoningEffortMap?` | `Record` | Akıl yürütme etiketleri için sağlayıcı genelinde hat takma adları. | @@ -304,6 +306,7 @@ Bozuk bir `openai-responses` ağ geçidi için onarım sağlayıcı nesnesine ai } ``` + Yer tutucu listeleri tam eşleşmelerdir. Normal/durum bilgili Responses sağlayıcıları için alanı ayarlanmamış bırakın, böylece doğrudan geçiş bayt bayt aynı kalır. @@ -411,6 +414,47 @@ Model anahtarları, dış opencodex sağlayıcı öneki olmadan tam yerel OpenRo kimlikleridir. `openrouter/anthropic-claude-sonnet-5` seçimi model kuralını uygulamadan önce yerel `anthropic/claude-sonnet-5`'i geri yükler. +## Vercel AI Gateway sağlayıcı yönlendirmesi + +Vercel AI Gateway bir modeli birden çok temel çıkarım sağlayıcısı arasında +yönlendirebilir. `vercelGatewayRouting` sağlayıcı genelindeki tercihleri +yapılandırır; `modelVercelGatewayRouting` tam model kimlikleri için onun yerini +alır. İkisi de ayarlanmazsa `resolveVercelGatewayRouting()` `undefined` döndürür; +böylece Chat istek oluşturucuları `provider` alanını atlar ve Vercel AI Gateway +varsayılan dinamik yönlendirme davranışını korur. + +- `order`: Öncelik sırasına göre Vercel AI Gateway yukarı akış sağlayıcı slug'ları. +- `only`: Uygun Vercel AI Gateway yukarı akış sağlayıcılarını sınırlayan açık izin listesi. +- `sort`: Uygun sağlayıcıları `"cost"` (en düşük maliyet), `"ttft"` (ilk belirtece kadar geçen süre) veya `"tps"` (saniye başına belirteç) ölçütüne göre otomatik sıralar. + +```json +{ + "providers": { + "vercel-ai-gateway": { + "adapter": "openai-chat", + "baseUrl": "https://ai-gateway.vercel.sh/v1", + "apiKey": "${VERCEL_AI_GATEWAY_KEY}", + "vercelGatewayRouting": { + "sort": "ttft" + }, + "modelVercelGatewayRouting": { + "zai/glm-5.2": { + "only": ["novita", "deepinfra"], + "order": ["novita", "deepinfra"] + } + } + } + } +} +``` + +Model anahtarları, dış OpenCodex sağlayıcı öneki olmadan herkese açık Vercel +model seçicileridir. `vercel-ai-gateway/zai-glm-5.2` seçimi, model kuralını +uygulamadan önce yerel `zai/glm-5.2` kimliğini geri yükler. Aynı eşleme yerel bir +`vercel/` seçicisi için de geçerlidir: OpenCodex'te kodlanmış +`vercel-ai-gateway/vercel-` seçicisini kullanın ve model anahtarı olarak +`vercel/` değerini koruyun. + ## Statik model izin listeleri Yalnızca `models`'ı göstermek için `liveModels: false` ayarlayın. `models` boşsa diff --git a/docs-site/src/content/docs/tr/reference/configuration/routing.md b/docs-site/src/content/docs/tr/reference/configuration/routing.md index cdb7e76572..74d239ee14 100644 --- a/docs-site/src/content/docs/tr/reference/configuration/routing.md +++ b/docs-site/src/content/docs/tr/reference/configuration/routing.md @@ -41,6 +41,22 @@ Birden fazla sağlayıcıyla eşleşebilecek kurallar için sağlayıcı girdile ekleme sıralarına göre kontrol edilir, bu nedenle yalın bir model belirsiz olabileceğinde açık ad alanları kullanın. +### Engellenen model yeniden yönlendirmeleri + +`blockedModelRedirects`, varsayılan olarak ayarlanmamış, tam çözümlenmiş model +kimliği değiştirmelerinden oluşan isteğe bağlı üst düzey bir +`Record` eşlemesidir. Yukarıdaki çözümleme sırasından sonra +çalışır: bir eşleşme önceden seçilmiş sağlayıcı ve hesap rotasını korur, yalnızca +yukarı akış model kimliğini değiştirir ve rota nedenini +`blocked-model-redirect` olarak kaydeder. Anahtarın atlanması yönlendirmeyi +değiştirmez. + +```json +{ + "blockedModelRedirects": { "gpt-5.6-terra": "gpt-5.6-luna" } +} +``` + ## Tam Codex hesap seçicileri `codexAccountNamespaces`, `side` gibi genel bir seçiciyi saklanan bir Codex @@ -92,7 +108,7 @@ aileleri kullanamaz. | Anahtar | Tip | Varsayılan | Anlamı | | --- | --- | --- | --- | | `targets` | `{ provider: string; model: string; weight?: number }[]` | gerekli | Sıralı somut rotalar. `weight` 1–10000 arasındadır ve varsayılan olarak `1`'dir. | -| `strategy?` | `"failover" \| "round-robin"` | `"failover"` | Seçim stratejisi. Hedef sırası yük devretme önceliğidir; ağırlıklar pürüzsüz ağırlıklı round-robin'i şekillendirir. | +| `strategy?` | `"failover" \| "round-robin" \| "random" \| "least-used" \| "reset-window"` | `"failover"` | Seçim stratejisi. Hedef sırası `failover` önceliğini belirler; `weight` değerleri `round-robin` ve `random` seçimlerini biçimlendirir; `least-used` kaydedilen başarılı istekleri izler; `reset-window` en yakın kota sıfırlamasını izler. | | `stickyLimit?` | `number` | `1` | Tek bir round-robin grubunda tutulan başarılı istekler. Aralık 1–100. | | `defaultEffort?` | `"low" \| "medium" \| "high" \| "xhigh" \| "max" \| "ultra" \| null` | ayarlanmamış | Yalnızca arayan çabayı atladığında ve seçilen hedef istenen basamağı bildirdiğinde uygulanır. | | `alias?` | `string` | — | Kurallı seçici slug'ı yerine isteğe bağlı genel model kimliği. | @@ -216,9 +232,10 @@ deneme çalıştırması bu aday başına hesap alanlarını sağlayamaz. ### Kombolar ve politika profilleri -- Bir **kombo**, açık sıralı/ağırlıklı hedef yönlendirmesi ve yük devretmesidir: - yapılandırılmış sıra (veya pürüzsüz ağırlıklı round-robin) karar verir ve - arızalar liste boyunca ilerler. +- Bir **kombo**, açık sıralı/ağırlıklı hedef yönlendirmesidir (`failover`, + ağırlıklı `round-robin` veya `random` dengelemesi, `least-used` ya da + `reset-window`): yapılandırılmış strateji karar verir ve yeniden denenebilir arızalar + liste boyunca ilerler. - Bir **politika profili**, yapılandırılmış adaylar arasında kanıta dayalı seçimdir: kesin yetenek gereksinimleri önce filtreler, ardından belirleyici puanlama kalanları sıralar. @@ -294,4 +311,3 @@ otomatik bir yeniden oluşturmayı tetikler; `ocx logs rebuild-index` bunu zorla Bu sistemdeki hiçbir şey ağırlıkları, bütçeleri veya aday kümelerini otomatik olarak ayarlamaz. - diff --git a/docs-site/src/content/docs/tr/reference/management-api.md b/docs-site/src/content/docs/tr/reference/management-api.md index d4a0ed290b..cc5c293345 100644 --- a/docs-site/src/content/docs/tr/reference/management-api.md +++ b/docs-site/src/content/docs/tr/reference/management-api.md @@ -153,6 +153,13 @@ abonelik ücreti değildir. Yeni ana havuz istekleri ayrılmış `main` etiketin kullanır; eski yalın `openai` satırları geçerli yapılandırmadan yeniden atanmak yerine belirsiz bir sepette kalır. +`models`, `providers` ve `days[].models` içindeki satırlar da `cacheHitRate` +taşır: sağlayıcının istem önbelleğinden sunulan girdi belirteçlerinin `[0, 1]` +aralığıyla sınırlandırılmış payı. Sağlayıcı hiç önbellek telemetrisi +bildirmediğinde veya satırda hiç girdi belirteci olmadığında bu değer `0` değil, +`null` olur; çünkü "önbellek verisi yok" ile "gerçekten %0 isabet oranı" farklı +olgulardır ve bunları aynı şekilde gösteren bir grafik yanıltıcıdır. + :::caution Depolama temizleme uç noktaları arşivlenmiş oturum verilerini taşıyabilir veya kalıcı olarak kaldırabilir. Her zaman önce önizleyin ve döndürülen özeti @@ -301,4 +308,3 @@ olduğunda veya işlem başarısız olduğunda sıfır olmayan bir sonuç dönd Doğrudan HTTP, yukarıdaki tam uç nokta sözleşmelerine ihtiyaç duyan entegrasyonlar için en yararlıdır. - 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 8b53d1bd51..3258c31e39 100644 --- a/docs-site/src/content/docs/tr/reference/proxy-formats.md +++ b/docs-site/src/content/docs/tr/reference/proxy-formats.md @@ -99,6 +99,24 @@ içerebilir. Her zaman mevcut olan ayrıntı nesneleri katı Responses istemcile için bir uyumluluk garantisidir; sıfır olması "sağlayıcı böyle bir çalışma yapmadı" anlamına gelmek zorunda değildir, "bildirilmedi" anlamına gelebilir. +### Bir yanıtı istek günlüğüyle ilişkilendirme + +Kabul edilen her HTTP Responses yanıtı, `ocx-<32 hex>` biçiminde proxy +tarafından oluşturulan bir kimlik içeren `x-opencodex-request-id` başlığını +taşır. Bu, yanıtı istek günlüğündeki ve kullanım raporlamasındaki satırına +bağlayan anahtardır. + +Proxy bu değeri her zaman oluşturur ve arayanın sağladığı ya da yukarı akışın +döndürdüğü tüm kimliklerin üzerine yazar; bu nedenle yalnızca bu proxy'ye +özgüdür ve ilişkilendirme anahtarı olarak güvenle kullanılabilir. Başlık, +`Access-Control-Expose-Headers` içinde adlandırılır; bu sayede tarayıcı +JavaScript'i onu farklı kaynaktan okuyabilir — özel bir `x-` başlığı hatta +bulunsa bile aksi halde `response.headers.get()` için görünmezdir. + +Kimlik doğrulama veya kaynak kabulü sırasında reddedilen Responses istekleri bu +sarmalayıcıya hiç ulaşmaz ve kimlik taşımaz; dolayısıyla eksik başlık, isteğin +günlüğe kaydedilmeden önce reddedildiği anlamına gelir. + ### Aynı yol üzerinde WebSocket yükseltmesi `websockets` etkinleştirildiğinde bir istemci bir HTTP POST açmak yerine @@ -330,4 +348,3 @@ okuyamazsa opencodex bu sağlayıcıya okunamayan baytlar göndermek yerine 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/combos.md b/docs-site/src/content/docs/zh-cn/guides/combos.md index 854270fe24..d73f9c04f7 100644 --- a/docs-site/src/content/docs/zh-cn/guides/combos.md +++ b/docs-site/src/content/docs/zh-cn/guides/combos.md @@ -127,6 +127,18 @@ ocx combo set balanced \ 权重是相对值,不是百分比。权重 `2,1` 和 `200,100` 表达的是同样的比例。优先使用能清晰表达意图的小数值。 ::: +### `random`:按请求进行加权抽取 + +`random` 会按与 `weight` 成比例的概率,为每个请求抽取一个合格目标。每个请求都是独立抽取,因此流量会分散到各个目标,而不会形成 `round-robin` 的确定性模式或粘性。`stickyLimit` 不影响此策略。 + +### `least-used`:优先成功次数最少的目标 + +`least-used` 会将每个请求路由到合格目标中,由当前 opencodex 进程记录的成功请求数最少者。进程重启后计数从零开始,计数相同时保持配置顺序。`weight` 和 `stickyLimit` 不影响此策略。 + +### `reset-window`:跟随最近的额度重置 + +`reset-window` 会将每个请求路由到合格目标中,其缓存的提供商额度快照显示下一个窗口最早重置者(五小时、每周、每月或自定义窗口)。这样会优先消耗最先刷新额度的提供商。没有最新额度数据的目标以及并列目标会保持配置顺序。`weight` 和 `stickyLimit` 不影响此策略。 + ## 目标失败时会发生什么 combo 失败分为 **跳转** 失败和 **终止** 失败。 @@ -248,9 +260,9 @@ combo 会存储在顶层的 `combos` 对象中,并以 combo id 作为键: | 字段 | 必填 | 默认值 | 规则 | | --- | --- | --- | --- | | `targets` | 是 | — | 非空、有顺序的数组,元素为已配置的 `{ provider, model, weight? }` 目标。重复的 provider/model 对会被拒绝。 | -| `targets[].weight` | 否 | `1` | 1 到 10,000 的整数。轮询会使用它;故障切换会忽略它。 | -| `strategy` | 否 | `"failover"` | `"failover"` 或 `"round-robin"`。 | -| `stickyLimit` | 否 | `1` | 每次轮询选择可连续处理的成功请求数,范围为 1 到 100。 | +| `targets[].weight` | 否 | `1` | 1 到 10,000 的整数。`round-robin` 和 `random` 会使用它;`failover`、`least-used` 和 `reset-window` 会忽略它。 | +| `strategy` | 否 | `"failover"` | `"failover"`、`"round-robin"`、`"random"`、`"least-used"` 或 `"reset-window"`。 | +| `stickyLimit` | 否 | `1` | 每次 `round-robin` 选择可连续处理 1 到 100 个成功请求。仅适用于 `round-robin`。 | | `defaultEffort` | 否 | `null` | `low`、`medium`、`high`、`xhigh`、`max` 或 `ultra`;仅当调用方省略 effort 且目标声明支持时才会应用。 | | `imageInput` | 否 | `"auto"` | `"auto"` 或 `"disabled"`。`"auto"` 仅在每个目标都支持图片时发布图片能力;`"disabled"` 强制仅文本(从对外能力中去掉图片,并在分发前拒绝带图请求)。 | | `alias` | 否 | 无 | 可选的、已修剪的公开模型 id;使用上面的别名规则。空值会以“无别名”形式存储。 | diff --git a/docs-site/src/content/docs/zh-cn/reference/cli/providers-accounts.md b/docs-site/src/content/docs/zh-cn/reference/cli/providers-accounts.md index 765c21aad6..984ac8c2ec 100644 --- a/docs-site/src/content/docs/zh-cn/reference/cli/providers-accounts.md +++ b/docs-site/src/content/docs/zh-cn/reference/cli/providers-accounts.md @@ -121,13 +121,12 @@ OAuth 账号会显示为 `Account N`,而 plan/label 列会在 plan、屏蔽后 } ``` -### `ocx account list [provider] [--json] [--all]` +### `ocx account list [provider] [--json] [--all] [--quota [--refresh]]` 不指定提供方时,会列出 Codex 池、OAuth 账号和已配置的 API 密钥池。除非提供 `--all`,否则会跳过空的提供方。指定提供方时,只列出该凭据家族。人类可读输出 使用 `PROVIDER TYPE ID PLAN/LABEL PRIORITY STATUS`;手动选中的 Codex 行会标记为 `selected`。 -当存在已存储的 Kiro 账号时,输出会提示 Kiro 只有一个登录槽位,并且再次登录会 -替换当前账号。空结果仍然算成功。`--json` 返回: +当存有两个或更多符合条件的 Kiro 账号时,默认情况下 429 会自动轮换到另一个账号,并优先选择已知剩余额度最多的账号;轮换由账号存在与否驱动,可通过 `oauthAccountFailover.enabled: false` 关闭。`ocx account login kiro` 每次向池中添加一个账号。空结果仍然算成功。`--json` 返回: ```text { accounts: AccountRow[], notes: string[] } 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 bc0590f0ce..754e77e220 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 @@ -79,6 +79,7 @@ selector,而不是分配一个新名称。 | `headers?` | `Record` | 额外的上游请求头。会拒绝 Authorization、cookie、API key 头、嵌入换行符以及无效名称。 | | `openRouterRouting?` | `OpenRouterProviderRouting` | 默认的 OpenRouter `order`、`only` 和 `allowFallbacks` 偏好;仅对使用 `openai-chat` 的规范 OpenRouter 有效。 | | `modelOpenRouterRouting?` | `Record` | 精确模型 id 级别的覆盖项,会替换提供者级 OpenRouter 偏好。 | +| `vercelGatewayRouting?` | `VercelGatewayRouting` | 默认的 Vercel AI Gateway `order`、`only` 和 `sort`(`"cost"` \| `"ttft"` \| `"tps"`)偏好;仅对使用 `openai-chat` 的规范 Vercel AI Gateway 有效。 | | `authMode?` | `"key" \| "forward" \| "oauth" \| "local"` | 身份验证模式(默认 `key`)。OAuth/订阅凭据存放在 `config.json` 之外;`local` 仅限注册表条目允许它的提供者。 | | `codexAccountMode?` | `"pool" \| "direct"` | 仅适用于规范的 `openai`;默认是 Pool。Direct 会绕过池状态。 | | `refreshPolicy?` | `"proactive" \| "lazy-only" \| "disabled"` | 覆盖该 OAuth 提供者的 Token Guardian 策略。 | @@ -88,6 +89,7 @@ selector,而不是分配一个新名称。 | `modelReasoningSummaryDelivery?` | `Record` | 按模型设置的 Responses 交付枚举;会重写现有的 delivery 字段。 | | `modelAdapters?` | `Record` | 按模型设置的 `openai-chat` 或 `openai-responses` 线协议覆盖项,用于混合线协议网关。显式条目优先于注册表默认值;DeepSeek 预设可以为 `deepseek-v4-flash` 选择原生 Responses,GitHub Copilot 则为 GPT-5 系列(`gpt-5.3-codex`、`gpt-5.4`、`gpt-5.4-mini`、`gpt-5.5`、`gpt-5.6-luna`、`gpt-5.6-sol`、`gpt-5.6-terra`)声明了 Responses 专用默认值,因为这些模型在代理流量下会拒绝 `/chat/completions`。没有内置默认值的模型(例如 `gpt-5.4-nano`)可以在此手动启用。单一线协议上游固定项和规范 ChatGPT forward 会拒绝覆盖。 | | xAI Responses 启用项(仪表板) | 开关 | 仅用于 `xai`,以原子方式设置或清除 `grok-4.5` 和 `grok-4.6` 的 `modelAdapters` 条目。若只存在一个条目,则显示混合状态,直到下次开关写入将两者统一。其他覆盖项和层级行为不变。 | +| `xaiResponsesXSearch?` | `boolean` | 默认禁用。在 xAI Responses 目标上,仅当有效的 `web_search` 工具在最终请求规范化后仍保留时,才附加由提供方托管的 `x_search` 声明。不会重复已有声明,绝不会扩大调用方的 `tool_choice`/`allowed_tools` 选择范围,并且此项独立于网络搜索辅助服务的 `search.xSearch` 选项。 | | `modelPreferHostedTools?` | `Record` | 非 forward Responses gateway 的精确模型 ID opt-in,用于上游预留 hosted tool namespace 的情况。目前只支持 `["image_generation"]`;匹配模型必须使用 `openai-responses` wire 且支持该 hosted 工具。它会移除冲突的客户端 `image_gen` 声明,并改写其 selector 以保持调用方的 tool choice。对于 OpenAI API 的虚拟 `-pro` 模型,先匹配所选公开 ID,未命中时才使用解析出的基础 wire-model ID 作为回退。`modelAdapters` 会先按公开 ID、再按基础 ID 解析;后一次结果决定最终 wire。未配置模型保持普通 alias 行为。 | | `annotateEmptyToolOutputs?` | `boolean` | 在工具结果到达模型之前,将存在但为空的结果替换为简短标记,以免空白结果被误认为缺失结果。适用于空白字符串和仅包含文本的部件数组;图像、文件和加密部件绝不会被修改。内置注册表中 `DeepSeek` 的默认值为 `true`,其他情况下不设置。设为 `false` 可让提供者退出此行为——后续编辑即使省略该字段,也会保留显式的 `false`。`PATCH /api/providers?name=` 接受 `true`、`false` 或 `null`;传入 `null` 可清除覆盖值并恢复注册表默认行为。 | | `reasoningEffortMap?` | `Record` | 提供者级、用于推理标签的线协议别名。 | @@ -302,6 +304,37 @@ OpenRouter 可以通过多个推理提供者来提供同一个模型。`openRout 模型键必须是精确的原生 OpenRouter id,不带外层的 opencodex 提供者前缀。选择 `openrouter/anthropic-claude-sonnet-5` 会在应用模型规则之前,还原为原生 `anthropic/claude-sonnet-5`。 +## Vercel AI Gateway 提供者路由 + +Vercel AI Gateway 可以在多个底层推理提供者之间路由一个模型。`vercelGatewayRouting` 配置提供者级偏好;`modelVercelGatewayRouting` 会针对精确模型 ID 替换这些偏好。两者均未设置时,`resolveVercelGatewayRouting()` 返回 `undefined`,因此 Chat 请求构建器会省略 `provider` 字段,Vercel AI Gateway 则保留其默认的动态路由行为。 + +- `order`:按优先级排列的 Vercel AI Gateway 上游提供者 slug。 +- `only`:限制可用 Vercel AI Gateway 上游提供者的显式允许列表。 +- `sort`:按 `"cost"`(成本最低)、`"ttft"`(首个 token 所需时间)或 `"tps"`(每秒 token 数)自动排列可用提供者。 + +```json +{ + "providers": { + "vercel-ai-gateway": { + "adapter": "openai-chat", + "baseUrl": "https://ai-gateway.vercel.sh/v1", + "apiKey": "${VERCEL_AI_GATEWAY_KEY}", + "vercelGatewayRouting": { + "sort": "ttft" + }, + "modelVercelGatewayRouting": { + "zai/glm-5.2": { + "only": ["novita", "deepinfra"], + "order": ["novita", "deepinfra"] + } + } + } + } +} +``` + +模型键是 Vercel 的公开模型选择器,不带外层的 OpenCodex 提供者前缀。选择 `vercel-ai-gateway/zai-glm-5.2` 时,会先还原为原生 `zai/glm-5.2`,再应用模型规则。相同映射也适用于原生 `vercel/` 选择器:在 OpenCodex 中使用编码后的 `vercel-ai-gateway/vercel-` 选择器,并将 `vercel/` 保留为模型键。 + ## 静态模型允许列表 将 `liveModels: false` 设为只暴露 `models`。如果 `models` 为空或省略,该提供者将不暴露任何路由模型。实时发现会在缓存前拒绝超过 4 MiB 或 2,000 条原始模型行;内置预设可能使用更低的限制,并过滤为可聊天的行。过大或格式错误的结果会走陈旧/配置回退。合法的、零可用结果的发现仍然具有权威性,不会被静默替换或截断。 diff --git a/docs-site/src/content/docs/zh-cn/reference/configuration/routing.md b/docs-site/src/content/docs/zh-cn/reference/configuration/routing.md index 11a3ad97ce..609c9ab48f 100644 --- a/docs-site/src/content/docs/zh-cn/reference/configuration/routing.md +++ b/docs-site/src/content/docs/zh-cn/reference/configuration/routing.md @@ -33,6 +33,16 @@ opencodex 按以下顺序解析请求的模型: 向后回退。对于可能匹配多个提供方的规则,提供方条目会按照其 JSON 插入顺序进行检查, 因此当一个裸模型可能存在歧义时,请使用显式命名空间。 +### 被阻止模型重定向 + +`blockedModelRedirects` 是可选的顶层 `Record`,用于精确替换已解析的模型 ID,默认未设置。它在上述解析顺序之后运行:匹配后会保留已选定的提供方和账户路由,仅替换上游模型 ID,并记录路由原因 `blocked-model-redirect`。省略该键则路由保持不变。 + +```json +{ + "blockedModelRedirects": { "gpt-5.6-terra": "gpt-5.6-luna" } +} +``` + ## 精确 Codex 账户选择器 `codexAccountNamespaces` 会把 `side` 这样的公开 selector 映射到一个已存储 Codex 账户。 @@ -61,7 +71,7 @@ Codex Auth 页面将此 picker 行为作为选择加入项。关闭它会隐藏 | 键 | 类型 | 默认值 | 含义 | | --- | --- | --- | --- | | `targets` | `{ provider: string; model: string; weight?: number }[]` | required | 有序的具体路由。`weight` 范围为 1–10000,默认值为 `1`。 | -| `strategy?` | `"failover" \| "round-robin"` | `"failover"` | 选择策略。目标顺序表示故障切换优先级;权重会影响平滑加权轮询。 | +| `strategy?` | `"failover" \| "round-robin" \| "random" \| "least-used" \| "reset-window"` | `"failover"` | 选择策略。目标顺序表示 `failover` 优先级;`weight` 决定 `round-robin` 和 `random` 的抽取权重;`least-used` 根据记录的成功次数选择;`reset-window` 跟随最近的额度重置。 | | `stickyLimit?` | `number` | `1` | 在单个轮询批次中保留的成功请求数。范围 1–100。 | | `defaultEffort?` | `"low" \| "medium" \| "high" \| "xhigh" \| "max" \| "ultra" \| null` | unset | 仅在调用方省略 effort 且所选目标声明了请求的档位时应用。 | | `imageInput?` | `"auto" \| "disabled"` | `"auto"` | `"auto"` 仅在每个目标都支持图片时发布图片能力;`"disabled"` 强制仅文本(从对外能力中去掉图片,并在分发前拒绝带图请求)。 | @@ -107,7 +117,7 @@ Codex Auth 页面将此 picker 行为作为选择加入项。关闭它会隐藏 CLI:`ocx route policy list`、`ocx route policy show `、`ocx route policy dry-run --model-context --tools`、`ocx route policy evaluate `。 -组合是显式的有序/加权目标路由与故障转移;策略配置文件是基于证据在候选之间进行选择。 +组合是采用可选策略的显式目标路由(有序 `failover`、平滑加权的 `round-robin` 或 `random` 均衡、`least-used`,以及 `reset-window`):由配置的策略决定目标,可重试失败则沿列表继续尝试;策略配置文件是基于证据在候选之间进行选择。 ## 请求历史与路由分析 diff --git a/docs-site/src/content/docs/zh-cn/reference/management-api.md b/docs-site/src/content/docs/zh-cn/reference/management-api.md index ab06540139..09910a7a46 100644 --- a/docs-site/src/content/docs/zh-cn/reference/management-api.md +++ b/docs-site/src/content/docs/zh-cn/reference/management-api.md @@ -120,6 +120,8 @@ Authorization: Bearer | `POST /api/storage/cleanup-policy/run` | 启动一次手动清理策略运行 | 409 `already_running`;500 `cleanup_failed` | | `GET /api/storage/cleanup-policy/test-stream` | 仅测试用的策略流钩子 | 不可用时返回 404 `not_found` | +`models`、`providers` 和 `days[].models` 中的记录也带有 `cacheHitRate`:它表示由提供方提示缓存提供的输入 token 比例,并限制在 `[0, 1]` 范围内。当提供方未报告缓存遥测数据或该记录没有输入 token 时,其值为 `null`,绝不会是 `0`,因为“没有缓存数据”与“实际命中率为 0%”是不同的事实,将两者显示为相同结果的图表会产生误导。 + :::caution 存储清理端点可以移动或永久删除已归档的会话数据。务必先预览,并提交返回的摘要。若可能需要恢复,优先选择隔离。 ::: 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 0d18903ecd..52f255091b 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 @@ -82,6 +82,14 @@ Responses 表示是这座桥的中心。原生兼容的路由可以跳过部分 在可用时,`input_tokens_details` 还可以包含 `cache_write_tokens`。始终存在的 detail 对象是严格 Responses 客户端的兼容性保证;零可能表示“未报告”,不一定表示“提供方没有进行此类工作”。 +### 将响应与其请求日志关联 + +每个通过准入的 HTTP Responses 回复都带有 `x-opencodex-request-id` 标头,其中保存代理生成的 `ocx-<32 hex>` 形式 ID。它是将响应与请求日志及使用情况报告中对应记录关联起来的键。 + +代理始终生成此值,并覆盖调用方提供或上游返回的任何 ID,因此该值仅属于此代理,可安全地用作关联键。该标头列在 `Access-Control-Expose-Headers` 中,浏览器 JavaScript 因而可以跨源读取它;否则,即使自定义 `x-` 标头已在网络上传输,`response.headers.get()` 也无法看到它。 + +在身份验证或来源准入阶段被拒绝的 Responses 请求不会到达此包装层,也不会带有 ID。因此,缺少该标头意味着请求在写入日志之前已被拒绝。 + ### 同一路径上的 WebSocket 升级 当启用 `websockets` 时,客户端可以升级 `/v1/responses`,而不是发起 HTTP POST。 diff --git a/docs-site/src/content/docs/zh-tw/guides/combos.md b/docs-site/src/content/docs/zh-tw/guides/combos.md index 155baeb06b..bb8ef901f9 100644 --- a/docs-site/src/content/docs/zh-tw/guides/combos.md +++ b/docs-site/src/content/docs/zh-tw/guides/combos.md @@ -142,6 +142,18 @@ ocx combo set balanced \ 權重是相對的,不是百分比。權重 `2,1` 與 `200,100` 表達同一比例。偏好能傳達意圖的小數值。 ::: +### `random`:每個請求各自進行加權抽選 + +`random` 針對每個請求抽選一個合格目標,中選機率與 `weight` 成正比。每個請求都是獨立抽選,因此流量會分散至各目標,同時不會呈現 `round-robin` 的確定性模式或黏著性。`stickyLimit` 不影響此策略。 + +### `least-used`:優先選擇成功次數最少的目標 + +`least-used` 將每個請求路由至這個 opencodex 行程所記錄成功請求數最少的合格目標。重新啟動後,計數從零開始;若計數相同,則維持設定順序。`weight` 與 `stickyLimit` 不影響此策略。 + +### `reset-window`:跟隨最早的配額重設 + +`reset-window` 將每個請求路由至快取供應商配額快照顯示下一個時段最早重設的合格目標(五小時、每週、每月或自訂)。這會優先使用最早重新取得額度的供應商。沒有最新配額資料的目標,以及發生平手時,皆維持設定順序。`weight` 與 `stickyLimit` 不影響此策略。 + ## 目標失敗時會發生什麼 Combo 失敗分為**跳轉**失敗與**終端**失敗。 @@ -253,9 +265,9 @@ Combo 儲存於頂層 `combos` 物件中,以 combo id 為 key: | 欄位 | 必填 | 預設值 | 規則 | | --- | --- | --- | --- | | `targets` | 是 | — | 已設定 `{ provider, model, weight? }` 目標的非空有序陣列。重複的供應商/模型對會被拒絕。 | -| `targets[].weight` | 否 | `1` | 1 到 10,000 的整數。由 round-robin 使用;failover 忽略。 | -| `strategy` | 否 | `"failover"` | `"failover"` 或 `"round-robin"`。 | -| `stickyLimit` | 否 | `1` | 每次 round-robin 選擇的成功請求數,1 到 100 的整數。 | +| `targets[].weight` | 否 | `1` | 1 到 10,000 的整數。由 `round-robin` 與 `random` 使用;`failover`、`least-used` 與 `reset-window` 忽略。 | +| `strategy` | 否 | `"failover"` | 可用值為 `"failover"`、`"round-robin"`、`"random"`、`"least-used"`、`"reset-window"`。 | +| `stickyLimit` | 否 | `1` | 僅適用於 `round-robin`:每次選擇的成功請求數,1 到 100 的整數。 | | `defaultEffort` | 否 | `null` | `low`、`medium`、`high`、`xhigh`、`max` 或 `ultra`;僅在呼叫者省略 effort 且目標宣告支援時套用。 | | `alias` | 否 | 無 | 可選的修剪後公開模型 id;使用上述別名規則。空值儲存為無別名。 | diff --git a/docs-site/src/content/docs/zh-tw/reference/cli/providers-accounts.md b/docs-site/src/content/docs/zh-tw/reference/cli/providers-accounts.md index ec2063b31b..33722358f3 100644 --- a/docs-site/src/content/docs/zh-tw/reference/cli/providers-accounts.md +++ b/docs-site/src/content/docs/zh-tw/reference/cli/providers-accounts.md @@ -92,9 +92,9 @@ Codex 池選擇套用於清除既有親和性後的下一個請求;進行中 } ``` -### `ocx account list [provider] [--json] [--all]` +### `ocx account list [provider] [--json] [--all] [--quota [--refresh]]` -未指定供應商時,列出 Codex 池、OAuth 帳號與已設定的 API-key 池。除非存在 `--all`,否則空的供應商會被跳過。指定供應商時,僅列出該憑證家族。人類輸出使用 `PROVIDER TYPE ID PLAN/LABEL STATUS`;手動選擇的 Codex 列標記為 `selected`。當存在已儲存的 Kiro 帳號時,輸出會註明 Kiro 只有一個登入插槽,再次登入會取代目前帳號。空結果仍為成功。`--json` 回傳: +未指定供應商時,列出 Codex 池、OAuth 帳號與已設定的 API-key 池。除非存在 `--all`,否則空的供應商會被跳過。指定供應商時,僅列出該憑證家族。人類輸出使用 `PROVIDER TYPE ID PLAN/LABEL STATUS`;手動選擇的 Codex 列標記為 `selected`。當儲存了兩個以上符合資格的 Kiro 帳號時,預設情況下 429 會自動輪換至另一個帳號,並優先選擇已知剩餘額度最多的帳號;輪換由帳號存在與否驅動,可透過 `oauthAccountFailover.enabled: false` 關閉。`ocx account login kiro` 每次將一個帳號加入池中。空結果仍為成功。`--json` 回傳: ```text { accounts: AccountRow[], notes: string[] } 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 065419cddf..d64e5dc350 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 @@ -60,6 +60,7 @@ description: 供應商項目、認證、端點、模型目錄、配額、context | `headers?` | `Record` | 額外上游標頭。Authorization、cookie、API-key 標頭、內嵌換行與無效名稱被拒絕。 | | `openRouterRouting?` | `OpenRouterProviderRouting` | 預設 OpenRouter `order`、`only` 與 `allowFallbacks` 偏好;僅對規範 OpenRouter 搭配 `openai-chat` 有效。 | | `modelOpenRouterRouting?` | `Record` | 取代供應商範圍 OpenRouter 偏好的精確 model-id 覆寫。 | +| `vercelGatewayRouting?` | `VercelGatewayRouting` | 預設 Vercel AI Gateway `order`、`only` 與 `sort`(`"cost"` \| `"ttft"` \| `"tps"`)偏好;僅對規範 Vercel AI Gateway 搭配 `openai-chat` 有效。 | | `authMode?` | `"key" \| "forward" \| "oauth" \| "local"` | 認證模式(預設 `key`)。OAuth/訂閱憑證儲存在 `config.json` 之外;`local` 僅限其 registry 項目允許的供應商。 | | `codexAccountMode?` | `"pool" \| "direct"` | 僅規範 `openai`;預設為池。Direct 繞過池狀態。 | | `refreshPolicy?` | `"proactive" \| "lazy-only" \| "disabled"` | 覆寫此 OAuth 供應商的 Token Guardian 政策。 | @@ -70,6 +71,7 @@ description: 供應商項目、認證、端點、模型目錄、配額、context | `modelAdapters?` | `Record` | 混合 wire 閘道的 Per-model `openai-chat` 或 `openai-responses` wire 覆寫。明確項目勝過 registry 預設;DeepSeek 的預設可為 `deepseek-v4-flash` 選擇原生 Responses。單一 wire 上游 pin 與規範 ChatGPT forward 拒絕覆寫。 | | xAI Responses 選用(儀表板) | 開關 | 僅用於 `xai`,以原子方式設定或清除 `grok-4.5` 與 `grok-4.6` 的 `modelAdapters` 項目。若只有一個項目,會顯示混合狀態,直到下次開關寫入統一兩者。其他覆寫與層級行為不變。 | | `annotateEmptyToolOutputs?` | `boolean` | 在工具結果送達模型前,將已存在但為空的結果替換成簡短標記,使空白結果不會被解讀為遺漏的結果。適用於空白字串及僅含文字部分的陣列;影像、檔案及加密部分絕不會被更動。DeepSeek 透過內建登錄檔預設為 `true`,其他情況則不設定。設為 `false` 可讓供應商停用此功能;後續編輯即使省略此欄位,也會保留明確設定的 `false`。`PATCH /api/providers?name=` 接受 `true`、`false` 或 `null`;`null` 會清除覆寫並恢復使用登錄檔的預設行為。 | +| `xaiResponsesXSearch?` | `boolean` | 預設停用。在 xAI Responses 目的地上,僅當即時 `web_search` 工具通過最終請求正規化後仍保留時,才附加由供應商託管的 `x_search` 宣告。既有宣告不會重複,呼叫端的 `tool_choice`/`allowed_tools` 選擇器絕不會擴大,且此設定與網頁搜尋輔助服務的 `search.xSearch` 選項分開。 | | `reasoningEffortMap?` | `Record` | 供應商範圍的 reasoning 標籤 wire 別名。 | | `modelReasoningEffortMap?` | `Record>` | Per-model 的 reasoning 標籤 wire 別名。 | | `noReasoningModels?` | `string[]` | 拒絕 reasoning/thinking 參數的模型。 | @@ -270,6 +272,37 @@ OpenRouter 可透過多個推論供應商提供一個模型。`openRouterRouting 模型 key 為精確的原生 OpenRouter id,不含外層 opencodex 供應商前綴。選擇 `openrouter/anthropic-claude-sonnet-5` 會在套用模型規則前還原原生 `anthropic/claude-sonnet-5`。 +## Vercel AI Gateway 供應商路由 + +Vercel AI Gateway 可在多個底層推論供應商之間路由一個模型。`vercelGatewayRouting` 設定供應商範圍偏好;`modelVercelGatewayRouting` 會針對精確模型 ID 取代它。若兩者皆未設定,`resolveVercelGatewayRouting()` 會回傳 `undefined`,因此 Chat 請求建構器會省略 `provider` 欄位,讓 Vercel AI Gateway 保留其預設的動態路由行為。 + +- `order`:依優先順序排列的 Vercel AI Gateway 上游供應商 slug。 +- `only`:限制合格 Vercel AI Gateway 上游供應商的明確允許清單。 +- `sort`:依 `"cost"`(最低成本)、`"ttft"`(首個權杖時間)或 `"tps"`(每秒權杖數)自動排序合格供應商。 + +```json +{ + "providers": { + "vercel-ai-gateway": { + "adapter": "openai-chat", + "baseUrl": "https://ai-gateway.vercel.sh/v1", + "apiKey": "${VERCEL_AI_GATEWAY_KEY}", + "vercelGatewayRouting": { + "sort": "ttft" + }, + "modelVercelGatewayRouting": { + "zai/glm-5.2": { + "only": ["novita", "deepinfra"], + "order": ["novita", "deepinfra"] + } + } + } + } +} +``` + +模型 key 是不含外層 OpenCodex 供應商前綴的 Vercel 公開模型選擇器。選擇 `vercel-ai-gateway/zai-glm-5.2` 時,會先還原原生 `zai/glm-5.2`,再套用模型規則。相同映射也適用於原生 `vercel/` 選擇器:在 OpenCodex 中使用編碼後的 `vercel-ai-gateway/vercel-` 選擇器,並保留 `vercel/` 作為模型 key。 + ## 靜態模型允許清單 設定 `liveModels: false` 以僅暴露 `models`。若 `models` 為空或省略,供應商暴露無路由模型。即時探索在快取前拒絕超過 4 MiB 或 2,000 個原始模型列;內建預設可能使用較低限制並過濾到 chat 合格列。過大或格式錯誤的結果遵循過時/設定的後備。有效的零合格結果恆為權威,且不被靜默取代或截斷。 diff --git a/docs-site/src/content/docs/zh-tw/reference/configuration/routing.md b/docs-site/src/content/docs/zh-tw/reference/configuration/routing.md index e2ca4f3622..13a4e2622e 100644 --- a/docs-site/src/content/docs/zh-tw/reference/configuration/routing.md +++ b/docs-site/src/content/docs/zh-tw/reference/configuration/routing.md @@ -29,6 +29,16 @@ opencodex 依此順序解析請求的模型: 已停用的供應商被排除。對已停用供應商的明確命名空間會失敗而非往下落。當規則可符合多個供應商時,供應商項目依其 JSON 插入順序檢查,因此裸模型有歧義時請使用明確命名空間。 +### 封鎖模型重新導向 + +`blockedModelRedirects` 是選用的頂層 `Record`,用於精確替換已解析的模型 id,預設不設定。它在上述解析順序後執行:符合時會保留已選取的供應商與帳號路由,僅替換上游模型 id,並記錄路由原因 `blocked-model-redirect`。省略此鍵時,路由維持不變。 + +```json +{ + "blockedModelRedirects": { "gpt-5.6-terra": "gpt-5.6-luna" } +} +``` + ## 精確 Codex 帳號選擇器 `codexAccountNamespaces` 將一個公開選擇器(如 `side`)映射到一個已儲存的 Codex 帳號。對 `side/gpt-5.6-sol` 的請求僅使用該帳號——即使在 Direct 模式下標準的 `openai` 供應商亦然——並向上游發送裸的 `gpt-5.6-sol` 模型 id。選擇器之後只有裸的原生 OpenAI 家族 id 有效。 @@ -44,7 +54,7 @@ Codex Auth 頁面將此 picker 行為作為選擇加入功能暴露。停用它 | Key | 型別 | 預設值 | 意義 | | --- | --- | --- | --- | | `targets` | `{ provider: string; model: string; weight?: number }[]` | 必填 | 有序的具體路由。`weight` 為 1–10000,預設 `1`。 | -| `strategy?` | `"failover" \| "round-robin"` | `"failover"` | 選擇策略。目標順序為 failover 優先序;權重塑造平滑的加權 round-robin。 | +| `strategy?` | `"failover" \| "round-robin" \| "random" \| "least-used" \| "reset-window"` | `"failover"` | 選擇策略。目標順序為 `failover` 優先序;`weight` 塑造 `round-robin` 與 `random` 抽選;`least-used` 依循已記錄的成功次數;`reset-window` 依循最早的配額重設。 | | `stickyLimit?` | `number` | `1` | 在一個 round-robin 批次中保留的成功請求數。範圍 1–100。 | | `defaultEffort?` | `"low" \| "medium" \| "high" \| "xhigh" \| "max" \| "ultra" \| null` | 未設定 | 僅在呼叫者省略 effort 且所選目標廣告請求的階層時套用。 | | `alias?` | `string` | — | 可選的公開模型 id,取代標準 picker slug。 | @@ -125,7 +135,7 @@ Dry-run 評估候選項而不發送任何上游請求。 ### 組合 vs 政策設定檔 -- **combo** 是明確的有序/加權目標路由與 failover:設定的順序(或平滑加權 round-robin)決定,失敗會沿清單前進。 +- **combo** 是使用可選策略的明確目標路由(有序 `failover`、平滑加權 `round-robin` 或 `random` 平衡、`least-used` 或 `reset-window`):由設定的策略決定,發生可重試失敗時則沿清單前進。 - **政策設定檔** 是在設定候選項中的證據式選擇:硬性能力需求先過濾,再以確定性計分排列倖存者。 兩者皆為附別名與碰撞驗證的虛擬命名空間;差異在所選候選項的**方式**。設定檔計分結合設定優先元件與健康(RI-06)、配額(RI-07)與成本(RI-08)計分維度(有證據時);`latency` 權重併入優先份額而非獨立計分。成本也透過 `limits.maxEstimatedCostUsd` 上限強制執行:估計成本已知且超過上限的候選項被排除(`cost-limit`)。設定上限且估計未知時,預設 `limits.onUnknownCost: "allow"` 在路由決策軌跡上記錄 `cost.capOutcome: "unknown-allowed"` 而不做上限排除;設定 `onUnknownCost: "exclude"` 以取得 fail-closed 上限(`cost-limit-unknown`)。上限結果不是整體資格——`unknownEvidence.cost: "exclude"` 仍可新增 `unknown-price` 並將候選項標記為不合格。政策設定檔執行時會記錄 per-request 的路由決策軌跡。 diff --git a/docs-site/src/content/docs/zh-tw/reference/management-api.md b/docs-site/src/content/docs/zh-tw/reference/management-api.md index 52d6db4d8e..3c996662cb 100644 --- a/docs-site/src/content/docs/zh-tw/reference/management-api.md +++ b/docs-site/src/content/docs/zh-tw/reference/management-api.md @@ -120,6 +120,8 @@ Session 簽發在需要 data-plane 認證時停用,這包含遠端綁定。遠 | `POST /api/storage/cleanup-policy/run` | 啟動手動清理政策執行 | 409 `already_running`;500 `cleanup_failed` | | `GET /api/storage/cleanup-policy/test-stream` | 僅測試的政策串流 hook | 不可用時 404 `not_found` | +`models`、`providers` 及 `days[].models` 中的列也帶有 `cacheHitRate`:表示由供應商提示快取提供的輸入權杖比例,並限制在 `[0, 1]`。當供應商未回報快取遙測資料,或該列沒有輸入權杖時,其值為 `null`,絕不會是 `0`;因為「沒有快取資料」與「確實為 0% 的命中率」是不同事實,若圖表將兩者呈現為相同狀態,便會造成誤導。 + :::caution 儲存清理端點可移動或永久移除已封存的 session 資料。請務必先預覽並提交回傳的摘要。在可能需要復原時偏好隔離。 ::: 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 64852d205c..5587b88ae2 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 @@ -67,6 +67,14 @@ Responses 表示是橋接的中心。原生相容的路由可跳過部分轉譯 可用時,`input_tokens_details` 亦可包含 `cache_write_tokens`。恆存在的 detail 物件是對嚴格 Responses 客戶端的相容性保證;零可能意指「未回報」,不一定是「供應商未執行此類工作」。 +### 將回應與其請求日誌相互關聯 + +每個通過准入的 HTTP Responses 回覆都帶有 `x-opencodex-request-id` 標頭,其中保存代理產生、格式為 `ocx-<32 hex>` 的識別碼。它是將回應連結至請求日誌及用量報告中對應列的關鍵。 + +代理一律產生此值,並覆寫呼叫端提供或上游傳回的任何識別碼,因此它專屬於此代理,可安全信任為關聯鍵。該標頭列於 `Access-Control-Expose-Headers` 中,這讓瀏覽器中的 JavaScript 能跨來源讀取它;否則即使自訂 `x-` 標頭已在實際傳輸中,`response.headers.get()` 仍看不到它。 + +在認證或來源准入階段遭拒的 Responses 請求不會進入此包裝層,也不會帶有識別碼,因此缺少此標頭表示該請求在寫入日誌前已遭拒。 + ### 同路徑上的 WebSocket 升級 當 `websockets` 啟用時,客戶端可升級 `/v1/responses` 而非開啟 HTTP POST。認證與來源許可在 WebSocket 握手期間發生。它們不在每個 frame 內重複。 diff --git a/src/cli/account.ts b/src/cli/account.ts index e6269c6940..acda3639b8 100644 --- a/src/cli/account.ts +++ b/src/cli/account.ts @@ -25,8 +25,19 @@ type TargetProvenance = "live-oauth-list" | "config" | "codex"; const MAIN_ALIAS = "main"; const MAIN_CODEX_ID = "__main__"; -/** Replacement-style single-slot OAuth (no stable identity; not HTTP-derivable). */ -const REPLACEMENT_STYLE_OAUTH = new Set(["kiro"]); +/** + * Replacement-style single-slot OAuth (no stable identity; not HTTP-derivable). + * + * Empty since `d82b3049d` gave Kiro a quota-aware account pool: multiple Kiro accounts are + * stored under multiauth, ranked by remaining headroom in `rankAccountsByHeadroom`, and + * rotated on 429 by the generic OAuth failover path, which does not exclude Kiro. Printing a + * "single login slot" note alongside a list of several pooled accounts told operators the + * opposite of what the runtime does. + * + * Kept as a named seam rather than deleted: the replacement-style shape is a real category, + * and a future provider without stable per-account identity belongs here. + */ +const REPLACEMENT_STYLE_OAUTH = new Set(); const ACCOUNT_USAGE = `Usage: ocx account list [provider] [--json] [--all] [--quota [--refresh]] diff --git a/tests/cli-account.test.ts b/tests/cli-account.test.ts index c16a72ff63..7c16eb03e5 100644 --- a/tests/cli-account.test.ts +++ b/tests/cli-account.test.ts @@ -589,12 +589,15 @@ describe("ocx account CLI (issue #180 matrix)", () => { expect(machine.output).not.toContain(RAW_SENTINEL); }); - test("12: list kiro prints the single-slot replacement note", async () => { + test("12: list kiro does not claim a single login slot", async () => { + // Kiro pools multiple accounts since d82b3049d (quota-aware ranking + 429 rotation), so + // the old replacement-style note contradicted the runtime. Asserting its ABSENCE is what + // keeps the CLI and the docs from drifting apart again. const result = await run(["list", "kiro"]); expect(result.code).toBe(0); - expect(result.stdout).toContain("single login slot"); - expect(result.stdout).toContain("re-login replaces the current account"); + expect(result.stdout).not.toContain("single login slot"); + expect(result.stdout).not.toContain("re-login replaces the current account"); }); test("13: bare account and use without an id return usage errors", async () => {