refactor: update authentication handling and model configuration

- Enhanced authentication method validation in `auth.ts` and `auth.test.ts`.
- Introduced new model provider configuration logic
- Updated environment variable handling for various auth types.
- Removed deprecated utility functions and tests related to fallback mechanisms.
This commit is contained in:
mingholy.lmh 2026-01-06 15:36:44 +08:00
parent aa9cdf2a3c
commit db12796df5
53 changed files with 5183 additions and 942 deletions

View file

@ -0,0 +1,112 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import {
AuthType,
type ContentGeneratorConfig,
type ContentGeneratorConfigSources,
resolveModelConfig,
type ModelConfigSourcesInput,
} from '@qwen-code/qwen-code-core';
import type { Settings } from '../config/settings.js';
export interface CliGenerationConfigInputs {
argv: {
model?: string | undefined;
openaiApiKey?: string | undefined;
openaiBaseUrl?: string | undefined;
openaiLogging?: boolean | undefined;
openaiLoggingDir?: string | undefined;
};
settings: Settings;
selectedAuthType: AuthType | undefined;
/**
* Injectable env for testability. Defaults to process.env at callsites.
*/
env?: Record<string, string | undefined>;
}
export interface ResolvedCliGenerationConfig {
/** The resolved model id (may be empty string if not resolvable at CLI layer) */
model: string;
/** API key for OpenAI-compatible auth */
apiKey: string;
/** Base URL for OpenAI-compatible auth */
baseUrl: string;
/** The full generation config to pass to core Config */
generationConfig: Partial<ContentGeneratorConfig>;
/** Source attribution for each resolved field */
sources: ContentGeneratorConfigSources;
}
/**
* Unified resolver for CLI generation config.
*
* Precedence (for OpenAI auth):
* - model: argv.model > OPENAI_MODEL > QWEN_MODEL > settings.model.name
* - apiKey: argv.openaiApiKey > OPENAI_API_KEY > settings.security.auth.apiKey
* - baseUrl: argv.openaiBaseUrl > OPENAI_BASE_URL > settings.security.auth.baseUrl
*
* For non-OpenAI auth, only argv.model override is respected at CLI layer.
*/
export function resolveCliGenerationConfig(
inputs: CliGenerationConfigInputs,
): ResolvedCliGenerationConfig {
const { argv, settings, selectedAuthType } = inputs;
const env = inputs.env ?? (process.env as Record<string, string | undefined>);
const authType = selectedAuthType ?? AuthType.QWEN_OAUTH;
const configSources: ModelConfigSourcesInput = {
authType,
cli: {
model: argv.model,
apiKey: argv.openaiApiKey,
baseUrl: argv.openaiBaseUrl,
},
settings: {
model: settings.model?.name,
apiKey: settings.security?.auth?.apiKey,
baseUrl: settings.security?.auth?.baseUrl,
generationConfig: settings.model?.generationConfig as
| Partial<ContentGeneratorConfig>
| undefined,
},
env,
};
const resolved = resolveModelConfig(configSources);
// Log warnings if any
for (const warning of resolved.warnings) {
console.warn(`[modelProviderUtils] ${warning}`);
}
// Resolve OpenAI logging config (CLI-specific, not part of core resolver)
const enableOpenAILogging =
(typeof argv.openaiLogging === 'undefined'
? settings.model?.enableOpenAILogging
: argv.openaiLogging) ?? false;
const openAILoggingDir =
argv.openaiLoggingDir || settings.model?.openAILoggingDir;
// Build the full generation config
// Note: we merge the resolved config with logging settings
const generationConfig: Partial<ContentGeneratorConfig> = {
...resolved.config,
enableOpenAILogging,
openAILoggingDir,
};
return {
model: resolved.config.model || '',
apiKey: resolved.config.apiKey || '',
baseUrl: resolved.config.baseUrl || '',
generationConfig,
sources: resolved.sources,
};
}

View file

@ -1,142 +0,0 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import {
AuthType,
type ContentGeneratorConfig,
type ContentGeneratorConfigSource,
type ContentGeneratorConfigSources,
type ModelProvidersConfig,
type ProviderModelConfig as ModelConfig,
} from '@qwen-code/qwen-code-core';
import type { Settings } from '../config/settings.js';
export interface GenerationConfigSourceInputs {
argv: {
model?: string | undefined;
openaiApiKey?: string | undefined;
openaiBaseUrl?: string | undefined;
};
settings: Settings;
selectedAuthType: AuthType | undefined;
/**
* Injectable env for testability. Defaults to process.env at callsites.
*/
env?: Record<string, string | undefined>;
}
/**
* Get models configuration from settings, grouped by authType.
* Returns the models config from the merged settings without mutating files.
*/
export function getModelProvidersConfigFromSettings(
settings: Settings,
): ModelProvidersConfig {
return (settings.modelProviders as ModelProvidersConfig) || {};
}
/**
* Get models for a specific authType from settings.
*/
export function getModelsForAuthType(
settings: Settings,
authType: AuthType,
): ModelConfig[] {
const modelProvidersConfig = getModelProvidersConfigFromSettings(settings);
return modelProvidersConfig[authType] || [];
}
/**
* Best-effort attribution for the seed generationConfig fields.
*
* NOTE:
* - This does not attempt to distinguish user vs workspace settings; it reflects merged settings.
* - This should stay consistent with the actual precedence used to compute the corresponding values.
*/
export function buildGenerationConfigSources(
inputs: GenerationConfigSourceInputs,
): ContentGeneratorConfigSources {
const { argv, settings, selectedAuthType } = inputs;
const env = inputs.env ?? (process.env as Record<string, string | undefined>);
const sources: ContentGeneratorConfigSources = {};
const setSource = (path: string, source: ContentGeneratorConfigSource) => {
sources[path] = source;
};
// Model/apiKey/baseUrl attribution mirrors current CLI precedence:
// - model: argv.model > (OPENAI_MODEL|QWEN_MODEL|settings.model.name) only for OpenAI auth
// - apiKey/baseUrl: only meaningful for OpenAI auth in current CLI wiring
if (selectedAuthType === AuthType.USE_OPENAI) {
if (argv.model) {
setSource('model', { kind: 'cli', detail: '--model' });
} else if (env['OPENAI_MODEL']) {
setSource('model', { kind: 'env', envKey: 'OPENAI_MODEL' });
} else if (env['QWEN_MODEL']) {
setSource('model', { kind: 'env', envKey: 'QWEN_MODEL' });
} else if (settings.model?.name) {
setSource('model', { kind: 'settings', settingsPath: 'model.name' });
}
if (argv.openaiApiKey) {
setSource('apiKey', { kind: 'cli', detail: '--openaiApiKey' });
} else if (env['OPENAI_API_KEY']) {
setSource('apiKey', { kind: 'env', envKey: 'OPENAI_API_KEY' });
} else if (settings.security?.auth?.apiKey) {
setSource('apiKey', {
kind: 'settings',
settingsPath: 'security.auth.apiKey',
});
}
if (argv.openaiBaseUrl) {
setSource('baseUrl', { kind: 'cli', detail: '--openaiBaseUrl' });
} else if (env['OPENAI_BASE_URL']) {
setSource('baseUrl', { kind: 'env', envKey: 'OPENAI_BASE_URL' });
} else if (settings.security?.auth?.baseUrl) {
setSource('baseUrl', {
kind: 'settings',
settingsPath: 'security.auth.baseUrl',
});
}
} else if (argv.model) {
// For non-openai auth types, the CLI only wires through an explicit raw model override.
setSource('model', { kind: 'cli', detail: '--model' });
}
const mergedGenerationConfig = settings.model?.generationConfig as
| Partial<ContentGeneratorConfig>
| undefined;
if (mergedGenerationConfig) {
setSource('generationConfig', {
kind: 'settings',
settingsPath: 'model.generationConfig',
});
// We also map the known top-level fields used by core.
if (mergedGenerationConfig.samplingParams) {
setSource('samplingParams', {
kind: 'settings',
settingsPath: 'model.generationConfig.samplingParams',
});
}
for (const k of [
'timeout',
'maxRetries',
'disableCacheControl',
'schemaCompliance',
] as const) {
if (mergedGenerationConfig[k] !== undefined) {
setSource(k, {
kind: 'settings',
settingsPath: `model.generationConfig.${k}`,
});
}
}
}
return sources;
}