feat: Implement message bus and policy engine (#11523)

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
This commit is contained in:
Allen Hutchison
2025-10-21 11:45:33 -07:00
committed by GitHub
parent 0658b4aa31
commit bf80263bd6
19 changed files with 339 additions and 94 deletions
+48 -13
View File
@@ -76,13 +76,9 @@ export abstract class BaseToolInvocation<
constructor(
readonly params: TParams,
protected readonly messageBus?: MessageBus,
) {
if (this.messageBus) {
console.debug(
`[DEBUG] Tool ${this.constructor.name} created with messageBus: YES`,
);
}
}
readonly _toolName?: string,
readonly _toolDisplayName?: string,
) {}
abstract getDescription(): string;
@@ -90,11 +86,43 @@ export abstract class BaseToolInvocation<
return [];
}
shouldConfirmExecute(
_abortSignal: AbortSignal,
async shouldConfirmExecute(
abortSignal: AbortSignal,
): Promise<ToolCallConfirmationDetails | false> {
// Default implementation for tools that don't override it.
return Promise.resolve(false);
if (this.messageBus) {
const decision = await this.getMessageBusDecision(abortSignal);
if (decision === 'ALLOW') {
return false;
}
if (decision === 'DENY') {
throw new Error(
`Tool execution for "${
this._toolDisplayName || this._toolName
}" denied by policy.`,
);
}
if (decision === 'ASK_USER') {
const confirmationDetails: ToolCallConfirmationDetails = {
type: 'info',
title: `Confirm: ${this._toolDisplayName || this._toolName}`,
prompt: this.getDescription(),
onConfirm: async (outcome: ToolConfirmationOutcome) => {
if (outcome === ToolConfirmationOutcome.ProceedAlways) {
if (this.messageBus && this._toolName) {
this.messageBus.publish({
type: MessageBusType.UPDATE_POLICY,
toolName: this._toolName,
});
}
}
},
};
return confirmationDetails;
}
}
return false;
}
protected getMessageBusDecision(
@@ -108,7 +136,7 @@ export abstract class BaseToolInvocation<
const correlationId = randomUUID();
const toolCall = {
name: this.constructor.name,
name: this._toolName || this.constructor.name,
args: this.params as Record<string, unknown>,
};
@@ -385,7 +413,12 @@ export abstract class BaseDeclarativeTool<
if (validationError) {
throw new Error(validationError);
}
return this.createInvocation(params, this.messageBus);
return this.createInvocation(
params,
this.messageBus,
this.name,
this.displayName,
);
}
override validateToolParams(params: TParams): string | null {
@@ -408,6 +441,8 @@ export abstract class BaseDeclarativeTool<
protected abstract createInvocation(
params: TParams,
messageBus?: MessageBus,
_toolName?: string,
_toolDisplayName?: string,
): ToolInvocation<TParams, TResult>;
}