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 || ""}