feat: Add Codex OAuth FAST mode toggle (#2210)

* Add Codex OAuth FAST mode toggle

* fix(codex-oauth): default FAST mode to off to avoid surprise quota burn

service_tier="priority" consumes ChatGPT subscription quota at a higher
rate. Users must now opt in explicitly rather than inherit FAST mode
silently when this feature ships.

---------

Co-authored-by: Jason <farion1231@gmail.com>
This commit is contained in:
Jesus Díaz Rivas
2026-04-23 06:05:17 +02:00
committed by GitHub
parent 444c123ad0
commit 10e0772d8c
11 changed files with 181 additions and 40 deletions
@@ -82,6 +82,8 @@ interface ClaudeFormFieldsProps {
isCodexOauthAuthenticated?: boolean;
selectedCodexAccountId?: string | null;
onCodexAccountSelect?: (accountId: string | null) => void;
codexFastMode?: boolean;
onCodexFastModeChange?: (enabled: boolean) => void;
// Template Values
templateValueEntries: Array<[string, TemplateValueConfig]>;
@@ -148,6 +150,8 @@ export function ClaudeFormFields({
isCodexOauthPreset,
selectedCodexAccountId,
onCodexAccountSelect,
codexFastMode,
onCodexFastModeChange,
templateValueEntries,
templateValues,
templatePresetName,
@@ -374,6 +378,8 @@ export function ClaudeFormFields({
<CodexOAuthSection
selectedAccountId={selectedCodexAccountId}
onAccountSelect={onCodexAccountSelect}
fastModeEnabled={codexFastMode}
onFastModeChange={onCodexFastModeChange}
/>
)}
@@ -3,6 +3,7 @@ import { useTranslation } from "react-i18next";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Label } from "@/components/ui/label";
import { Switch } from "@/components/ui/switch";
import {
Select,
SelectContent,
@@ -30,6 +31,10 @@ interface CodexOAuthSectionProps {
selectedAccountId?: string | null;
/** 账号选择回调 */
onAccountSelect?: (accountId: string | null) => void;
/** 是否开启 Codex FAST mode */
fastModeEnabled?: boolean;
/** FAST mode 切换回调 */
onFastModeChange?: (enabled: boolean) => void;
}
/**
@@ -42,6 +47,8 @@ export const CodexOAuthSection: React.FC<CodexOAuthSectionProps> = ({
className,
selectedAccountId,
onAccountSelect,
fastModeEnabled = false,
onFastModeChange,
}) => {
const { t } = useTranslation();
const [copied, setCopied] = React.useState(false);
@@ -140,6 +147,27 @@ export const CodexOAuthSection: React.FC<CodexOAuthSectionProps> = ({
</div>
)}
{onFastModeChange && (
<div className="flex items-center justify-between rounded-md border bg-muted/30 p-3">
<div className="space-y-1 pr-4">
<Label className="text-sm font-medium">
{t("codexOauth.fastMode", "FAST mode")}
</Label>
<p className="text-xs text-muted-foreground">
{t("codexOauth.fastModeDescription", {
defaultValue:
'Send service_tier="priority" for lower latency. Turn it off if the ChatGPT Codex backend rejects the parameter.',
})}
</p>
</div>
<Switch
checked={fastModeEnabled}
onCheckedChange={onFastModeChange}
aria-label={t("codexOauth.fastMode", "FAST mode")}
/>
</div>
)}
{/* 已登录账号列表 */}
{hasAnyAccount && (
<div className="space-y-2">
@@ -382,6 +382,9 @@ export function ProviderForm({
const [selectedCodexAccountId, setSelectedCodexAccountId] = useState<
string | null
>(() => resolveManagedAccountId(initialData?.meta, "codex_oauth"));
const [codexFastMode, setCodexFastMode] = useState<boolean>(
() => initialData?.meta?.codexFastMode ?? false,
);
const {
codexAuth,
@@ -1115,7 +1118,7 @@ export function ProviderForm({
const providerType =
templatePreset?.providerType || initialData?.meta?.providerType;
payload.meta = {
const nextMeta: ProviderMeta = {
...(baseMeta ?? {}),
commonConfigEnabled:
appId === "claude"
@@ -1146,6 +1149,7 @@ export function ProviderForm({
isCopilotProvider && selectedGitHubAccountId
? selectedGitHubAccountId
: undefined,
codexFastMode: isCodexOauthProvider ? codexFastMode : undefined,
testConfig: testConfig.enabled ? testConfig : undefined,
costMultiplier: pricingConfig.enabled
? pricingConfig.costMultiplier
@@ -1170,6 +1174,12 @@ export function ProviderForm({
: undefined,
};
if (!isCodexOauthProvider && "codexFastMode" in nextMeta) {
delete nextMeta.codexFastMode;
}
payload.meta = nextMeta;
await onSubmit(payload);
};
@@ -1735,6 +1745,8 @@ export function ProviderForm({
isCodexOauthAuthenticated={isCodexOauthAuthenticated}
selectedCodexAccountId={selectedCodexAccountId}
onCodexAccountSelect={setSelectedCodexAccountId}
codexFastMode={codexFastMode}
onCodexFastModeChange={setCodexFastMode}
templateValueEntries={templateValueEntries}
templateValues={templateValues}
templatePresetName={templatePreset?.name || ""}
+3 -1
View File
@@ -929,7 +929,9 @@
"addAnotherAccount": "Add another account",
"logoutAll": "Logout all accounts",
"retry": "Retry",
"copyCode": "Copy code"
"copyCode": "Copy code",
"fastMode": "FAST mode",
"fastModeDescription": "Send service_tier=\"priority\" for lower latency. Off by default — enabling it consumes your ChatGPT quota at a higher rate."
},
"endpointTest": {
"title": "API Endpoint Management",
+3 -1
View File
@@ -929,7 +929,9 @@
"addAnotherAccount": "別のアカウントを追加",
"logoutAll": "すべてのアカウントをログアウト",
"retry": "再試行",
"copyCode": "コードをコピー"
"copyCode": "コードをコピー",
"fastMode": "FAST モード",
"fastModeDescription": "低遅延のため service_tier=\"priority\" を送信します。既定ではオフ——オンにすると ChatGPT のクォータがより速く消費されます。"
},
"endpointTest": {
"title": "API エンドポイント管理",
+3 -1
View File
@@ -929,7 +929,9 @@
"addAnotherAccount": "添加其他账号",
"logoutAll": "注销所有账号",
"retry": "重试",
"copyCode": "复制代码"
"copyCode": "复制代码",
"fastMode": "FAST 模式",
"fastModeDescription": "发送 service_tier=\"priority\" 换取更低延迟。默认关闭——开启后会按更高速率消耗 ChatGPT 配额。"
},
"endpointTest": {
"title": "请求地址管理",
+2
View File
@@ -155,6 +155,8 @@ export interface ProviderMeta {
isFullUrl?: boolean;
// Prompt cache key for OpenAI Responses-compatible endpoints (improves cache hit rate)
promptCacheKey?: string;
// Codex OAuth FAST mode: injects service_tier="priority" on ChatGPT Codex requests
codexFastMode?: boolean;
// 供应商类型(用于识别 Copilot 等特殊供应商)
providerType?: string;
// GitHub Copilot 关联账号 ID(旧字段,保留兼容读取)