fix(cliproxy): address 4 functional regressions in composite variants

- P1: Remote composite env now uses remote endpoint/auth
  Add CompositeRemoteConfig parameter to getCompositeEnvVars()
  Pass remote config when useRemoteProxy is true

- P2: Tier thinking uses tier-specific provider
  Extract tier provider from compositeTiers for supportsThinking()
  Fix mixed-provider composite thinking config

- P2: Force variant removal checks result
  Fail fast if removeVariant fails in --force mode

- P2: Guard composite validation against missing tiers
  Add null check before Object.entries(variant.tiers)
This commit is contained in:
Tam Nhu Tran committed 2026-02-12 12:08:20 +07:00
1 parent a99180fa22
commit 27d22e836f
5 files changed
+80 -12

No files matched your search

+28 -4
View File
@@ -415,6 +415,14 @@ export function getRemoteEnvVars(
return env;
}
/** Remote config for composite variant (passed from env-resolver) */
export interface CompositeRemoteConfig {
host: string;
port: number;
protocol: 'http' | 'https';
authToken?: string;
}
/**
* Get environment variables for composite variant.
* Uses root URL (no /api/provider/ path) for model-based routing.
@@ -422,14 +430,16 @@ export function getRemoteEnvVars(
*
* @param tiers Per-tier provider+model mappings
* @param defaultTier Which tier ANTHROPIC_MODEL equals
* @param port Local CLIProxy port
* @param port Local CLIProxy port (ignored if remoteConfig provided)
* @param customSettingsPath Optional path to user's custom settings file
* @param remoteConfig Optional remote proxy config (overrides localhost URL/auth)
*/
export function getCompositeEnvVars(
tiers: { opus: CompositeTierConfig; sonnet: CompositeTierConfig; haiku: CompositeTierConfig },
defaultTier: 'opus' | 'sonnet' | 'haiku',
port: number = CLIPROXY_DEFAULT_PORT,
customSettingsPath?: string
customSettingsPath?: string,
remoteConfig?: CompositeRemoteConfig
): Record<string, string> {
const globalEnv = getGlobalEnvVars();
@@ -473,12 +483,26 @@ export function getCompositeEnvVars(
throw new Error(`Missing model for default tier '${defaultTier}'`);
}
// Determine base URL and auth token based on remote vs local mode
const baseUrl = remoteConfig
? (() => {
const normalizedProtocol = normalizeProtocol(remoteConfig.protocol);
const effectivePort =
validateRemotePort(remoteConfig.port) ?? getRemoteDefaultPort(normalizedProtocol);
const standardWebPort = normalizedProtocol === 'https' ? 443 : 80;
const portSuffix = effectivePort === standardWebPort ? '' : `:${effectivePort}`;
return `${normalizedProtocol}://${remoteConfig.host}${portSuffix}`;
})()
: `http://127.0.0.1:${validPort}`;
const authToken = remoteConfig?.authToken ?? getEffectiveApiKey();
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_BASE_URL: baseUrl,
ANTHROPIC_AUTH_TOKEN: authToken,
ANTHROPIC_MODEL: defaultModel,
};