mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-20 02:17:05 +00:00
Merge pull request #924 from kaitranntt/kai/fix/codex-profile-raw-json-reset
fix(cliproxy): preserve saved codex model selections
This commit is contained in:
4 files changed
+10
-21
No files matched your search
@@ -59,7 +59,7 @@ All major modularization work is complete. The codebase evolved from monolithic
|
|||||||
- **2026-03-17**: Deprecated user-facing GLMT discovery across CLI help, completions, presets, and docs. Existing `glmt` profiles now run through a compatibility path that normalizes legacy proxy settings to the direct GLM endpoint.
|
- **2026-03-17**: Deprecated user-facing GLMT discovery across CLI help, completions, presets, and docs. Existing `glmt` profiles now run through a compatibility path that normalizes legacy proxy settings to the direct GLM endpoint.
|
||||||
- **#748**: API profile creation now keeps provider selection compact by collapsing advanced presets behind an explicit toggle, shrinking chooser cards so the form fields stay visually primary, and giving `llama.cpp` a dedicated provider logo.
|
- **#748**: API profile creation now keeps provider selection compact by collapsing advanced presets behind an explicit toggle, shrinking chooser cards so the form fields stay visually primary, and giving `llama.cpp` a dedicated provider logo.
|
||||||
- **#744**: API profile creation now keeps featured providers in a horizontal rail with scroll fallback, moves Anthropic Direct API to the end, reuses the shared Claude logo, and separates the custom-endpoint entry point from advanced template discovery.
|
- **#744**: API profile creation now keeps featured providers in a horizontal rail with scroll fallback, moves Anthropic Direct API to the end, reuses the shared Claude logo, and separates the custom-endpoint entry point from advanced template discovery.
|
||||||
- **#724**: Codex startup is now free-plan safe. CCS defaults new Codex sessions to a cross-plan model and auto-repairs stale paid-only Codex defaults when the active account is on the free plan.
|
- **#724**: Codex startup is now free-plan safe. CCS defaults new Codex sessions to a cross-plan model and uses runtime fallback handling for unsupported paid-only models without rewriting the saved dashboard settings.
|
||||||
- **#737**: Dashboard model pickers in Cursor, Copilot, and CLIProxy now use a searchable combobox with autofocus and explicit no-results states for large model catalogs.
|
- **#737**: Dashboard model pickers in Cursor, Copilot, and CLIProxy now use a searchable combobox with autofocus and explicit no-results states for large model catalogs.
|
||||||
- **#736**: `ccs config` now supports explicit dashboard bind hosts via `--host`, and surfaces remote-access warnings plus reachable URLs when the effective bind is non-loopback.
|
- **#736**: `ccs config` now supports explicit dashboard bind hosts via `--host`, and surfaces remote-access warnings plus reachable URLs when the effective bind is non-loopback.
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { getProviderCatalog } from './model-catalog';
|
|||||||
import { fetchCodexQuota } from './quota-fetcher-codex';
|
import { fetchCodexQuota } from './quota-fetcher-codex';
|
||||||
import { getCachedQuota, setCachedQuota } from './quota-response-cache';
|
import { getCachedQuota, setCachedQuota } from './quota-response-cache';
|
||||||
import type { CodexQuotaResult } from './quota-types';
|
import type { CodexQuotaResult } from './quota-types';
|
||||||
import { updateSettingsModel } from './services/variant-settings';
|
|
||||||
import { info, warn } from '../utils/ui';
|
import { info, warn } from '../utils/ui';
|
||||||
|
|
||||||
export type CodexPlanType = CodexQuotaResult['planType'];
|
export type CodexPlanType = CodexQuotaResult['planType'];
|
||||||
@@ -140,13 +139,12 @@ export function resolveRuntimeCodexFallbackModel(options: {
|
|||||||
|
|
||||||
export async function reconcileCodexModelForActivePlan(
|
export async function reconcileCodexModelForActivePlan(
|
||||||
options: {
|
options: {
|
||||||
settingsPath: string;
|
|
||||||
currentModel: string | undefined;
|
currentModel: string | undefined;
|
||||||
verbose: boolean;
|
verbose: boolean;
|
||||||
},
|
},
|
||||||
deps: CodexPlanCompatibilityDeps = {}
|
deps: CodexPlanCompatibilityDeps = {}
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const { settingsPath, currentModel, verbose } = options;
|
const { currentModel, verbose } = options;
|
||||||
if (!currentModel) return;
|
if (!currentModel) return;
|
||||||
|
|
||||||
const fallbackModel = getFreePlanFallbackCodexModel(currentModel);
|
const fallbackModel = getFreePlanFallbackCodexModel(currentModel);
|
||||||
@@ -175,13 +173,10 @@ export async function reconcileCodexModelForActivePlan(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (quota.planType === 'free') {
|
if (quota.planType === 'free') {
|
||||||
updateSettingsModel(settingsPath, fallbackModel, 'codex', {
|
|
||||||
rewriteHaikuModel: (haikuModel) => getFreePlanFallbackCodexModel(haikuModel) ?? haikuModel,
|
|
||||||
});
|
|
||||||
console.error(
|
console.error(
|
||||||
formatInfo(
|
formatInfo(
|
||||||
`Codex free plan detected. Switched unsupported model "${normalizeCodexModelId(currentModel)}" ` +
|
`Codex free plan detected. Keeping saved model "${normalizeCodexModelId(currentModel)}" in settings; ` +
|
||||||
`to "${fallbackModel}".`
|
`runtime requests will fall back to "${fallbackModel}" when needed.`
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -883,7 +883,6 @@ export async function execClaudeWithCLIProxy(
|
|||||||
|
|
||||||
if (provider === 'codex' && !cfg.isComposite && !skipLocalAuth) {
|
if (provider === 'codex' && !cfg.isComposite && !skipLocalAuth) {
|
||||||
await reconcileCodexModelForActivePlan({
|
await reconcileCodexModelForActivePlan({
|
||||||
settingsPath: cfg.customSettingsPath || getProviderSettingsPath(provider),
|
|
||||||
currentModel: getCurrentModel(provider, cfg.customSettingsPath),
|
currentModel: getCurrentModel(provider, cfg.customSettingsPath),
|
||||||
verbose,
|
verbose,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ async function importCompatibilityModule(cacheTag: string) {
|
|||||||
const identity = (message: string) => message;
|
const identity = (message: string) => message;
|
||||||
|
|
||||||
describe('codex plan compatibility reconcile', () => {
|
describe('codex plan compatibility reconcile', () => {
|
||||||
it('repairs stale paid-only Codex settings for free-plan accounts before launch', async () => {
|
it('keeps saved Codex settings intact and warns about runtime fallback for free-plan accounts', async () => {
|
||||||
const { tmpDir, settingsPath } = createCodexSettingsFixture('gpt-5.3-codex-spark');
|
const { tmpDir, settingsPath } = createCodexSettingsFixture('gpt-5.3-codex-spark');
|
||||||
const errorSpy = spyOn(console, 'error').mockImplementation(() => {});
|
const errorSpy = spyOn(console, 'error').mockImplementation(() => {});
|
||||||
|
|
||||||
@@ -54,7 +54,6 @@ describe('codex plan compatibility reconcile', () => {
|
|||||||
|
|
||||||
await reconcileCodexModelForActivePlan(
|
await reconcileCodexModelForActivePlan(
|
||||||
{
|
{
|
||||||
settingsPath,
|
|
||||||
currentModel: 'gpt-5.3-codex',
|
currentModel: 'gpt-5.3-codex',
|
||||||
verbose: false,
|
verbose: false,
|
||||||
},
|
},
|
||||||
@@ -76,12 +75,12 @@ describe('codex plan compatibility reconcile', () => {
|
|||||||
const repaired = JSON.parse(fs.readFileSync(settingsPath, 'utf-8')) as {
|
const repaired = JSON.parse(fs.readFileSync(settingsPath, 'utf-8')) as {
|
||||||
env: Record<string, string>;
|
env: Record<string, string>;
|
||||||
};
|
};
|
||||||
expect(repaired.env.ANTHROPIC_MODEL).toBe('gpt-5-codex');
|
expect(repaired.env.ANTHROPIC_MODEL).toBe('gpt-5.3-codex');
|
||||||
expect(repaired.env.ANTHROPIC_DEFAULT_OPUS_MODEL).toBe('gpt-5-codex');
|
expect(repaired.env.ANTHROPIC_DEFAULT_OPUS_MODEL).toBe('gpt-5.3-codex');
|
||||||
expect(repaired.env.ANTHROPIC_DEFAULT_SONNET_MODEL).toBe('gpt-5-codex');
|
expect(repaired.env.ANTHROPIC_DEFAULT_SONNET_MODEL).toBe('gpt-5.3-codex');
|
||||||
expect(repaired.env.ANTHROPIC_DEFAULT_HAIKU_MODEL).toBe('gpt-5-codex-mini');
|
expect(repaired.env.ANTHROPIC_DEFAULT_HAIKU_MODEL).toBe('gpt-5.3-codex-spark');
|
||||||
expect(errorSpy).toHaveBeenCalledWith(
|
expect(errorSpy).toHaveBeenCalledWith(
|
||||||
'Codex free plan detected. Switched unsupported model "gpt-5.3-codex" to "gpt-5-codex".'
|
'Codex free plan detected. Keeping saved model "gpt-5.3-codex" in settings; runtime requests will fall back to "gpt-5-codex" when needed.'
|
||||||
);
|
);
|
||||||
} finally {
|
} finally {
|
||||||
fs.rmSync(tmpDir, { recursive: true, force: true });
|
fs.rmSync(tmpDir, { recursive: true, force: true });
|
||||||
@@ -98,7 +97,6 @@ describe('codex plan compatibility reconcile', () => {
|
|||||||
|
|
||||||
await reconcileCodexModelForActivePlan(
|
await reconcileCodexModelForActivePlan(
|
||||||
{
|
{
|
||||||
settingsPath,
|
|
||||||
currentModel: 'gpt-5.3-codex',
|
currentModel: 'gpt-5.3-codex',
|
||||||
verbose: false,
|
verbose: false,
|
||||||
},
|
},
|
||||||
@@ -134,7 +132,6 @@ describe('codex plan compatibility reconcile', () => {
|
|||||||
|
|
||||||
await reconcileCodexModelForActivePlan(
|
await reconcileCodexModelForActivePlan(
|
||||||
{
|
{
|
||||||
settingsPath,
|
|
||||||
currentModel: 'gpt-5.3-codex',
|
currentModel: 'gpt-5.3-codex',
|
||||||
verbose: false,
|
verbose: false,
|
||||||
},
|
},
|
||||||
@@ -174,7 +171,6 @@ describe('codex plan compatibility reconcile', () => {
|
|||||||
|
|
||||||
await reconcileCodexModelForActivePlan(
|
await reconcileCodexModelForActivePlan(
|
||||||
{
|
{
|
||||||
settingsPath,
|
|
||||||
currentModel: 'gpt-5.3-codex',
|
currentModel: 'gpt-5.3-codex',
|
||||||
verbose: false,
|
verbose: false,
|
||||||
},
|
},
|
||||||
@@ -216,7 +212,6 @@ describe('codex plan compatibility reconcile', () => {
|
|||||||
|
|
||||||
await reconcileCodexModelForActivePlan(
|
await reconcileCodexModelForActivePlan(
|
||||||
{
|
{
|
||||||
settingsPath,
|
|
||||||
currentModel: 'gpt-5.3-codex',
|
currentModel: 'gpt-5.3-codex',
|
||||||
verbose: false,
|
verbose: false,
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in new issue
Block a user