diff --git a/packages/core/src/agents/registry.ts b/packages/core/src/agents/registry.ts index 3a815aa012..ad1b0b7afa 100644 --- a/packages/core/src/agents/registry.ts +++ b/packages/core/src/agents/registry.ts @@ -104,6 +104,11 @@ export class AgentRegistry { private async loadAgents(): Promise { this.agents.clear(); this.allDefinitions.clear(); + + if (this.config.isThinHarness()) { + return; + } + this.loadBuiltInAgents(); if (!this.config.isAgentsEnabled()) { @@ -240,6 +245,10 @@ export class AgentRegistry { } private loadBuiltInAgents(): void { + if (this.config.isThinHarness()) { + return; + } + this.registerLocalAgent(CodebaseInvestigatorAgent(this.config)); this.registerLocalAgent(CliHelpAgent(this.config)); this.registerLocalAgent(GeneralistAgent(this.config)); diff --git a/packages/core/src/config/config.ts b/packages/core/src/config/config.ts index 2e9102250c..b5c44f9fd3 100644 --- a/packages/core/src/config/config.ts +++ b/packages/core/src/config/config.ts @@ -633,6 +633,7 @@ export interface ConfigParameters { tracker?: boolean; planSettings?: PlanSettings; modelSteering?: boolean; + thinHarness?: boolean; onModelChange?: (model: string) => void; mcpEnabled?: boolean; extensionsEnabled?: boolean; @@ -853,6 +854,7 @@ export class Config implements McpContext, AgentLoopContext { private readonly planEnabled: boolean; private readonly trackerEnabled: boolean; private readonly planModeRoutingEnabled: boolean; + private readonly thinHarness: boolean; private readonly modelSteering: boolean; private contextManager?: ContextManager; private terminalBackground: string | undefined = undefined; @@ -996,6 +998,8 @@ export class Config implements McpContext, AgentLoopContext { modelConfigServiceConfig ?? DEFAULT_MODEL_CONFIGS, ); + this.thinHarness = + params.thinHarness ?? process.env['GEMINI_THIN_HARNESS'] === 'true'; this.experimentalJitContext = params.experimentalJitContext ?? true; this.topicUpdateNarration = params.topicUpdateNarration ?? false; this.modelSteering = params.modelSteering ?? false; @@ -2024,6 +2028,10 @@ export class Config implements McpContext, AgentLoopContext { } getUserMemory(): string | HierarchicalMemory { + if (this.thinHarness) { + return { global: '', extension: '', project: '' }; + } + if (this.experimentalJitContext && this.contextManager) { return { global: this.contextManager.getGlobalMemory(), @@ -2120,6 +2128,9 @@ export class Config implements McpContext, AgentLoopContext { } getGeminiMdFileCount(): number { + if (this.thinHarness) { + return 0; + } if (this.experimentalJitContext && this.contextManager) { return this.contextManager.getLoadedPaths().size; } @@ -2131,6 +2142,9 @@ export class Config implements McpContext, AgentLoopContext { } getGeminiMdFilePaths(): string[] { + if (this.thinHarness) { + return []; + } if (this.experimentalJitContext && this.contextManager) { return Array.from(this.contextManager.getLoadedPaths()); } @@ -2493,7 +2507,7 @@ export class Config implements McpContext, AgentLoopContext { } isAgentsEnabled(): boolean { - return this.enableAgents; + return this.enableAgents && !this.thinHarness; } isEventDrivenSchedulerEnabled(): boolean { @@ -2786,7 +2800,7 @@ export class Config implements McpContext, AgentLoopContext { } isSkillsSupportEnabled(): boolean { - return this.skillsSupport; + return this.skillsSupport && !this.thinHarness; } /** @@ -2843,6 +2857,10 @@ export class Config implements McpContext, AgentLoopContext { } } + isThinHarness(): boolean { + return this.thinHarness; + } + isInteractive(): boolean { return this.interactive; } @@ -3153,6 +3171,10 @@ export class Config implements McpContext, AgentLoopContext { * Registers SubAgentTools for all available agents. */ private registerSubAgentTools(registry: ToolRegistry): void { + if (this.thinHarness) { + return; + } + const agentsOverrides = this.getAgentsSettings().overrides ?? {}; const definitions = this.agentRegistry.getAllDefinitions(); diff --git a/packages/core/src/prompts/promptProvider.ts b/packages/core/src/prompts/promptProvider.ts index ed71b035dc..8f6273d873 100644 --- a/packages/core/src/prompts/promptProvider.ts +++ b/packages/core/src/prompts/promptProvider.ts @@ -44,6 +44,11 @@ export class PromptProvider { userMemory?: string | HierarchicalMemory, interactiveOverride?: boolean, ): string { + const config = context.config; + if (config.isThinHarness()) { + return 'You are Gemini CLI, a helpful assistant specializing in software engineering tasks.'; + } + const systemMdResolution = resolvePathFromEnv( process.env['GEMINI_SYSTEM_MD'], ); @@ -216,11 +221,13 @@ export class PromptProvider { } // --- Finalization (Shell) --- - const finalPrompt = activeSnippets.renderFinalShell( - basePrompt, - userMemory, - contextFilenames, - ); + const finalPrompt = context.config.isThinHarness() + ? basePrompt + : activeSnippets.renderFinalShell( + basePrompt, + userMemory, + contextFilenames, + ); // Sanitize erratic newlines from composition const sanitizedPrompt = finalPrompt.replace(/\n{3,}/g, '\n\n'); diff --git a/packages/core/src/utils/memoryDiscovery.ts b/packages/core/src/utils/memoryDiscovery.ts index f772394d79..64e0a97a3b 100644 --- a/packages/core/src/utils/memoryDiscovery.ts +++ b/packages/core/src/utils/memoryDiscovery.ts @@ -699,6 +699,18 @@ export async function loadServerHierarchicalMemory( * Returns the result of the call to `loadHierarchicalGeminiMemory`. */ export async function refreshServerHierarchicalMemory(config: Config) { + if (config.isThinHarness()) { + const emptyResult: LoadServerHierarchicalMemoryResponse = { + memoryContent: { global: '', extension: '', project: '' }, + fileCount: 0, + filePaths: [], + }; + config.setUserMemory(emptyResult.memoryContent); + config.setGeminiMdFileCount(0); + config.setGeminiMdFilePaths([]); + return emptyResult; + } + const result = await loadServerHierarchicalMemory( config.getWorkingDir(), config.shouldLoadMemoryFromIncludeDirectories()