mirror of
https://github.com/tiennm99/ccs.git
synced 2026-09-02 16:19:27 +00:00
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:
@@ -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 = {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user