mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-01 07:24:38 -07:00
feat(a2a): Introduce /init command for a2a server (#13419)
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
import { CoderAgentEvent, type AgentSettings } from '../types.js';
|
||||
import { performInit } from '@google/gemini-cli-core';
|
||||
import type {
|
||||
Command,
|
||||
CommandContext,
|
||||
CommandExecutionResponse,
|
||||
} from './types.js';
|
||||
import type { CoderAgentExecutor } from '../agent/executor.js';
|
||||
import type {
|
||||
ExecutionEventBus,
|
||||
RequestContext,
|
||||
AgentExecutionEvent,
|
||||
} from '@a2a-js/sdk/server';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { logger } from '../utils/logger.js';
|
||||
|
||||
export class InitCommand implements Command {
|
||||
name = 'init';
|
||||
description = 'Analyzes the project and creates a tailored GEMINI.md file';
|
||||
requiresWorkspace = true;
|
||||
streaming = true;
|
||||
|
||||
private handleMessageResult(
|
||||
result: { content: string; messageType: 'info' | 'error' },
|
||||
context: CommandContext,
|
||||
eventBus: ExecutionEventBus,
|
||||
taskId: string,
|
||||
contextId: string,
|
||||
): CommandExecutionResponse {
|
||||
const statusState = result.messageType === 'error' ? 'failed' : 'completed';
|
||||
const eventType =
|
||||
result.messageType === 'error'
|
||||
? CoderAgentEvent.StateChangeEvent
|
||||
: CoderAgentEvent.TextContentEvent;
|
||||
|
||||
const event: AgentExecutionEvent = {
|
||||
kind: 'status-update',
|
||||
taskId,
|
||||
contextId,
|
||||
status: {
|
||||
state: statusState,
|
||||
message: {
|
||||
kind: 'message',
|
||||
role: 'agent',
|
||||
parts: [{ kind: 'text', text: result.content }],
|
||||
messageId: uuidv4(),
|
||||
taskId,
|
||||
contextId,
|
||||
},
|
||||
timestamp: new Date().toISOString(),
|
||||
},
|
||||
final: true,
|
||||
metadata: {
|
||||
coderAgent: { kind: eventType },
|
||||
model: context.config.getModel(),
|
||||
},
|
||||
};
|
||||
|
||||
logger.info('[EventBus event]: ', event);
|
||||
eventBus.publish(event);
|
||||
return {
|
||||
name: this.name,
|
||||
data: result,
|
||||
};
|
||||
}
|
||||
|
||||
private async handleSubmitPromptResult(
|
||||
result: { content: unknown },
|
||||
context: CommandContext,
|
||||
geminiMdPath: string,
|
||||
eventBus: ExecutionEventBus,
|
||||
taskId: string,
|
||||
contextId: string,
|
||||
): Promise<CommandExecutionResponse> {
|
||||
fs.writeFileSync(geminiMdPath, '', 'utf8');
|
||||
|
||||
if (!context.agentExecutor) {
|
||||
throw new Error('Agent executor not found in context.');
|
||||
}
|
||||
const agentExecutor = context.agentExecutor as CoderAgentExecutor;
|
||||
|
||||
const agentSettings: AgentSettings = {
|
||||
kind: CoderAgentEvent.StateAgentSettingsEvent,
|
||||
workspacePath: process.env['CODER_AGENT_WORKSPACE_PATH']!,
|
||||
autoExecute: true,
|
||||
};
|
||||
|
||||
if (typeof result.content !== 'string') {
|
||||
throw new Error('Init command content must be a string.');
|
||||
}
|
||||
const promptText = result.content;
|
||||
|
||||
const requestContext: RequestContext = {
|
||||
userMessage: {
|
||||
kind: 'message',
|
||||
role: 'user',
|
||||
parts: [{ kind: 'text', text: promptText }],
|
||||
messageId: uuidv4(),
|
||||
taskId,
|
||||
contextId,
|
||||
metadata: {
|
||||
coderAgent: agentSettings,
|
||||
},
|
||||
},
|
||||
taskId,
|
||||
contextId,
|
||||
};
|
||||
|
||||
// The executor will handle the entire agentic loop, including
|
||||
// creating the task, streaming responses, and handling tools.
|
||||
await agentExecutor.execute(requestContext, eventBus);
|
||||
return {
|
||||
name: this.name,
|
||||
data: geminiMdPath,
|
||||
};
|
||||
}
|
||||
|
||||
async execute(
|
||||
context: CommandContext,
|
||||
_args: string[] = [],
|
||||
): Promise<CommandExecutionResponse> {
|
||||
if (!context.eventBus) {
|
||||
return {
|
||||
name: this.name,
|
||||
data: 'Use executeStream to get streaming results.',
|
||||
};
|
||||
}
|
||||
|
||||
const geminiMdPath = path.join(
|
||||
process.env['CODER_AGENT_WORKSPACE_PATH']!,
|
||||
'GEMINI.md',
|
||||
);
|
||||
const result = performInit(fs.existsSync(geminiMdPath));
|
||||
|
||||
const taskId = uuidv4();
|
||||
const contextId = uuidv4();
|
||||
|
||||
switch (result.type) {
|
||||
case 'message':
|
||||
return this.handleMessageResult(
|
||||
result,
|
||||
context,
|
||||
context.eventBus,
|
||||
taskId,
|
||||
contextId,
|
||||
);
|
||||
case 'submit_prompt':
|
||||
return this.handleSubmitPromptResult(
|
||||
result,
|
||||
context,
|
||||
geminiMdPath,
|
||||
context.eventBus,
|
||||
taskId,
|
||||
contextId,
|
||||
);
|
||||
default:
|
||||
throw new Error('Unknown result type from performInit');
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user