feat(cliproxy): add per-tier thinking config for composite variants

- Extend applyThinkingConfig() with compositeTierThinking parameter
- Priority chain: CLI --thinking > per-tier config > global config > defaults
- thinking: 'off' skips suffix for that tier
- Wire compositeTierThinking extraction in buildClaudeEnvironment()
- Add applyFallback() helper for tier-level env var modification
This commit is contained in:
Tam Nhu Tran
2026-02-12 04:24:50 +07:00
parent 478e9e8f73
commit ed22c1aa1e
2 changed files with 70 additions and 5 deletions
+36 -4
View File
@@ -74,12 +74,18 @@ export function getThinkingValueForTier(
* @param envVars - Environment variables to modify
* @param provider - CLIProxy provider
* @param thinkingOverride - Optional CLI override (takes priority over config)
* @param compositeTierThinking - Optional per-tier thinking overrides for composite variants
* @returns Modified env vars with thinking suffixes applied
*/
export function applyThinkingConfig(
envVars: NodeJS.ProcessEnv,
provider: CLIProxyProvider,
thinkingOverride?: string | number
thinkingOverride?: string | number,
compositeTierThinking?: {
opus?: string;
sonnet?: string;
haiku?: string;
}
): NodeJS.ProcessEnv {
const thinkingConfig = getThinkingConfig();
const result = { ...envVars };
@@ -115,7 +121,13 @@ export function applyThinkingConfig(
} else if (thinkingConfig.mode === 'auto') {
// Auto mode: detect tier and apply default
const tier = detectTierFromModel(baseModel);
thinkingValue = getThinkingValueForTier(tier, provider, thinkingConfig);
// Check per-tier config first if composite
const perTierValue = compositeTierThinking?.[tier];
if (perTierValue !== undefined) {
thinkingValue = perTierValue;
} else {
thinkingValue = getThinkingValueForTier(tier, provider, thinkingConfig);
}
} else {
return result; // No thinking to apply
}
@@ -153,8 +165,28 @@ export function applyThinkingConfig(
: tierVar.includes('SONNET')
? 'sonnet'
: 'haiku';
const tierThinkingValue =
thinkingOverride ?? getThinkingValueForTier(tier, provider, thinkingConfig);
// Priority chain: CLI --thinking > per-tier config > global config > defaults
let tierThinkingValue: string | number;
if (thinkingOverride !== undefined) {
// CLI override takes priority
tierThinkingValue = thinkingOverride;
} else {
const perTierValue = compositeTierThinking?.[tier];
if (perTierValue !== undefined) {
// Per-tier config from composite variant
tierThinkingValue = perTierValue;
} else {
// Global config or defaults
tierThinkingValue = getThinkingValueForTier(tier, provider, thinkingConfig);
}
}
// If per-tier thinking is 'off', skip this tier
if (tierThinkingValue === 'off') {
continue;
}
result[tierVar] = applyThinkingSuffix(model, tierThinkingValue);
}
}
+34 -1
View File
@@ -132,8 +132,20 @@ export function buildClaudeEnvironment(config: ProxyChainConfig): Record<string,
envVars = getEffectiveEnvVars(provider, localPort, customSettingsPath, remoteRewriteConfig);
}
// Extract per-tier thinking from composite config
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 (Object.keys(tierThinking).length > 0) {
compositeTierThinking = tierThinking;
}
}
// Apply thinking configuration to model (auto tier-based or manual override)
applyThinkingConfig(envVars, provider, thinkingOverride);
applyThinkingConfig(envVars, provider, thinkingOverride, compositeTierThinking);
// Apply extended context suffix for 1M token context window
// Auto-enabled for Gemini, opt-in for Claude (--1m flag)
@@ -203,3 +215,24 @@ export function logEnvironment(
log(`Claude env: Global env applied (telemetry/reporting disabled)`);
}
}
/** Apply fallback provider config to env vars for a failed tier */
export function applyFallback(
env: Record<string, string>,
failedTier: 'opus' | 'sonnet' | 'haiku',
fallback: { provider: string; model: string }
): Record<string, string> {
const tierEnvMap = {
opus: 'ANTHROPIC_DEFAULT_OPUS_MODEL',
sonnet: 'ANTHROPIC_DEFAULT_SONNET_MODEL',
haiku: 'ANTHROPIC_DEFAULT_HAIKU_MODEL',
} as const;
const result = { ...env };
const originalModel = result[tierEnvMap[failedTier]];
result[tierEnvMap[failedTier]] = fallback.model;
// If failed tier is default tier, also update ANTHROPIC_MODEL
if (result.ANTHROPIC_MODEL === originalModel) {
result.ANTHROPIC_MODEL = fallback.model;
}
return result;
}