mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-13 08:15:17 +00:00
feat(cliproxy): add warning for broken claude proxy models on agy
- add broken flag to model catalog for models with known issues - display [BROKEN] badge in model selection and config display - show warning message when starting with a broken model - link to tracking issue: CLIProxyAPI#415 Claude proxy models (gemini-claude-*) currently fail with tool calls due to upstream CLIProxyAPI bug. Warning helps users know to switch to gemini-3-pro-preview until fixed.
This commit is contained in:
1 parent
43e45c157c
commit
0e11426daa
3 files changed
+50
-5
No files matched your search
@@ -26,8 +26,8 @@ import {
|
|||||||
} from './config-generator';
|
} from './config-generator';
|
||||||
import { isAuthenticated } from './auth-handler';
|
import { isAuthenticated } from './auth-handler';
|
||||||
import { CLIProxyProvider, ExecutorConfig } from './types';
|
import { CLIProxyProvider, ExecutorConfig } from './types';
|
||||||
import { configureProviderModel } from './model-config';
|
import { configureProviderModel, getCurrentModel } from './model-config';
|
||||||
import { supportsModelConfig } from './model-catalog';
|
import { supportsModelConfig, isModelBroken, getModelIssueUrl, findModel } from './model-catalog';
|
||||||
|
|
||||||
/** Default executor configuration */
|
/** Default executor configuration */
|
||||||
const DEFAULT_CONFIG: ExecutorConfig = {
|
const DEFAULT_CONFIG: ExecutorConfig = {
|
||||||
@@ -170,7 +170,24 @@ export async function execClaudeWithCLIProxy(
|
|||||||
await configureProviderModel(provider, false); // false = only if not configured
|
await configureProviderModel(provider, false); // false = only if not configured
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. Ensure user settings file exists (creates from defaults if not)
|
// 5. Check for known broken models and warn user
|
||||||
|
const currentModel = getCurrentModel(provider);
|
||||||
|
if (currentModel && isModelBroken(provider, currentModel)) {
|
||||||
|
const modelEntry = findModel(provider, currentModel);
|
||||||
|
const issueUrl = getModelIssueUrl(provider, currentModel);
|
||||||
|
console.error('');
|
||||||
|
console.error(
|
||||||
|
`[!] Warning: ${modelEntry?.name || currentModel} has known issues with Claude Code`
|
||||||
|
);
|
||||||
|
console.error(' Tool calls will fail. Use "gemini-3-pro-preview" instead.');
|
||||||
|
if (issueUrl) {
|
||||||
|
console.error(` Tracking: ${issueUrl}`);
|
||||||
|
}
|
||||||
|
console.error(` Run "ccs ${provider} --config" to change model.`);
|
||||||
|
console.error('');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. Ensure user settings file exists (creates from defaults if not)
|
||||||
ensureProviderSettings(provider);
|
ensureProviderSettings(provider);
|
||||||
|
|
||||||
// 6. Generate config file
|
// 6. Generate config file
|
||||||
|
|||||||
@@ -19,6 +19,10 @@ export interface ModelEntry {
|
|||||||
tier?: 'free' | 'paid';
|
tier?: 'free' | 'paid';
|
||||||
/** Optional description for the model */
|
/** Optional description for the model */
|
||||||
description?: string;
|
description?: string;
|
||||||
|
/** Model has known issues - show warning when selected */
|
||||||
|
broken?: boolean;
|
||||||
|
/** Issue URL for broken models */
|
||||||
|
issueUrl?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -46,16 +50,22 @@ export const MODEL_CATALOG: Partial<Record<CLIProxyProvider, ProviderCatalog>> =
|
|||||||
id: 'gemini-claude-opus-4-5-thinking',
|
id: 'gemini-claude-opus-4-5-thinking',
|
||||||
name: 'Claude Opus 4.5 Thinking',
|
name: 'Claude Opus 4.5 Thinking',
|
||||||
description: 'Most capable, extended thinking',
|
description: 'Most capable, extended thinking',
|
||||||
|
broken: true,
|
||||||
|
issueUrl: 'https://github.com/router-for-me/CLIProxyAPI/issues/415',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'gemini-claude-sonnet-4-5-thinking',
|
id: 'gemini-claude-sonnet-4-5-thinking',
|
||||||
name: 'Claude Sonnet 4.5 Thinking',
|
name: 'Claude Sonnet 4.5 Thinking',
|
||||||
description: 'Balanced with extended thinking',
|
description: 'Balanced with extended thinking',
|
||||||
|
broken: true,
|
||||||
|
issueUrl: 'https://github.com/router-for-me/CLIProxyAPI/issues/415',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'gemini-claude-sonnet-4-5',
|
id: 'gemini-claude-sonnet-4-5',
|
||||||
name: 'Claude Sonnet 4.5',
|
name: 'Claude Sonnet 4.5',
|
||||||
description: 'Fast and capable',
|
description: 'Fast and capable',
|
||||||
|
broken: true,
|
||||||
|
issueUrl: 'https://github.com/router-for-me/CLIProxyAPI/issues/415',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'gemini-3-pro-preview',
|
id: 'gemini-3-pro-preview',
|
||||||
@@ -107,3 +117,19 @@ export function findModel(provider: CLIProxyProvider, modelId: string): ModelEnt
|
|||||||
if (!catalog) return undefined;
|
if (!catalog) return undefined;
|
||||||
return catalog.models.find((m) => m.id === modelId);
|
return catalog.models.find((m) => m.id === modelId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if model has known issues
|
||||||
|
*/
|
||||||
|
export function isModelBroken(provider: CLIProxyProvider, modelId: string): boolean {
|
||||||
|
const model = findModel(provider, modelId);
|
||||||
|
return model?.broken === true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get issue URL for broken model
|
||||||
|
*/
|
||||||
|
export function getModelIssueUrl(provider: CLIProxyProvider, modelId: string): string | undefined {
|
||||||
|
const model = findModel(provider, modelId);
|
||||||
|
return model?.issueUrl;
|
||||||
|
}
|
||||||
@@ -45,7 +45,8 @@ export function getCurrentModel(provider: CLIProxyProvider): string | undefined
|
|||||||
function formatModelOption(model: ModelEntry): string {
|
function formatModelOption(model: ModelEntry): string {
|
||||||
// Tier badge: clarify that "paid" means paid Google account (not free tier)
|
// Tier badge: clarify that "paid" means paid Google account (not free tier)
|
||||||
const tierBadge = model.tier === 'paid' ? color(' [Paid Tier]', 'warning') : '';
|
const tierBadge = model.tier === 'paid' ? color(' [Paid Tier]', 'warning') : '';
|
||||||
return `${model.name}${tierBadge}`;
|
const brokenBadge = model.broken ? color(' [BROKEN]', 'error') : '';
|
||||||
|
return `${model.name}${tierBadge}${brokenBadge}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -55,8 +56,9 @@ function formatModelDetailed(model: ModelEntry, isCurrent: boolean): string {
|
|||||||
const marker = isCurrent ? color('>', 'success') : ' ';
|
const marker = isCurrent ? color('>', 'success') : ' ';
|
||||||
const name = isCurrent ? bold(model.name) : model.name;
|
const name = isCurrent ? bold(model.name) : model.name;
|
||||||
const tierBadge = model.tier === 'paid' ? color(' [Paid Tier]', 'warning') : '';
|
const tierBadge = model.tier === 'paid' ? color(' [Paid Tier]', 'warning') : '';
|
||||||
|
const brokenBadge = model.broken ? color(' [BROKEN]', 'error') : '';
|
||||||
const desc = model.description ? dim(` - ${model.description}`) : '';
|
const desc = model.description ? dim(` - ${model.description}`) : '';
|
||||||
return ` ${marker} ${name}${tierBadge}${desc}`;
|
return ` ${marker} ${name}${tierBadge}${brokenBadge}${desc}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in new issue
Block a user