mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-20 18:14:29 -07:00
feat(a2a): Introduce /init command for a2a server (#13419)
This commit is contained in:
@@ -127,6 +127,7 @@ export class CoderAgentExecutor implements AgentExecutor {
|
||||
contextId,
|
||||
config,
|
||||
eventBus,
|
||||
agentSettings.autoExecute,
|
||||
);
|
||||
runtimeTask.taskState = persistedState._taskState;
|
||||
await runtimeTask.geminiClient.initialize();
|
||||
@@ -145,7 +146,13 @@ export class CoderAgentExecutor implements AgentExecutor {
|
||||
): Promise<TaskWrapper> {
|
||||
const agentSettings = agentSettingsInput || ({} as AgentSettings);
|
||||
const config = await this.getConfig(agentSettings, taskId);
|
||||
const runtimeTask = await Task.create(taskId, contextId, config, eventBus);
|
||||
const runtimeTask = await Task.create(
|
||||
taskId,
|
||||
contextId,
|
||||
config,
|
||||
eventBus,
|
||||
agentSettings.autoExecute,
|
||||
);
|
||||
await runtimeTask.geminiClient.initialize();
|
||||
|
||||
const wrapper = new TaskWrapper(runtimeTask, agentSettings);
|
||||
|
||||
@@ -20,6 +20,8 @@ import {
|
||||
type ToolCallRequestInfo,
|
||||
type GitService,
|
||||
type CompletedToolCall,
|
||||
ApprovalMode,
|
||||
ToolConfirmationOutcome,
|
||||
} from '@google/gemini-cli-core';
|
||||
import { createMockConfig } from '../utils/testing_utils.js';
|
||||
import type { ExecutionEventBus, RequestContext } from '@a2a-js/sdk/server';
|
||||
@@ -353,10 +355,12 @@ describe('Task', () => {
|
||||
let task: Task;
|
||||
type SpyInstance = ReturnType<typeof vi.spyOn>;
|
||||
let setTaskStateAndPublishUpdateSpy: SpyInstance;
|
||||
let mockConfig: Config;
|
||||
let mockEventBus: ExecutionEventBus;
|
||||
|
||||
beforeEach(() => {
|
||||
const mockConfig = createMockConfig();
|
||||
const mockEventBus: ExecutionEventBus = {
|
||||
mockConfig = createMockConfig() as Config;
|
||||
mockEventBus = {
|
||||
publish: vi.fn(),
|
||||
on: vi.fn(),
|
||||
off: vi.fn(),
|
||||
@@ -465,6 +469,67 @@ describe('Task', () => {
|
||||
);
|
||||
expect(finalCall).toBeUndefined();
|
||||
});
|
||||
|
||||
describe('auto-approval', () => {
|
||||
it('should auto-approve tool calls when autoExecute is true', () => {
|
||||
task.autoExecute = true;
|
||||
const onConfirmSpy = vi.fn();
|
||||
const toolCalls = [
|
||||
{
|
||||
request: { callId: '1' },
|
||||
status: 'awaiting_approval',
|
||||
confirmationDetails: { onConfirm: onConfirmSpy },
|
||||
},
|
||||
] as unknown as ToolCall[];
|
||||
|
||||
// @ts-expect-error - Calling private method
|
||||
task._schedulerToolCallsUpdate(toolCalls);
|
||||
|
||||
expect(onConfirmSpy).toHaveBeenCalledWith(
|
||||
ToolConfirmationOutcome.ProceedOnce,
|
||||
);
|
||||
});
|
||||
|
||||
it('should auto-approve tool calls when approval mode is YOLO', () => {
|
||||
(mockConfig.getApprovalMode as Mock).mockReturnValue(ApprovalMode.YOLO);
|
||||
task.autoExecute = false;
|
||||
const onConfirmSpy = vi.fn();
|
||||
const toolCalls = [
|
||||
{
|
||||
request: { callId: '1' },
|
||||
status: 'awaiting_approval',
|
||||
confirmationDetails: { onConfirm: onConfirmSpy },
|
||||
},
|
||||
] as unknown as ToolCall[];
|
||||
|
||||
// @ts-expect-error - Calling private method
|
||||
task._schedulerToolCallsUpdate(toolCalls);
|
||||
|
||||
expect(onConfirmSpy).toHaveBeenCalledWith(
|
||||
ToolConfirmationOutcome.ProceedOnce,
|
||||
);
|
||||
});
|
||||
|
||||
it('should NOT auto-approve when autoExecute is false and mode is not YOLO', () => {
|
||||
task.autoExecute = false;
|
||||
(mockConfig.getApprovalMode as Mock).mockReturnValue(
|
||||
ApprovalMode.DEFAULT,
|
||||
);
|
||||
const onConfirmSpy = vi.fn();
|
||||
const toolCalls = [
|
||||
{
|
||||
request: { callId: '1' },
|
||||
status: 'awaiting_approval',
|
||||
confirmationDetails: { onConfirm: onConfirmSpy },
|
||||
},
|
||||
] as unknown as ToolCall[];
|
||||
|
||||
// @ts-expect-error - Calling private method
|
||||
task._schedulerToolCallsUpdate(toolCalls);
|
||||
|
||||
expect(onConfirmSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('currentPromptId and promptCount', () => {
|
||||
|
||||
@@ -73,6 +73,7 @@ export class Task {
|
||||
modelInfo?: string;
|
||||
currentPromptId: string | undefined;
|
||||
promptCount = 0;
|
||||
autoExecute: boolean;
|
||||
|
||||
// For tool waiting logic
|
||||
private pendingToolCalls: Map<string, string> = new Map(); //toolCallId --> status
|
||||
@@ -87,6 +88,7 @@ export class Task {
|
||||
contextId: string,
|
||||
config: Config,
|
||||
eventBus?: ExecutionEventBus,
|
||||
autoExecute = false,
|
||||
) {
|
||||
this.id = id;
|
||||
this.contextId = contextId;
|
||||
@@ -98,6 +100,7 @@ export class Task {
|
||||
this.eventBus = eventBus;
|
||||
this.completedToolCalls = [];
|
||||
this._resetToolCompletionPromise();
|
||||
this.autoExecute = autoExecute;
|
||||
this.config.setFallbackModelHandler(
|
||||
// For a2a-server, we want to automatically switch to the fallback model
|
||||
// for future requests without retrying the current one. The 'stop'
|
||||
@@ -111,8 +114,9 @@ export class Task {
|
||||
contextId: string,
|
||||
config: Config,
|
||||
eventBus?: ExecutionEventBus,
|
||||
autoExecute?: boolean,
|
||||
): Promise<Task> {
|
||||
return new Task(id, contextId, config, eventBus);
|
||||
return new Task(id, contextId, config, eventBus, autoExecute);
|
||||
}
|
||||
|
||||
// Note: `getAllMCPServerStatuses` retrieves the status of all MCP servers for the entire
|
||||
@@ -396,8 +400,15 @@ export class Task {
|
||||
}
|
||||
});
|
||||
|
||||
if (this.config.getApprovalMode() === ApprovalMode.YOLO) {
|
||||
logger.info('[Task] YOLO mode enabled. Auto-approving all tool calls.');
|
||||
if (
|
||||
this.autoExecute ||
|
||||
this.config.getApprovalMode() === ApprovalMode.YOLO
|
||||
) {
|
||||
logger.info(
|
||||
'[Task] ' +
|
||||
(this.autoExecute ? '' : 'YOLO mode enabled. ') +
|
||||
'Auto-approving all tool calls.',
|
||||
);
|
||||
toolCalls.forEach((tc: ToolCall) => {
|
||||
if (tc.status === 'awaiting_approval' && tc.confirmationDetails) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
|
||||
Reference in New Issue
Block a user