feat: implement thin harness mode

This commit is contained in:
Aishanee Shah
2026-03-17 14:07:44 +00:00
parent fc51e50bc6
commit a39866a7cd
4 changed files with 57 additions and 7 deletions
+9
View File
@@ -104,6 +104,11 @@ export class AgentRegistry {
private async loadAgents(): Promise<void> {
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));
+24 -2
View File
@@ -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();
+12 -5
View File
@@ -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');
@@ -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()