import { useState } from 'react'; import { CircleAlert, Loader2, SlidersHorizontal } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import type { CodexTopLevelSettingsPatch } from '@/hooks/use-codex-types'; import type { CodexTopLevelSettingsView } from '@/lib/codex-config'; import { CodexConfigCardShell } from './codex-config-card-shell'; const UNSET = '__unset__'; const GPT_54_MAX_CONTEXT_WINDOW = 1_050_000; const GPT_54_STANDARD_CONTEXT_WINDOW = 272_000; const CCS_GPT_54_STARTER_CONTEXT_WINDOW = 800_000; const CCS_GPT_54_STARTER_AUTO_COMPACT_TOKEN_LIMIT = 700_000; const INTEGER_FORMATTER = new Intl.NumberFormat('en-US'); interface CodexTopLevelControlsCardProps { values: CodexTopLevelSettingsView; providerNames: string[]; disabled?: boolean; disabledReason?: string | null; saving?: boolean; onSave: (values: CodexTopLevelSettingsPatch) => Promise | void; } function toSelectValue(value: string | null | undefined) { return value ?? UNSET; } function withCurrentValue(options: string[], current: string | null | undefined) { return current && !options.includes(current) ? [current, ...options] : options; } function formatInteger(value: number) { return INTEGER_FORMATTER.format(value); } function isGpt54ModelId(value: string | null | undefined) { return value?.trim().toLowerCase().startsWith('gpt-5.4') ?? false; } function buildTopLevelPatch( initialValues: CodexTopLevelSettingsView, draft: CodexTopLevelSettingsView ): CodexTopLevelSettingsPatch { const patch: CodexTopLevelSettingsPatch = {}; if (draft.model !== initialValues.model) patch.model = draft.model; if (draft.modelReasoningEffort !== initialValues.modelReasoningEffort) { patch.modelReasoningEffort = draft.modelReasoningEffort; } if (draft.modelContextWindow !== initialValues.modelContextWindow) { patch.modelContextWindow = draft.modelContextWindow; } if (draft.modelAutoCompactTokenLimit !== initialValues.modelAutoCompactTokenLimit) { patch.modelAutoCompactTokenLimit = draft.modelAutoCompactTokenLimit; } if (draft.modelProvider !== initialValues.modelProvider) { patch.modelProvider = draft.modelProvider; } if (draft.approvalPolicy !== initialValues.approvalPolicy) { patch.approvalPolicy = draft.approvalPolicy; } if (draft.sandboxMode !== initialValues.sandboxMode) patch.sandboxMode = draft.sandboxMode; if (draft.webSearch !== initialValues.webSearch) patch.webSearch = draft.webSearch; if (draft.toolOutputTokenLimit !== initialValues.toolOutputTokenLimit) { patch.toolOutputTokenLimit = draft.toolOutputTokenLimit; } if (draft.personality !== initialValues.personality) patch.personality = draft.personality; return patch; } interface TopLevelControlsFormProps { initialValues: CodexTopLevelSettingsView; providerNames: string[]; disabled: boolean; saving: boolean; onSave: (values: CodexTopLevelSettingsPatch) => Promise | void; } function TopLevelControlsForm({ initialValues, providerNames, disabled, saving, onSave, }: TopLevelControlsFormProps) { const { t } = useTranslation(); const [draft, setDraft] = useState(initialValues); const reasoningOptions = withCurrentValue( ['minimal', 'low', 'medium', 'high', 'xhigh'], draft.modelReasoningEffort ); const providerOptions = withCurrentValue(providerNames, draft.modelProvider); const approvalOptions = withCurrentValue( ['on-request', 'never', 'untrusted'], draft.approvalPolicy ); const sandboxOptions = withCurrentValue( ['read-only', 'workspace-write', 'danger-full-access'], draft.sandboxMode ); const webSearchOptions = withCurrentValue(['cached', 'live', 'disabled'], draft.webSearch); const personalityOptions = withCurrentValue(['none', 'friendly', 'pragmatic'], draft.personality); const patch = buildTopLevelPatch(initialValues, draft); const hasChanges = Object.keys(patch).length > 0; const isGpt54Selected = isGpt54ModelId(draft.model); const parseOptionalInteger = (value: string) => { const trimmed = value.trim(); return trimmed.length > 0 ? Number(trimmed) : null; }; return ( <>

{t('codex.model')}

setDraft((current) => ({ ...current, model: event.target.value || null })) } placeholder="gpt-5.4" disabled={disabled} />

{t('codex.reasoningEffort')}

{t('codex.defaultProvider')}

{t('codex.approvalPolicy')}

{t('codex.sandboxMode')}

{t('codex.webSearch')}

{t('codex.toolOutputTokenLimit')}

setDraft((current) => ({ ...current, toolOutputTokenLimit: event.target.value ? Number(event.target.value) : null, })) } placeholder="25000" disabled={disabled} />

{t('codex.personality')}

{t('codex.longContextOverride')}

{/* TODO i18n: missing key codex.manualOptInOnly */} Manual opt-in only {/* TODO i18n: missing keys codex.gpt54Selected / codex.gpt54Reference */} {isGpt54Selected ? 'GPT-5.4 selected' : 'GPT-5.4 reference'}

{/* TODO i18n: missing key codex.draftValuesOnly */} Draft values only. Nothing applies until Save.

{/* TODO i18n: missing key codex.officialMax */} Official max

1.05M / 1M

{t('codex.gptContextCap')}

{/* TODO i18n: missing key codex.standardWindow */} Standard window

{formatInteger(GPT_54_STANDARD_CONTEXT_WINDOW)}

{t('codex.normalUsageWindow')}

{/* TODO i18n: missing key codex.above272k */} Above 272K

{t('codex.counts2x')}

{t('codex.usageLimitCost')}

{/* TODO i18n: missing key codex.oneCautiousPair */} One cautious pair

{/* TODO i18n: missing key codex.context */} Context {formatInteger(CCS_GPT_54_STARTER_CONTEXT_WINDOW)}
{/* TODO i18n: missing key codex.autoCompact */} Auto-compact {formatInteger(CCS_GPT_54_STARTER_AUTO_COMPACT_TOKEN_LIMIT)}
{/* TODO i18n: missing key codex.notOfficial */} Not official {/* TODO i18n: missing key codex.draftOnly */} Draft only
{t('codex.quickFillWarning')} {!isGpt54Selected && draft.model ? ( {/* TODO i18n: missing key codex.shouldBeCheckedSeparately */} {draft.model} should be checked separately. ) : null}

{t('codex.modelContextWindow')}

setDraft((current) => ({ ...current, modelContextWindow: parseOptionalInteger(event.target.value), })) } // TODO i18n: missing key codex.unset placeholder="Unset" disabled={disabled} />

{/* TODO i18n: missing key codex.writesModelContextWindow */} Writes model_context_window. Leave unset to keep Codex defaults.

{t('codex.autoCompactTokenLimit')}

setDraft((current) => ({ ...current, modelAutoCompactTokenLimit: parseOptionalInteger(event.target.value), })) } // TODO i18n: missing key codex.unset placeholder="Unset" disabled={disabled} />

{/* TODO i18n: missing key codex.writesAutoCompactTokenLimit */} Writes model_auto_compact_token_limit. Leave unset to keep model defaults.

{/* TODO i18n: missing key codex.docs */} Docs {/* TODO i18n: missing key codex.gpt54ModelPage */} GPT-5.4 model page {/* TODO i18n: missing key codex.releaseNotes */} Release notes {/* TODO i18n: missing key codex.configReference */} Config reference
); } export function CodexTopLevelControlsCard({ values, providerNames, disabled = false, disabledReason, saving = false, onSave, }: CodexTopLevelControlsCardProps) { return ( } // TODO i18n: missing key codex.topLevelControlsDesc description="Structured controls for the stable top-level Codex settings users touch most often. Unsupported upstream shapes stay untouched and should be edited in raw TOML." disabledReason={disabledReason} > ); }