fix(cliproxy): respect user model settings in remote proxy mode

getRemoteEnvVars was ignoring user settings and always loading
models from base config. Now follows same priority as local mode:
1. Custom settings path (variant configs)
2. User settings file (~/.ccs/{provider}.settings.json)
3. Base config defaults

This fixes the issue where selecting Opus 4.5 in UI resulted in
Gemini 3 preview being loaded when using remote proxy mode.
This commit is contained in:
kaitranntt
2025-12-21 04:29:49 -05:00
parent d86dfab2e7
commit 4ee3100622
2 changed files with 70 additions and 25 deletions
+10 -6
View File
@@ -547,12 +547,16 @@ export async function execClaudeWithCLIProxy(
: undefined; : undefined;
const envVars = useRemoteProxy const envVars = useRemoteProxy
? getRemoteEnvVars(provider, { ? getRemoteEnvVars(
host: proxyConfig.host ?? 'localhost', provider,
port: proxyConfig.port, {
protocol: proxyConfig.protocol, host: proxyConfig.host ?? 'localhost',
authToken: proxyConfig.authToken, port: proxyConfig.port,
}) protocol: proxyConfig.protocol,
authToken: proxyConfig.authToken,
},
cfg.customSettingsPath
)
: getEffectiveEnvVars(provider, cfg.port, cfg.customSettingsPath, remoteRewriteConfig); : getEffectiveEnvVars(provider, cfg.port, cfg.customSettingsPath, remoteRewriteConfig);
const webSearchEnv = getWebSearchHookEnv(); const webSearchEnv = getWebSearchHookEnv();
const env = { const env = {
+60 -19
View File
@@ -540,48 +540,89 @@ export function ensureProviderSettings(provider: CLIProxyProvider): void {
/** /**
* Get environment variables for remote proxy mode. * Get environment variables for remote proxy mode.
* Uses the remote proxy's provider endpoint as the base URL. * Uses the remote proxy's provider endpoint as the base URL.
* Respects user model settings from custom settings path or provider settings file.
* *
* @param provider CLIProxy provider (gemini, codex, agy, qwen, iflow) * @param provider CLIProxy provider (gemini, codex, agy, qwen, iflow)
* @param remoteConfig Remote proxy connection details * @param remoteConfig Remote proxy connection details
* @param customSettingsPath Optional path to user's custom settings file
* @returns Environment variables for Claude CLI * @returns Environment variables for Claude CLI
*/ */
export function getRemoteEnvVars( export function getRemoteEnvVars(
provider: CLIProxyProvider, provider: CLIProxyProvider,
remoteConfig: { host: string; port?: number; protocol: 'http' | 'https'; authToken?: string } remoteConfig: { host: string; port?: number; protocol: 'http' | 'https'; authToken?: string },
customSettingsPath?: string
): Record<string, string> { ): Record<string, string> {
// Build URL with smart port handling - omit if using protocol default // Build URL with smart port handling - omit if using protocol default
const defaultPort = remoteConfig.protocol === 'https' ? 443 : 80; const defaultPort = remoteConfig.protocol === 'https' ? 443 : 80;
const effectivePort = remoteConfig.port ?? defaultPort; const effectivePort = remoteConfig.port ?? defaultPort;
const portSuffix = effectivePort === defaultPort ? '' : `:${effectivePort}`; const portSuffix = effectivePort === defaultPort ? '' : `:${effectivePort}`;
const baseUrl = `${remoteConfig.protocol}://${remoteConfig.host}${portSuffix}/api/provider/${provider}`; const baseUrl = `${remoteConfig.protocol}://${remoteConfig.host}${portSuffix}/api/provider/${provider}`;
const models = getModelMapping(provider);
// Get global env vars (DISABLE_TELEMETRY, etc.) // Get global env vars (DISABLE_TELEMETRY, etc.)
const globalEnv = getGlobalEnvVars(); const globalEnv = getGlobalEnvVars();
// Get additional env vars from base config (ANTHROPIC_MAX_TOKENS, etc.) // Load user settings with priority: custom path > user settings file > base config
const baseEnvVars = getEnvVarsFromConfig(provider); let userEnvVars: Record<string, string> = {};
// Filter out core env vars from base config to avoid conflicts // Priority 1: Custom settings path (for user-defined variants)
const { if (customSettingsPath) {
ANTHROPIC_BASE_URL: _baseUrl, const expandedPath = customSettingsPath.replace(/^~/, require('os').homedir());
ANTHROPIC_AUTH_TOKEN: _authToken, if (fs.existsSync(expandedPath)) {
ANTHROPIC_MODEL: _model, try {
ANTHROPIC_DEFAULT_OPUS_MODEL: _opusModel, const content = fs.readFileSync(expandedPath, 'utf-8');
ANTHROPIC_DEFAULT_SONNET_MODEL: _sonnetModel, const settings: ProviderSettings = JSON.parse(content);
ANTHROPIC_DEFAULT_HAIKU_MODEL: _haikuModel, if (settings.env && typeof settings.env === 'object') {
...additionalEnvVars userEnvVars = settings.env as Record<string, string>;
} = baseEnvVars; }
} catch {
// Invalid JSON - fall through to provider defaults
console.warn(warn(`Invalid settings file: ${customSettingsPath}`));
}
}
}
// Priority 2: Default provider settings file (~/.ccs/{provider}.settings.json)
if (Object.keys(userEnvVars).length === 0) {
const settingsPath = getProviderSettingsPath(provider);
if (fs.existsSync(settingsPath)) {
try {
const content = fs.readFileSync(settingsPath, 'utf-8');
const settings: ProviderSettings = JSON.parse(content);
if (settings.env && typeof settings.env === 'object') {
userEnvVars = settings.env as Record<string, string>;
}
} catch {
// Invalid JSON - fall through to base config
}
}
}
// Priority 3: Base config defaults
if (Object.keys(userEnvVars).length === 0) {
const models = getModelMapping(provider);
const baseEnvVars = getEnvVarsFromConfig(provider);
// Filter out URL/auth from base config (we'll set those from remote config)
const {
ANTHROPIC_BASE_URL: _baseUrl,
ANTHROPIC_AUTH_TOKEN: _authToken,
...additionalEnvVars
} = baseEnvVars;
userEnvVars = {
...additionalEnvVars,
ANTHROPIC_MODEL: models.claudeModel,
ANTHROPIC_DEFAULT_OPUS_MODEL: models.opusModel || models.claudeModel,
ANTHROPIC_DEFAULT_SONNET_MODEL: models.sonnetModel || models.claudeModel,
ANTHROPIC_DEFAULT_HAIKU_MODEL: models.haikuModel || models.claudeModel,
};
}
// Build final env: global + user settings + remote URL/auth override
const env: Record<string, string> = { const env: Record<string, string> = {
...globalEnv, ...globalEnv,
...additionalEnvVars, ...userEnvVars,
// Always override URL and auth token with remote config
ANTHROPIC_BASE_URL: baseUrl, ANTHROPIC_BASE_URL: baseUrl,
ANTHROPIC_AUTH_TOKEN: remoteConfig.authToken || CCS_INTERNAL_API_KEY, ANTHROPIC_AUTH_TOKEN: remoteConfig.authToken || CCS_INTERNAL_API_KEY,
ANTHROPIC_MODEL: models.claudeModel,
ANTHROPIC_DEFAULT_OPUS_MODEL: models.opusModel || models.claudeModel,
ANTHROPIC_DEFAULT_SONNET_MODEL: models.sonnetModel || models.claudeModel,
ANTHROPIC_DEFAULT_HAIKU_MODEL: models.haikuModel || models.claudeModel,
}; };
return env; return env;