mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-17 04:17:11 +00:00
fix(cliproxy): add defensive null checks for composite tier config
- Add optional chaining for tier access in env-resolver - Throw error if default tier model missing in env-builder - Add null checks for composite.tiers in profile-detector
This commit is contained in:
@@ -130,10 +130,27 @@ class ProfileDetector {
|
||||
// Handle composite variants
|
||||
if ('type' in variant && variant.type === 'composite') {
|
||||
const composite = variant as CompositeVariantConfig;
|
||||
|
||||
// Defensive: check for missing tiers or default_tier
|
||||
if (!composite.tiers || !composite.default_tier) {
|
||||
console.warn(
|
||||
`[!] Warning: Composite variant '${profileName}' has missing tiers or default_tier`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
const defaultTierConfig = composite.tiers[composite.default_tier];
|
||||
if (!defaultTierConfig) {
|
||||
console.warn(
|
||||
`[!] Warning: Composite variant '${profileName}' missing config for default tier '${composite.default_tier}'`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'cliproxy',
|
||||
name: profileName,
|
||||
provider: composite.tiers[composite.default_tier].provider as CLIProxyProfileName,
|
||||
provider: defaultTierConfig.provider as CLIProxyProfileName,
|
||||
settingsPath: composite.settings,
|
||||
port: composite.port,
|
||||
isComposite: true,
|
||||
|
||||
@@ -461,17 +461,31 @@ export function getCompositeEnvVars(
|
||||
}
|
||||
|
||||
const validPort = validatePort(port);
|
||||
const defaultModel = tiers[defaultTier].model;
|
||||
|
||||
return {
|
||||
// Defensive: handle missing tiers gracefully
|
||||
const opusModel = tiers.opus?.model;
|
||||
const sonnetModel = tiers.sonnet?.model;
|
||||
const haikuModel = tiers.haiku?.model;
|
||||
const defaultModel = tiers[defaultTier]?.model;
|
||||
|
||||
// If default tier is missing, we cannot proceed meaningfully
|
||||
if (!defaultModel) {
|
||||
throw new Error(`Missing model for default tier '${defaultTier}'`);
|
||||
}
|
||||
|
||||
const env: Record<string, string> = {
|
||||
...globalEnv,
|
||||
...additionalEnvVars,
|
||||
// Root URL — CLIProxyAPI routes based on model name in request body
|
||||
ANTHROPIC_BASE_URL: `http://127.0.0.1:${validPort}`,
|
||||
ANTHROPIC_AUTH_TOKEN: getEffectiveApiKey(),
|
||||
ANTHROPIC_MODEL: defaultModel,
|
||||
ANTHROPIC_DEFAULT_OPUS_MODEL: tiers.opus.model,
|
||||
ANTHROPIC_DEFAULT_SONNET_MODEL: tiers.sonnet.model,
|
||||
ANTHROPIC_DEFAULT_HAIKU_MODEL: tiers.haiku.model,
|
||||
};
|
||||
|
||||
// Only set tier env vars if the tier exists
|
||||
if (opusModel) env.ANTHROPIC_DEFAULT_OPUS_MODEL = opusModel;
|
||||
if (sonnetModel) env.ANTHROPIC_DEFAULT_SONNET_MODEL = sonnetModel;
|
||||
if (haikuModel) env.ANTHROPIC_DEFAULT_HAIKU_MODEL = haikuModel;
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
@@ -136,9 +136,9 @@ export function buildClaudeEnvironment(config: ProxyChainConfig): Record<string,
|
||||
let compositeTierThinking: { opus?: string; sonnet?: string; haiku?: string } | undefined;
|
||||
if (isComposite && compositeTiers) {
|
||||
const tierThinking: { opus?: string; sonnet?: string; haiku?: string } = {};
|
||||
if (compositeTiers.opus.thinking) tierThinking.opus = compositeTiers.opus.thinking;
|
||||
if (compositeTiers.sonnet.thinking) tierThinking.sonnet = compositeTiers.sonnet.thinking;
|
||||
if (compositeTiers.haiku.thinking) tierThinking.haiku = compositeTiers.haiku.thinking;
|
||||
if (compositeTiers.opus?.thinking) tierThinking.opus = compositeTiers.opus.thinking;
|
||||
if (compositeTiers.sonnet?.thinking) tierThinking.sonnet = compositeTiers.sonnet.thinking;
|
||||
if (compositeTiers.haiku?.thinking) tierThinking.haiku = compositeTiers.haiku.thinking;
|
||||
if (Object.keys(tierThinking).length > 0) {
|
||||
compositeTierThinking = tierThinking;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user