;
brokenLabel: string;
deprecatedLabel: string;
}) {
return (
<>
{model.broken && (
{brokenLabel}
)}
{model.deprecated && (
{deprecatedLabel}
)}
>
);
}
function CodexEffortBadge({ modelId }: { modelId: string | undefined }) {
const codexEffort = getCodexEffortDisplay(modelId);
if (!codexEffort) return null;
return (
{codexEffort.label}
);
}
export function ProviderModelSelector({
catalog,
isLoading,
value,
onChange,
disabled,
placeholder,
className,
}: ProviderModelSelectorProps) {
const { t } = useTranslation();
const resolvedPlaceholder = placeholder ?? t('providerModelSelector.selectModel');
const groupedModels = useMemo(() => {
if (!catalog?.models) return { free: [], paid: [] };
return {
free: catalog.models.filter((model) => !model.tier || model.tier === 'free'),
paid: catalog.models.filter((model) => model.tier === 'paid'),
};
}, [catalog]);
const selectedModel = useMemo(
() => catalog?.models.find((model) => model.id === value),
[catalog, value]
);
if (isLoading) {
return ;
}
if (!catalog || catalog.models.length === 0) {
return (
{t('providerModelSelector.noModelsForProvider')}
);
}
return (
{t('providerModelSelector.freeTier')}
),
},
{
key: 'paid',
label: (
{t('providerModelSelector.paidTier')}
),
},
]}
options={[...groupedModels.free, ...groupedModels.paid].map((model) => ({
value: model.id,
groupKey: model.tier === 'paid' ? 'paid' : 'free',
searchText: `${model.name} ${model.id}`,
keywords: [model.tier ?? 'free'],
triggerContent: (
{model.name}
{model.tier === 'paid' &&
}
),
itemContent: (
{model.name}
),
}))}
/>
{selectedModel?.broken && (
)}
{selectedModel?.deprecated && (
{t('providerModelSelector.modelDeprecated')}
{selectedModel.deprecationReason && (
{selectedModel.deprecationReason}
)}
)}
{selectedModel?.description && !selectedModel.broken && !selectedModel.deprecated && (
{selectedModel.description}
)}
);
}
/** Model Mapping Selector - For Opus/Sonnet/Haiku mapping */
interface ModelMappingSelectorProps {
catalog: ProviderCatalog | undefined;
label: string;
value: string | undefined;
onChange: (model: string) => void;
disabled?: boolean;
}
export function ModelMappingSelector({
catalog,
label,
value,
onChange,
disabled,
}: ModelMappingSelectorProps) {
const { t } = useTranslation();
if (!catalog) return null;
return (
({
value: model.id,
searchText: `${model.name} ${model.id}`,
triggerContent: {model.id},
itemContent: (
{model.name}
{model.tier === 'paid' &&
}
),
}))}
/>
);
}
/** Flexible Model Selector - Combines catalog recommendations with full model list */
interface FlexibleModelSelectorProps {
label: string;
description?: string;
value: string | undefined;
onChange: (model: string) => void;
catalog?: ProviderCatalog;
allModels: { id: string; owned_by: string }[];
routing?: CliproxyProviderRoutingHints;
disabled?: boolean;
}
function normalizeModelValue(
value: string | undefined,
routing?: CliproxyProviderRoutingHints
): string {
if (!value) return '';
if (!routing?.prefix) return value;
const prefix = `${routing.prefix}/`;
return value.startsWith(prefix) ? value.slice(prefix.length) : value;
}
function getPreferredOptionValue(
modelId: string,
routingHint: CliproxyProviderRoutingHints['models'][number] | undefined
): string {
if (!routingHint?.pinnedAvailable) {
return modelId;
}
return routingHint.recommendedModelId;
}
export function FlexibleModelSelector({
label,
description,
value,
onChange,
catalog,
allModels,
routing,
disabled,
}: FlexibleModelSelectorProps) {
const { t } = useTranslation();
const isCodexProvider = catalog?.provider === 'codex';
const resolvedCatalogModels = useMemo(
() => getResolvedCatalogModels(catalog, allModels),
[allModels, catalog]
);
const catalogModelIds = new Set(resolvedCatalogModels.map((model) => model.id));
const routingHints = useMemo(
() =>
new Map((routing?.models ?? []).map((hint) => [hint.modelId.toLowerCase(), hint] as const)),
[routing]
);
const selectedRoutingHint = useMemo(
() => routingHints.get(normalizeModelValue(value, routing).toLowerCase()),
[routing, routingHints, value]
);
const recommendedOptions = resolvedCatalogModels.map((model) => ({
value: getPreferredOptionValue(model.id, routingHints.get(model.id.toLowerCase())),
groupKey: 'recommended',
searchText: `${model.id} ${model.name} ${routingHints.get(model.id.toLowerCase())?.recommendedModelId ?? ''}`,
keywords: [model.tier ?? '', catalog?.provider ?? ''],
triggerContent: (
{getPreferredOptionValue(model.id, routingHints.get(model.id.toLowerCase()))}
{routingHints.get(model.id.toLowerCase())?.pinnedAvailable ? (
{routingHints.get(model.id.toLowerCase())?.prefix}
) : null}
{isCodexProvider && }
),
itemContent: (
{getPreferredOptionValue(model.id, routingHints.get(model.id.toLowerCase()))}
{model.tier === 'paid' &&
}
{routingHints.get(model.id.toLowerCase())?.unprefixedStatus === 'shadowed' ? (
Shadowed
) : null}
{routingHints.get(model.id.toLowerCase())?.unprefixedStatus === 'prefix-only' ? (
Prefix only
) : null}
{isCodexProvider &&
}
),
}));
const allModelOptions = allModels
.filter((model) => !catalogModelIds.has(model.id))
.map((model) => ({
value: getPreferredOptionValue(model.id, routingHints.get(model.id.toLowerCase())),
groupKey: 'all',
searchText: `${model.id} ${routingHints.get(model.id.toLowerCase())?.recommendedModelId ?? ''}`,
keywords: [model.owned_by],
triggerContent: (
{getPreferredOptionValue(model.id, routingHints.get(model.id.toLowerCase()))}
{routingHints.get(model.id.toLowerCase())?.pinnedAvailable ? (
{routingHints.get(model.id.toLowerCase())?.prefix}
) : null}
{isCodexProvider && }
),
itemContent: (
{getPreferredOptionValue(model.id, routingHints.get(model.id.toLowerCase()))}
{routingHints.get(model.id.toLowerCase())?.unprefixedStatus === 'shadowed' ? (
Shadowed
) : null}
{routingHints.get(model.id.toLowerCase())?.unprefixedStatus === 'prefix-only' ? (
Prefix only
) : null}
{isCodexProvider && }
),
}));
const selectedValueMissing =
Boolean(value) &&
!recommendedOptions.some((option) => option.value === value) &&
!allModelOptions.some((option) => option.value === value);
const legacySelectedOption = value
? {
value,
groupKey: 'current',
searchText: value,
triggerContent: (
{value}
Current
),
itemContent: (
{value}
Current
),
}
: null;
const hasAvailableModels = recommendedOptions.length + allModelOptions.length > 0;
return (
{description &&
{description}
}
Current value,
},
]
: []),
{
key: 'recommended',
label: (
{t('providerModelSelector.recommended')}
),
},
{
key: 'all',
label: (
{t('providerModelSelector.allModelsCount', { count: allModels.length })}
),
},
]}
options={[
...(selectedValueMissing && legacySelectedOption ? [legacySelectedOption] : []),
...recommendedOptions,
...allModelOptions,
]}
/>
{selectedRoutingHint ? (
{selectedRoutingHint.pinnedAvailable
? 'Preferred pinned model:'
: 'Pinned route status:'}{' '}
{selectedRoutingHint.pinnedAvailable
? selectedRoutingHint.recommendedModelId
: selectedRoutingHint.pinnedModelId}
{selectedRoutingHint.summary}
) : null}
{value && !selectedRoutingHint && normalizeModelValue(value, routing) !== value ? (
Pinned model is not currently advertised by the proxy: {value}
) : null}
);
}