refactor: deprecate legacy confirmation settings and enforce Policy Engine (#15626)

This commit is contained in:
Abhi
2025-12-29 14:22:42 -05:00
committed by GitHub
parent a3d214f8d7
commit dcd2449b1a
17 changed files with 31 additions and 113 deletions
+2 -1
View File
@@ -61,6 +61,7 @@ vi.mock('../tools/tool-registry', () => {
ToolRegistryMock.prototype.sortTools = vi.fn();
ToolRegistryMock.prototype.getAllTools = vi.fn(() => []); // Mock methods if needed
ToolRegistryMock.prototype.getTool = vi.fn();
ToolRegistryMock.prototype.setMessageBus = vi.fn();
ToolRegistryMock.prototype.getFunctionDeclarations = vi.fn(() => []);
return { ToolRegistry: ToolRegistryMock };
});
@@ -923,7 +924,7 @@ describe('Server Config (config.ts)', () => {
expect(DelegateToAgentToolMock).toHaveBeenCalledWith(
expect.anything(), // AgentRegistry
config,
undefined,
expect.anything(), // MessageBus
);
const calls = registerToolMock.mock.calls;
+3 -24
View File
@@ -312,7 +312,6 @@ export interface ConfigParameters {
useWriteTodos?: boolean;
policyEngineConfig?: PolicyEngineConfig;
output?: OutputSettings;
enableMessageBusIntegration?: boolean;
disableModelRouterForAuth?: AuthType[];
codebaseInvestigatorSettings?: CodebaseInvestigatorSettings;
introspectionAgentSettings?: IntrospectionAgentSettings;
@@ -436,7 +435,6 @@ export class Config {
private readonly messageBus: MessageBus;
private readonly policyEngine: PolicyEngine;
private readonly outputSettings: OutputSettings;
private readonly enableMessageBusIntegration: boolean;
private readonly codebaseInvestigatorSettings: CodebaseInvestigatorSettings;
private readonly introspectionAgentSettings: IntrospectionAgentSettings;
private readonly continueOnFailedApiCall: boolean;
@@ -579,14 +577,6 @@ export class Config {
? params.hooks.disabled
: undefined) ?? [];
// Enable MessageBus integration if:
// 1. Explicitly enabled via setting, OR
// 2. Hooks are enabled and hooks are configured
const hasHooks = params.hooks && Object.keys(params.hooks).length > 0;
const hooksNeedMessageBus = this.enableHooks && hasHooks;
this.enableMessageBusIntegration =
params.enableMessageBusIntegration ??
(hooksNeedMessageBus ? true : false);
this.codebaseInvestigatorSettings = {
enabled: params.codebaseInvestigatorSettings?.enabled ?? true,
maxNumTurns: params.codebaseInvestigatorSettings?.maxNumTurns ?? 10,
@@ -1580,10 +1570,6 @@ export class Config {
return this.policyEngine;
}
getEnableMessageBusIntegration(): boolean {
return this.enableMessageBusIntegration;
}
getEnableHooks(): boolean {
return this.enableHooks;
}
@@ -1600,9 +1586,7 @@ export class Config {
const registry = new ToolRegistry(this);
// Set message bus on tool registry before discovery so MCP tools can access it
if (this.getEnableMessageBusIntegration()) {
registry.setMessageBus(this.messageBus);
}
registry.setMessageBus(this.messageBus);
// helper to create & register core tools that are enabled
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -1628,11 +1612,7 @@ export class Config {
// Pass message bus to tools when feature flag is enabled
// This first implementation is only focused on the general case of
// the tool registry.
const messageBusEnabled = this.getEnableMessageBusIntegration();
const toolArgs = messageBusEnabled
? [...args, this.getMessageBus()]
: args;
const toolArgs = [...args, this.getMessageBus()];
registry.registerTool(new ToolClass(...toolArgs));
}
@@ -1686,11 +1666,10 @@ export class Config {
!allowedTools || allowedTools.includes(DELEGATE_TO_AGENT_TOOL_NAME);
if (isAllowed) {
const messageBusEnabled = this.getEnableMessageBusIntegration();
const delegateTool = new DelegateToAgentTool(
this.agentRegistry,
this,
messageBusEnabled ? this.getMessageBus() : undefined,
this.getMessageBus(),
);
registry.registerTool(delegateTool);
}
@@ -257,8 +257,7 @@ function createMockConfig(overrides: Partial<Config> = {}): Config {
getActiveModel: () => DEFAULT_GEMINI_MODEL,
getUseSmartEdit: () => false,
getGeminiClient: () => null,
getEnableMessageBusIntegration: () => false,
getMessageBus: () => null,
getMessageBus: () => createMockMessageBus(),
getEnableHooks: () => false,
getPolicyEngine: () => null,
getExperiments: () => {},
+21 -23
View File
@@ -148,32 +148,30 @@ export class CoreToolScheduler {
// Use a static WeakMap to ensure we only subscribe ONCE per MessageBus instance
// This prevents memory leaks when multiple CoreToolScheduler instances are created
// (e.g., on every React render, or for each non-interactive tool call)
if (this.config.getEnableMessageBusIntegration()) {
const messageBus = this.config.getMessageBus();
const messageBus = this.config.getMessageBus();
// Check if we've already subscribed a handler to this message bus
if (!CoreToolScheduler.subscribedMessageBuses.has(messageBus)) {
// Create a shared handler that will be used for this message bus
const sharedHandler = (request: ToolConfirmationRequest) => {
// When ASK_USER policy decision is made, respond with requiresUserConfirmation=true
// to tell tools to use their legacy confirmation flow
// eslint-disable-next-line @typescript-eslint/no-floating-promises
messageBus.publish({
type: MessageBusType.TOOL_CONFIRMATION_RESPONSE,
correlationId: request.correlationId,
confirmed: false,
requiresUserConfirmation: true,
});
};
// Check if we've already subscribed a handler to this message bus
if (!CoreToolScheduler.subscribedMessageBuses.has(messageBus)) {
// Create a shared handler that will be used for this message bus
const sharedHandler = (request: ToolConfirmationRequest) => {
// When ASK_USER policy decision is made, respond with requiresUserConfirmation=true
// to tell tools to use their legacy confirmation flow
// eslint-disable-next-line @typescript-eslint/no-floating-promises
messageBus.publish({
type: MessageBusType.TOOL_CONFIRMATION_RESPONSE,
correlationId: request.correlationId,
confirmed: false,
requiresUserConfirmation: true,
});
};
messageBus.subscribe(
MessageBusType.TOOL_CONFIRMATION_REQUEST,
sharedHandler,
);
messageBus.subscribe(
MessageBusType.TOOL_CONFIRMATION_REQUEST,
sharedHandler,
);
// Store the handler in the WeakMap so we don't subscribe again
CoreToolScheduler.subscribedMessageBuses.set(messageBus, sharedHandler);
}
// Store the handler in the WeakMap so we don't subscribe again
CoreToolScheduler.subscribedMessageBuses.set(messageBus, sharedHandler);
}
}
@@ -65,7 +65,6 @@ describe('executeToolCall', () => {
getActiveModel: () => PREVIEW_GEMINI_MODEL,
getUseSmartEdit: () => false,
getGeminiClient: () => null, // No client needed for these tests
getEnableMessageBusIntegration: () => false,
getMessageBus: () => null,
getPolicyEngine: () => null,
isInteractive: () => false,