Expose Codebase Investigator settings to the user (#10844)

This commit is contained in:
Silvio Junior
2025-10-13 22:30:32 -04:00
committed by GitHub
parent f56a561f02
commit 9185f68e52
8 changed files with 120 additions and 131 deletions
+27 -1
View File
@@ -33,7 +33,33 @@ export class AgentRegistry {
}
private loadBuiltInAgents(): void {
this.registerAgent(CodebaseInvestigatorAgent);
const investigatorSettings = this.config.getCodebaseInvestigatorSettings();
// Only register the agent if it's enabled in the settings.
if (investigatorSettings?.enabled) {
const agentDef = {
...CodebaseInvestigatorAgent,
modelConfig: {
...CodebaseInvestigatorAgent.modelConfig,
model:
investigatorSettings.model ??
CodebaseInvestigatorAgent.modelConfig.model,
thinkingBudget:
investigatorSettings.thinkingBudget ??
CodebaseInvestigatorAgent.modelConfig.thinkingBudget,
},
runConfig: {
...CodebaseInvestigatorAgent.runConfig,
max_time_minutes:
investigatorSettings.maxTimeMinutes ??
CodebaseInvestigatorAgent.runConfig.max_time_minutes,
max_turns:
investigatorSettings.maxNumTurns ??
CodebaseInvestigatorAgent.runConfig.max_turns,
},
};
this.registerAgent(agentDef);
}
}
/**
+15 -43
View File
@@ -133,6 +133,7 @@ vi.mock('../agents/registry.js', () => {
const AgentRegistryMock = vi.fn();
AgentRegistryMock.prototype.initialize = vi.fn();
AgentRegistryMock.prototype.getAllDefinitions = vi.fn(() => []);
AgentRegistryMock.prototype.getDefinition = vi.fn();
return { AgentRegistry: AgentRegistryMock };
});
@@ -600,31 +601,6 @@ describe('Server Config (config.ts)', () => {
});
});
describe('EnableSubagents Configuration', () => {
it('should default enableSubagents to false when not provided', () => {
const config = new Config(baseParams);
expect(config.getEnableSubagents()).toBe(false);
});
it('should set enableSubagents to true when provided as true', () => {
const paramsWithSubagents: ConfigParameters = {
...baseParams,
enableSubagents: true,
};
const config = new Config(paramsWithSubagents);
expect(config.getEnableSubagents()).toBe(true);
});
it('should set enableSubagents to false when explicitly provided as false', () => {
const paramsWithSubagents: ConfigParameters = {
...baseParams,
enableSubagents: false,
};
const config = new Config(paramsWithSubagents);
expect(config.getEnableSubagents()).toBe(false);
});
});
describe('ContinueOnFailedApiCall Configuration', () => {
it('should default continueOnFailedApiCall to false when not provided', () => {
const config = new Config(baseParams);
@@ -679,25 +655,26 @@ describe('Server Config (config.ts)', () => {
expect(wasReadFileToolRegistered).toBe(false);
});
it('should register subagents as tools when enableSubagents is true', async () => {
it('should register subagents as tools when codebaseInvestigatorSettings.enabled is true', async () => {
const params: ConfigParameters = {
...baseParams,
enableSubagents: true,
codebaseInvestigatorSettings: { enabled: true },
};
const config = new Config(params);
const mockAgentDefinitions = [
{ name: 'agent1', description: 'Agent 1', instructions: 'Inst 1' },
{ name: 'agent2', description: 'Agent 2', instructions: 'Inst 2' },
];
const mockAgentDefinition = {
name: 'codebase-investigator',
description: 'Agent 1',
instructions: 'Inst 1',
};
const AgentRegistryMock = (
(await vi.importMock('../agents/registry.js')) as {
AgentRegistry: Mock;
}
).AgentRegistry;
AgentRegistryMock.prototype.getAllDefinitions.mockReturnValue(
mockAgentDefinitions,
AgentRegistryMock.prototype.getDefinition.mockReturnValue(
mockAgentDefinition,
);
const SubagentToolWrapperMock = (
@@ -714,14 +691,9 @@ describe('Server Config (config.ts)', () => {
}
).ToolRegistry.prototype.registerTool;
expect(SubagentToolWrapperMock).toHaveBeenCalledTimes(2);
expect(SubagentToolWrapperMock).toHaveBeenCalledTimes(1);
expect(SubagentToolWrapperMock).toHaveBeenCalledWith(
mockAgentDefinitions[0],
config,
undefined,
);
expect(SubagentToolWrapperMock).toHaveBeenCalledWith(
mockAgentDefinitions[1],
mockAgentDefinition,
config,
undefined,
);
@@ -730,13 +702,13 @@ describe('Server Config (config.ts)', () => {
const registeredWrappers = calls.filter(
(call) => call[0] instanceof SubagentToolWrapperMock,
);
expect(registeredWrappers).toHaveLength(2);
expect(registeredWrappers).toHaveLength(1);
});
it('should not register subagents as tools when enableSubagents is false', async () => {
it('should not register subagents as tools when codebaseInvestigatorSettings.enabled is false', async () => {
const params: ConfigParameters = {
...baseParams,
enableSubagents: false,
codebaseInvestigatorSettings: { enabled: false },
};
const config = new Config(params);
+18 -8
View File
@@ -116,6 +116,14 @@ export interface OutputSettings {
format?: OutputFormat;
}
export interface CodebaseInvestigatorSettings {
enabled?: boolean;
maxNumTurns?: number;
maxTimeMinutes?: number;
thinkingBudget?: number;
model?: string;
}
/**
* All information required in CLI to handle an extension. Defined in Core so
* that the collection of loaded, active, and inactive extensions can be passed
@@ -268,7 +276,7 @@ export interface ConfigParameters {
output?: OutputSettings;
useModelRouter?: boolean;
enableMessageBusIntegration?: boolean;
enableSubagents?: boolean;
codebaseInvestigatorSettings?: CodebaseInvestigatorSettings;
continueOnFailedApiCall?: boolean;
}
@@ -361,7 +369,7 @@ export class Config {
private readonly outputSettings: OutputSettings;
private readonly useModelRouter: boolean;
private readonly enableMessageBusIntegration: boolean;
private readonly enableSubagents: boolean;
private readonly codebaseInvestigatorSettings?: CodebaseInvestigatorSettings;
private readonly continueOnFailedApiCall: boolean;
constructor(params: ConfigParameters) {
@@ -455,7 +463,7 @@ export class Config {
this.useModelRouter = params.useModelRouter ?? false;
this.enableMessageBusIntegration =
params.enableMessageBusIntegration ?? false;
this.enableSubagents = params.enableSubagents ?? false;
this.codebaseInvestigatorSettings = params.codebaseInvestigatorSettings;
this.continueOnFailedApiCall = params.continueOnFailedApiCall ?? true;
this.extensionManagement = params.extensionManagement ?? true;
this.storage = new Storage(this.targetDir);
@@ -1039,8 +1047,8 @@ export class Config {
return this.enableMessageBusIntegration;
}
getEnableSubagents(): boolean {
return this.enableSubagents;
getCodebaseInvestigatorSettings(): CodebaseInvestigatorSettings | undefined {
return this.codebaseInvestigatorSettings;
}
async createToolRegistry(): Promise<ToolRegistry> {
@@ -1135,9 +1143,11 @@ export class Config {
}
// Register Subagents as Tools
if (this.getEnableSubagents()) {
const agentDefinitions = this.agentRegistry.getAllDefinitions();
for (const definition of agentDefinitions) {
if (this.getCodebaseInvestigatorSettings()?.enabled) {
const definition = this.agentRegistry.getDefinition(
'codebase_investigator',
);
if (definition) {
// We must respect the main allowed/exclude lists for agents too.
const excludeTools = this.getExcludeTools() || [];
const allowedTools = this.getAllowedTools();