diff --git a/packages/cli/src/config/config.ts b/packages/cli/src/config/config.ts index d116bc6775..6bf9c2f539 100644 --- a/packages/cli/src/config/config.ts +++ b/packages/cli/src/config/config.ts @@ -19,6 +19,7 @@ import { TelemetryTarget, MCPServerConfig, IDE_SERVER_NAME, + IDEContext, } from '@google/gemini-cli-core'; import { Settings } from './settings.js'; @@ -242,6 +243,15 @@ export async function loadCliConfig( process.env.TERM_PROGRAM === 'vscode' && !process.env.SANDBOX; + const ideContext: IDEContext | undefined = ideMode + ? { + activeFile: { + path: 'foo/bar.txt', + content: 'this is a test file', + }, + } + : undefined; + const activeExtensions = filterActiveExtensions( extensions, argv.extensions || [], @@ -365,6 +375,7 @@ export async function loadCliConfig( noBrowser: !!process.env.NO_BROWSER, summarizeToolOutput: settings.summarizeToolOutput, ideMode, + ideContext, }); } diff --git a/packages/core/src/config/config.ts b/packages/core/src/config/config.ts index 268871caae..77d33dd3a1 100644 --- a/packages/core/src/config/config.ts +++ b/packages/core/src/config/config.ts @@ -45,6 +45,7 @@ import { DEFAULT_GEMINI_FLASH_MODEL, } from './models.js'; import { ClearcutLogger } from '../telemetry/clearcut-logger/clearcut-logger.js'; +import { IDEContext } from '../ide/types.js'; export enum ApprovalMode { DEFAULT = 'default', @@ -150,6 +151,7 @@ export interface ConfigParameters { noBrowser?: boolean; summarizeToolOutput?: Record; ideMode?: boolean; + ideContext?: IDEContext; } export class Config { @@ -190,6 +192,7 @@ export class Config { private readonly extensionContextFilePaths: string[]; private readonly noBrowser: boolean; private readonly ideMode: boolean; + private readonly ideContext: IDEContext | undefined; private modelSwitchedDuringSession: boolean = false; private readonly maxSessionTurns: number; private readonly listExtensions: boolean; @@ -246,6 +249,7 @@ export class Config { this.noBrowser = params.noBrowser ?? false; this.summarizeToolOutput = params.summarizeToolOutput; this.ideMode = params.ideMode ?? false; + this.ideContext = params.ideContext; if (params.contextFileName) { setGeminiMdFilename(params.contextFileName); @@ -516,6 +520,10 @@ export class Config { return this.ideMode; } + getIdeContext(): IDEContext | undefined { + return this.ideContext; + } + async getGitService(): Promise { if (!this.gitService) { this.gitService = new GitService(this.targetDir); diff --git a/packages/core/src/core/client.ts b/packages/core/src/core/client.ts index 8097981270..172ae53ee9 100644 --- a/packages/core/src/core/client.ts +++ b/packages/core/src/core/client.ts @@ -238,7 +238,8 @@ export class GeminiClient { ]; try { const userMemory = this.config.getUserMemory(); - const systemInstruction = getCoreSystemPrompt(userMemory); + const ideContext = this.config.getIdeContext(); + const systemInstruction = getCoreSystemPrompt(userMemory, ideContext); const generateContentConfigWithThinking = isThinkingSupported( this.config.getModel(), ) @@ -354,7 +355,8 @@ export class GeminiClient { model || this.config.getModel() || DEFAULT_GEMINI_FLASH_MODEL; try { const userMemory = this.config.getUserMemory(); - const systemInstruction = getCoreSystemPrompt(userMemory); + const ideContext = this.config.getIdeContext(); + const systemInstruction = getCoreSystemPrompt(userMemory, ideContext); const requestConfig = { abortSignal, ...this.generateContentConfig, @@ -447,7 +449,8 @@ export class GeminiClient { try { const userMemory = this.config.getUserMemory(); - const systemInstruction = getCoreSystemPrompt(userMemory); + const ideContext = this.config.getIdeContext(); + const systemInstruction = getCoreSystemPrompt(userMemory, ideContext); const requestConfig = { abortSignal, diff --git a/packages/core/src/core/prompts.ts b/packages/core/src/core/prompts.ts index 3b23f73556..05b6173e7e 100644 --- a/packages/core/src/core/prompts.ts +++ b/packages/core/src/core/prompts.ts @@ -17,8 +17,12 @@ import { WriteFileTool } from '../tools/write-file.js'; import process from 'node:process'; import { isGitRepository } from '../utils/gitUtils.js'; import { MemoryTool, GEMINI_CONFIG_DIR } from '../tools/memoryTool.js'; +import { IDEContext } from '../ide/types.js'; -export function getCoreSystemPrompt(userMemory?: string): string { +export function getCoreSystemPrompt( + userMemory?: string, + ideContext?: IDEContext, +): string { // if GEMINI_SYSTEM_MD is set (and not 0|false), override system prompt from file // default path is .gemini/system.md but can be modified via custom path in GEMINI_SYSTEM_MD let systemMdEnabled = false; @@ -34,11 +38,24 @@ export function getCoreSystemPrompt(userMemory?: string): string { throw new Error(`missing system prompt file '${systemMdPath}'`); } } + + const activeFileContext = ideContext?.activeFile + ? ` +# Active File + +The user has the following file open in their IDE. This is the most likely file they are wanting to work on. + +```${ideContext.activeFile.path} +${ideContext.activeFile.content} +``` +` + : ''; + const basePrompt = systemMdEnabled ? fs.readFileSync(systemMdPath, 'utf8') : ` You are an interactive CLI agent specializing in software engineering tasks. Your primary goal is to help users safely and efficiently, adhering strictly to the following instructions and utilizing your available tools. - +${activeFileContext} # Core Mandates - **Conventions:** Rigorously adhere to existing project conventions when reading or modifying code. Analyze surrounding code, tests, and configuration first. diff --git a/packages/core/src/ide/types.ts b/packages/core/src/ide/types.ts new file mode 100644 index 0000000000..bfde0fc2f1 --- /dev/null +++ b/packages/core/src/ide/types.ts @@ -0,0 +1,14 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +export interface ActiveFile { + path: string; + content: string; +} + +export interface IDEContext { + activeFile?: ActiveFile; +}