diff options
Diffstat (limited to 'packages/cli/src')
| -rw-r--r-- | packages/cli/src/config/config.integration.test.ts | 57 | ||||
| -rw-r--r-- | packages/cli/src/config/config.ts | 78 | ||||
| -rw-r--r-- | packages/cli/src/ui/App.test.tsx | 8 |
3 files changed, 77 insertions, 66 deletions
diff --git a/packages/cli/src/config/config.integration.test.ts b/packages/cli/src/config/config.integration.test.ts index c016aa98..2cbe8c66 100644 --- a/packages/cli/src/config/config.integration.test.ts +++ b/packages/cli/src/config/config.integration.test.ts @@ -8,7 +8,17 @@ import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest'; import * as fs from 'fs'; import * as path from 'path'; import { tmpdir } from 'os'; -import { Config, ConfigParameters } from '@gemini-cli/core'; +import { + Config, + ConfigParameters, + ContentGeneratorConfig, +} from '@gemini-cli/core'; + +const TEST_CONTENT_GENERATOR_CONFIG: ContentGeneratorConfig = { + apiKey: 'test-key', + model: 'test-model', + userAgent: 'test-agent', +}; // Mock file discovery service and tool registry vi.mock('@gemini-cli/core', async () => { @@ -43,12 +53,11 @@ describe('Configuration Integration Tests', () => { describe('File Filtering Configuration', () => { it('should load default file filtering settings', async () => { const configParams: ConfigParameters = { - apiKey: 'test-key', - model: 'test-model', + contentGeneratorConfig: TEST_CONTENT_GENERATOR_CONFIG, + embeddingModel: 'test-embedding-model', sandbox: false, targetDir: tempDir, debugMode: false, - userAgent: 'test-agent', fileFilteringRespectGitIgnore: undefined, // Should default to true fileFilteringAllowBuildArtifacts: undefined, // Should default to false }; @@ -61,12 +70,11 @@ describe('Configuration Integration Tests', () => { it('should load custom file filtering settings from configuration', async () => { const configParams: ConfigParameters = { - apiKey: 'test-key', - model: 'test-model', + contentGeneratorConfig: TEST_CONTENT_GENERATOR_CONFIG, + embeddingModel: 'test-embedding-model', sandbox: false, targetDir: tempDir, debugMode: false, - userAgent: 'test-agent', fileFilteringRespectGitIgnore: false, fileFilteringAllowBuildArtifacts: true, }; @@ -79,12 +87,11 @@ describe('Configuration Integration Tests', () => { it('should merge user and workspace file filtering settings', async () => { const configParams: ConfigParameters = { - apiKey: 'test-key', - model: 'test-model', + contentGeneratorConfig: TEST_CONTENT_GENERATOR_CONFIG, + embeddingModel: 'test-embedding-model', sandbox: false, targetDir: tempDir, debugMode: false, - userAgent: 'test-agent', fileFilteringRespectGitIgnore: true, fileFilteringAllowBuildArtifacts: true, }; @@ -99,12 +106,11 @@ describe('Configuration Integration Tests', () => { describe('Configuration Integration', () => { it('should handle partial configuration objects gracefully', async () => { const configParams: ConfigParameters = { - apiKey: 'test-key', - model: 'test-model', + contentGeneratorConfig: TEST_CONTENT_GENERATOR_CONFIG, + embeddingModel: 'test-embedding-model', sandbox: false, targetDir: tempDir, debugMode: false, - userAgent: 'test-agent', fileFilteringRespectGitIgnore: false, fileFilteringAllowBuildArtifacts: undefined, // Should default to false }; @@ -120,12 +126,11 @@ describe('Configuration Integration Tests', () => { it('should handle empty configuration objects gracefully', async () => { const configParams: ConfigParameters = { - apiKey: 'test-key', - model: 'test-model', + contentGeneratorConfig: TEST_CONTENT_GENERATOR_CONFIG, + embeddingModel: 'test-embedding-model', sandbox: false, targetDir: tempDir, debugMode: false, - userAgent: 'test-agent', fileFilteringRespectGitIgnore: undefined, fileFilteringAllowBuildArtifacts: undefined, }; @@ -139,12 +144,11 @@ describe('Configuration Integration Tests', () => { it('should handle missing configuration sections gracefully', async () => { const configParams: ConfigParameters = { - apiKey: 'test-key', - model: 'test-model', + contentGeneratorConfig: TEST_CONTENT_GENERATOR_CONFIG, + embeddingModel: 'test-embedding-model', sandbox: false, targetDir: tempDir, debugMode: false, - userAgent: 'test-agent', // Missing fileFiltering configuration }; @@ -159,12 +163,11 @@ describe('Configuration Integration Tests', () => { describe('Real-world Configuration Scenarios', () => { it('should handle a security-focused configuration', async () => { const configParams: ConfigParameters = { - apiKey: 'test-key', - model: 'test-model', + contentGeneratorConfig: TEST_CONTENT_GENERATOR_CONFIG, + embeddingModel: 'test-embedding-model', sandbox: false, targetDir: tempDir, debugMode: false, - userAgent: 'test-agent', fileFilteringRespectGitIgnore: true, fileFilteringAllowBuildArtifacts: false, }; @@ -177,12 +180,11 @@ describe('Configuration Integration Tests', () => { it('should handle a development-focused configuration', async () => { const configParams: ConfigParameters = { - apiKey: 'test-key', - model: 'test-model', + contentGeneratorConfig: TEST_CONTENT_GENERATOR_CONFIG, + embeddingModel: 'test-embedding-model', sandbox: false, targetDir: tempDir, debugMode: false, - userAgent: 'test-agent', fileFilteringRespectGitIgnore: true, fileFilteringAllowBuildArtifacts: true, }; @@ -194,12 +196,11 @@ describe('Configuration Integration Tests', () => { it('should handle a CI/CD environment configuration', async () => { const configParams: ConfigParameters = { - apiKey: 'test-key', - model: 'test-model', + contentGeneratorConfig: TEST_CONTENT_GENERATOR_CONFIG, + embeddingModel: 'test-embedding-model', sandbox: false, targetDir: tempDir, debugMode: false, - userAgent: 'test-agent', fileFilteringRespectGitIgnore: false, // CI might need to see all files fileFilteringAllowBuildArtifacts: true, }; diff --git a/packages/cli/src/config/config.ts b/packages/cli/src/config/config.ts index 89b751bc..49004776 100644 --- a/packages/cli/src/config/config.ts +++ b/packages/cli/src/config/config.ts @@ -14,6 +14,7 @@ import { setGeminiMdFilename as setServerGeminiMdFilename, getCurrentGeminiMdFilename, ApprovalMode, + ContentGeneratorConfig, } from '@gemini-cli/core'; import { Settings } from './settings.js'; import { getEffectiveModel } from '../utils/modelCheck.js'; @@ -121,29 +122,6 @@ export async function loadCliConfig( ): Promise<Config> { loadEnvironment(); - const geminiApiKey = process.env.GEMINI_API_KEY; - const googleApiKey = process.env.GOOGLE_API_KEY; - const googleCloudProject = process.env.GOOGLE_CLOUD_PROJECT; - const googleCloudLocation = process.env.GOOGLE_CLOUD_LOCATION; - - const hasGeminiApiKey = !!geminiApiKey; - const hasGoogleApiKey = !!googleApiKey; - const hasVertexProjectLocationConfig = - !!googleCloudProject && !!googleCloudLocation; - - if (!hasGeminiApiKey && !hasGoogleApiKey && !hasVertexProjectLocationConfig) { - logger.error( - 'No valid API authentication configuration found. Please set ONE of the following combinations in your environment variables or .env file:\n' + - '1. GEMINI_API_KEY (for Gemini API access).\n' + - '2. GOOGLE_API_KEY (for Gemini API or Vertex AI Express Mode access).\n' + - '3. GOOGLE_CLOUD_PROJECT and GOOGLE_CLOUD_LOCATION (for Vertex AI access).\n\n' + - 'For Gemini API keys, visit: https://ai.google.dev/gemini-api/docs/api-key\n' + - 'For Vertex AI authentication, visit: https://cloud.google.com/vertex-ai/docs/start/authentication\n' + - 'The GOOGLE_GENAI_USE_VERTEXAI environment variable can also be set to true/false to influence service selection when ambiguity exists.', - ); - process.exit(1); - } - const argv = await parseArguments(); const debugMode = argv.debug || false; @@ -164,18 +142,10 @@ export async function loadCliConfig( debugMode, ); - const userAgent = `GeminiCLI/${getCliVersion()}/(${process.platform}; ${process.arch})`; - const apiKeyForServer = geminiApiKey || googleApiKey || ''; - const useVertexAI = hasGeminiApiKey ? false : undefined; - - let modelToUse = argv.model || DEFAULT_GEMINI_MODEL; - if (apiKeyForServer) { - modelToUse = await getEffectiveModel(apiKeyForServer, modelToUse); - } + const contentGeneratorConfig = await createContentGeneratorConfig(argv); return new Config({ - apiKey: apiKeyForServer, - model: modelToUse, + contentGeneratorConfig, embeddingModel: DEFAULT_GEMINI_EMBEDDING_MODEL, sandbox: argv.sandbox ?? settings.sandbox ?? argv.yolo ?? false, targetDir: process.cwd(), @@ -187,11 +157,9 @@ export async function loadCliConfig( toolCallCommand: settings.toolCallCommand, mcpServerCommand: settings.mcpServerCommand, mcpServers: settings.mcpServers, - userAgent, userMemory: memoryContent, geminiMdFileCount: fileCount, approvalMode: argv.yolo || false ? ApprovalMode.YOLO : ApprovalMode.DEFAULT, - vertexai: useVertexAI, showMemoryUsage: argv.show_memory_usage || settings.showMemoryUsage || false, geminiIgnorePatterns, @@ -206,3 +174,43 @@ export async function loadCliConfig( settings.fileFiltering?.allowBuildArtifacts, }); } + +async function createContentGeneratorConfig( + argv: CliArgs, +): Promise<ContentGeneratorConfig> { + const geminiApiKey = process.env.GEMINI_API_KEY; + const googleApiKey = process.env.GOOGLE_API_KEY; + const googleCloudProject = process.env.GOOGLE_CLOUD_PROJECT; + const googleCloudLocation = process.env.GOOGLE_CLOUD_LOCATION; + + const hasGeminiApiKey = !!geminiApiKey; + const hasGoogleApiKey = !!googleApiKey; + const hasVertexProjectLocationConfig = + !!googleCloudProject && !!googleCloudLocation; + + if (!hasGeminiApiKey && !hasGoogleApiKey && !hasVertexProjectLocationConfig) { + logger.error( + 'No valid API authentication configuration found. Please set ONE of the following combinations in your environment variables or .env file:\n' + + '1. GEMINI_API_KEY (for Gemini API access).\n' + + '2. GOOGLE_API_KEY (for Gemini API or Vertex AI Express Mode access).\n' + + '3. GOOGLE_CLOUD_PROJECT and GOOGLE_CLOUD_LOCATION (for Vertex AI access).\n\n' + + 'For Gemini API keys, visit: https://ai.google.dev/gemini-api/docs/api-key\n' + + 'For Vertex AI authentication, visit: https://cloud.google.com/vertex-ai/docs/start/authentication\n' + + 'The GOOGLE_GENAI_USE_VERTEXAI environment variable can also be set to true/false to influence service selection when ambiguity exists.', + ); + process.exit(1); + } + + const config: ContentGeneratorConfig = { + model: argv.model || DEFAULT_GEMINI_MODEL, + apiKey: geminiApiKey || googleApiKey || '', + vertexai: hasGeminiApiKey ? false : undefined, + userAgent: `GeminiCLI/${getCliVersion()}/(${process.platform}; ${process.arch})`, + }; + + if (config.apiKey) { + config.model = await getEffectiveModel(config.apiKey, config.model); + } + + return config; +} diff --git a/packages/cli/src/ui/App.test.tsx b/packages/cli/src/ui/App.test.tsx index b46af795..eeb5bbe6 100644 --- a/packages/cli/src/ui/App.test.tsx +++ b/packages/cli/src/ui/App.test.tsx @@ -179,13 +179,15 @@ describe('App UI', () => { beforeEach(() => { const ServerConfigMocked = vi.mocked(ServerConfig, true); mockConfig = new ServerConfigMocked({ - apiKey: 'test-key', - model: 'test-model', + contentGeneratorConfig: { + apiKey: 'test-key', + model: 'test-model', + userAgent: 'test-agent', + }, embeddingModel: 'test-embedding-model', sandbox: false, targetDir: '/test/dir', debugMode: false, - userAgent: 'test-agent', userMemory: '', geminiMdFileCount: 0, showMemoryUsage: false, |
