mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-15 20:15:32 +00:00
feat: support minimal codex effort aliases
This commit is contained in:
1 parent
f0ad68d446
commit
6569eed15b
18 files changed
+204
-29
No files matched your search
@@ -228,9 +228,10 @@ export function ModelConfigSection({
|
||||
) : null}
|
||||
{provider === 'codex' && (
|
||||
<p className="text-[11px] text-muted-foreground mb-3 rounded-md border bg-muted/30 px-2.5 py-2">
|
||||
Codex tip: suffixes <code>-medium</code>, <code>-high</code>, and <code>-xhigh</code>{' '}
|
||||
pin reasoning effort. <code>-fast</code> enables the Codex fast service tier on models
|
||||
that support it, including combined forms such as <code>gpt-5.4-high-fast</code>.
|
||||
Codex tip: suffixes <code>-minimal</code>, <code>-low</code>, <code>-medium</code>,{' '}
|
||||
<code>-high</code>, and <code>-xhigh</code> pin reasoning effort. <code>-fast</code>{' '}
|
||||
enables the Codex fast service tier on models that support it, including combined forms
|
||||
such as <code>gpt-5.4-high-fast</code>.
|
||||
</p>
|
||||
)}
|
||||
<div className="space-y-4">
|
||||
|
||||
@@ -16,6 +16,7 @@ import type { CodexEffort, CodexServiceTier } from '@/lib/codex-effort';
|
||||
import {
|
||||
getCodexEffortDisplay,
|
||||
getCodexEffortVariants,
|
||||
parseCodexEffort,
|
||||
parseCodexServiceTier,
|
||||
} from '@/lib/codex-effort';
|
||||
import { getResolvedCatalogModels, getSupplementalCatalogModels } from '@/lib/model-catalogs';
|
||||
@@ -344,6 +345,13 @@ function getModelOptionValues(
|
||||
: [optionValue];
|
||||
}
|
||||
|
||||
function getRecommendedGroupKey(optionValue: string, isCodexProvider: boolean): string {
|
||||
if (!isCodexProvider) return 'recommended';
|
||||
if (parseCodexServiceTier(optionValue)) return 'codex-fast';
|
||||
if (parseCodexEffort(optionValue)) return 'codex-reasoning';
|
||||
return 'recommended';
|
||||
}
|
||||
|
||||
export function FlexibleModelSelector({
|
||||
label,
|
||||
description,
|
||||
@@ -400,7 +408,7 @@ export function FlexibleModelSelector({
|
||||
|
||||
return optionValues.map((optionValue) => ({
|
||||
value: optionValue,
|
||||
groupKey: 'recommended',
|
||||
groupKey: getRecommendedGroupKey(optionValue, isCodexProvider),
|
||||
searchText: `${optionValue} ${model.id} ${model.name} ${routingHint?.recommendedModelId ?? ''}`,
|
||||
keywords: [model.tier ?? '', catalog?.provider ?? ''],
|
||||
triggerContent: (
|
||||
@@ -555,6 +563,26 @@ export function FlexibleModelSelector({
|
||||
<span className="text-xs text-primary">{t('providerModelSelector.recommended')}</span>
|
||||
),
|
||||
},
|
||||
...(isCodexProvider
|
||||
? [
|
||||
{
|
||||
key: 'codex-reasoning',
|
||||
label: (
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{t('providerModelSelector.codexReasoningVariants')}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'codex-fast',
|
||||
label: (
|
||||
<span className="text-xs text-amber-600">
|
||||
{t('providerModelSelector.codexFastVariants')}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(allModelOptions.length > 0
|
||||
? [
|
||||
{
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
export type CodexEffort = 'medium' | 'high' | 'xhigh';
|
||||
export type CodexEffort = 'minimal' | 'low' | 'medium' | 'high' | 'xhigh';
|
||||
export type CodexServiceTier = 'fast';
|
||||
|
||||
const CODEX_TUNING_SUFFIX_TOKEN_REGEX = /-(medium|high|xhigh|fast)$/i;
|
||||
const CODEX_EFFORTS_IN_ORDER: readonly CodexEffort[] = ['medium', 'high', 'xhigh'];
|
||||
const CODEX_TUNING_SUFFIX_TOKEN_REGEX = /-(minimal|low|medium|high|xhigh|fast)$/i;
|
||||
const CODEX_EFFORTS_IN_ORDER: readonly CodexEffort[] = [
|
||||
'minimal',
|
||||
'low',
|
||||
'medium',
|
||||
'high',
|
||||
'xhigh',
|
||||
];
|
||||
|
||||
function trimModelId(modelId: string | undefined): string {
|
||||
return modelId?.trim() ?? '';
|
||||
|
||||
@@ -225,6 +225,8 @@ const resources = {
|
||||
pinnedRouteStatus: 'Pinned route status:',
|
||||
pinnedModelNotAdvertised:
|
||||
'Pinned model is not currently advertised by the proxy: {{model}}',
|
||||
codexReasoningVariants: 'Reasoning variants',
|
||||
codexFastVariants: 'Fast variants',
|
||||
},
|
||||
createAuthProfileDialog: {
|
||||
title: 'Create New Account',
|
||||
@@ -2929,6 +2931,8 @@ const resources = {
|
||||
preferredPinnedModel: '偏好的固定模型:',
|
||||
pinnedRouteStatus: '固定路由状态:',
|
||||
pinnedModelNotAdvertised: '固定模型当前未被代理广播:{{model}}',
|
||||
codexReasoningVariants: '推理变体',
|
||||
codexFastVariants: '快速变体',
|
||||
},
|
||||
createAuthProfileDialog: {
|
||||
title: '创建新账号',
|
||||
@@ -5517,6 +5521,8 @@ const resources = {
|
||||
preferredPinnedModel: 'Mô hình ghim ưu tiên:',
|
||||
pinnedRouteStatus: 'Trạng thái tuyến ghim:',
|
||||
pinnedModelNotAdvertised: 'Mô hình ghim hiện không được proxy quảng bá: {{model}}',
|
||||
codexReasoningVariants: 'Biến thể lý luận',
|
||||
codexFastVariants: 'Biến thể nhanh',
|
||||
},
|
||||
createAuthProfileDialog: {
|
||||
title: 'Tạo tài khoản mới',
|
||||
@@ -8220,6 +8226,8 @@ const resources = {
|
||||
preferredPinnedModel: '優先ピンモデル:',
|
||||
pinnedRouteStatus: 'ピンルートの状態:',
|
||||
pinnedModelNotAdvertised: 'ピンモデルは現在プロキシから通知されていません: {{model}}',
|
||||
codexReasoningVariants: '推論バリアント',
|
||||
codexFastVariants: '高速バリアント',
|
||||
},
|
||||
createAuthProfileDialog: {
|
||||
title: '新しいアカウントを作成',
|
||||
@@ -10946,6 +10954,8 @@ const resources = {
|
||||
preferredPinnedModel: '선호하는 고정 모델:',
|
||||
pinnedRouteStatus: '고정된 라우트 상태:',
|
||||
pinnedModelNotAdvertised: '고정된 모델이 현재 프록시에서 알리지 않고 있습니다: {{model}}',
|
||||
codexReasoningVariants: '추론 변형',
|
||||
codexFastVariants: '빠른 변형',
|
||||
},
|
||||
createAuthProfileDialog: {
|
||||
title: '새 계정 생성',
|
||||
|
||||
@@ -121,6 +121,10 @@ describe('FlexibleModelSelector', () => {
|
||||
|
||||
await userEvent.click(screen.getByRole('button', { name: /select model/i }));
|
||||
|
||||
expect(screen.getByText('Reasoning variants')).toBeInTheDocument();
|
||||
expect(screen.getByText('Fast variants')).toBeInTheDocument();
|
||||
expect(screen.getByText('gpt-5.5-minimal')).toBeInTheDocument();
|
||||
expect(screen.getByText('gpt-5.5-low')).toBeInTheDocument();
|
||||
expect(screen.getByText('gpt-5.3-codex-high')).toBeInTheDocument();
|
||||
expect(screen.getByText('gpt-5.3-codex-xhigh')).toBeInTheDocument();
|
||||
expect(screen.getByText('gpt-5.4-high-fast')).toBeInTheDocument();
|
||||
|
||||
@@ -15,6 +15,8 @@ describe('parseCodexEffort', () => {
|
||||
expect(parseCodexEffort('gpt-5.4-fast-high')).toBe('high');
|
||||
expect(parseCodexEffort('gpt-5.3-codex-xhigh')).toBe('xhigh');
|
||||
expect(parseCodexEffort('gpt-5-mini-medium')).toBe('medium');
|
||||
expect(parseCodexEffort('gpt-5.5-low')).toBe('low');
|
||||
expect(parseCodexEffort('gpt-5.5-minimal')).toBe('minimal');
|
||||
});
|
||||
|
||||
it('parses mixed-case suffixes', () => {
|
||||
@@ -23,7 +25,6 @@ describe('parseCodexEffort', () => {
|
||||
|
||||
it('returns undefined for unsuffixed or unsupported values', () => {
|
||||
expect(parseCodexEffort('gpt-5.3-codex')).toBeUndefined();
|
||||
expect(parseCodexEffort('gpt-5.3-codex-low')).toBeUndefined();
|
||||
expect(parseCodexEffort('gpt-5.4-fast')).toBeUndefined();
|
||||
expect(parseCodexEffort(undefined)).toBeUndefined();
|
||||
});
|
||||
@@ -69,12 +70,16 @@ describe('codex effort helpers', () => {
|
||||
it('builds ordered codex effort variants up to the supported max level', () => {
|
||||
expect(getCodexEffortVariants('gpt-5.3-codex', 'xhigh')).toEqual([
|
||||
'gpt-5.3-codex',
|
||||
'gpt-5.3-codex-minimal',
|
||||
'gpt-5.3-codex-low',
|
||||
'gpt-5.3-codex-medium',
|
||||
'gpt-5.3-codex-high',
|
||||
'gpt-5.3-codex-xhigh',
|
||||
]);
|
||||
expect(getCodexEffortVariants('gpt-5.4-mini', 'high')).toEqual([
|
||||
'gpt-5.4-mini',
|
||||
'gpt-5.4-mini-minimal',
|
||||
'gpt-5.4-mini-low',
|
||||
'gpt-5.4-mini-medium',
|
||||
'gpt-5.4-mini-high',
|
||||
]);
|
||||
@@ -84,6 +89,10 @@ describe('codex effort helpers', () => {
|
||||
expect(getCodexEffortVariants('gpt-5.4', 'high', ['fast'])).toEqual([
|
||||
'gpt-5.4',
|
||||
'gpt-5.4-fast',
|
||||
'gpt-5.4-minimal',
|
||||
'gpt-5.4-minimal-fast',
|
||||
'gpt-5.4-low',
|
||||
'gpt-5.4-low-fast',
|
||||
'gpt-5.4-medium',
|
||||
'gpt-5.4-medium-fast',
|
||||
'gpt-5.4-high',
|
||||
|
||||
Reference in new issue
Block a user