mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-08 04:10:35 -07:00
138 lines
4.1 KiB
TypeScript
138 lines
4.1 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2025 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
import type { Config } from '../config/config.js';
|
|
import { LocalAgentExecutor } from './local-executor.js';
|
|
import type { AnsiOutput } from '../utils/terminalSerializer.js';
|
|
import { BaseToolInvocation, type ToolResult } from '../tools/tools.js';
|
|
import { ToolErrorType } from '../tools/tool-error.js';
|
|
import type {
|
|
LocalAgentDefinition,
|
|
AgentInputs,
|
|
SubagentActivityEvent,
|
|
} from './types.js';
|
|
import type { MessageBus } from '../confirmation-bus/message-bus.js';
|
|
|
|
const INPUT_PREVIEW_MAX_LENGTH = 50;
|
|
const DESCRIPTION_MAX_LENGTH = 200;
|
|
|
|
/**
|
|
* Represents a validated, executable instance of a subagent tool.
|
|
*
|
|
* This class orchestrates the execution of a defined agent by:
|
|
* 1. Initializing the {@link LocalAgentExecutor}.
|
|
* 2. Running the agent's execution loop.
|
|
* 3. Bridging the agent's streaming activity (e.g., thoughts) to the tool's
|
|
* live output stream.
|
|
* 4. Formatting the final result into a {@link ToolResult}.
|
|
*/
|
|
export class LocalSubagentInvocation extends BaseToolInvocation<
|
|
AgentInputs,
|
|
ToolResult
|
|
> {
|
|
/**
|
|
* @param definition The definition object that configures the agent.
|
|
* @param config The global runtime configuration.
|
|
* @param params The validated input parameters for the agent.
|
|
* @param messageBus Optional message bus for policy enforcement.
|
|
*/
|
|
constructor(
|
|
private readonly definition: LocalAgentDefinition,
|
|
private readonly config: Config,
|
|
params: AgentInputs,
|
|
messageBus?: MessageBus,
|
|
) {
|
|
super(params, messageBus, definition.name, definition.displayName);
|
|
}
|
|
|
|
/**
|
|
* Returns a concise, human-readable description of the invocation.
|
|
* Used for logging and display purposes.
|
|
*/
|
|
getDescription(): string {
|
|
const inputSummary = Object.entries(this.params)
|
|
.map(
|
|
([key, value]) =>
|
|
`${key}: ${String(value).slice(0, INPUT_PREVIEW_MAX_LENGTH)}`,
|
|
)
|
|
.join(', ');
|
|
|
|
const description = `Running subagent '${this.definition.name}' with inputs: { ${inputSummary} }`;
|
|
return description.slice(0, DESCRIPTION_MAX_LENGTH);
|
|
}
|
|
|
|
/**
|
|
* Executes the subagent.
|
|
*
|
|
* @param signal An `AbortSignal` to cancel the agent's execution.
|
|
* @param updateOutput A callback to stream intermediate output, such as the
|
|
* agent's thoughts, to the user interface.
|
|
* @returns A `Promise` that resolves with the final `ToolResult`.
|
|
*/
|
|
async execute(
|
|
signal: AbortSignal,
|
|
updateOutput?: (output: string | AnsiOutput) => void,
|
|
): Promise<ToolResult> {
|
|
try {
|
|
if (updateOutput) {
|
|
updateOutput('Subagent starting...\n');
|
|
}
|
|
|
|
// Create an activity callback to bridge the executor's events to the
|
|
// tool's streaming output.
|
|
const onActivity = (activity: SubagentActivityEvent): void => {
|
|
if (!updateOutput) return;
|
|
|
|
if (
|
|
activity.type === 'THOUGHT_CHUNK' &&
|
|
typeof activity.data['text'] === 'string'
|
|
) {
|
|
updateOutput(`🤖💭 ${activity.data['text']}`);
|
|
}
|
|
};
|
|
|
|
const executor = await LocalAgentExecutor.create(
|
|
this.definition,
|
|
this.config,
|
|
onActivity,
|
|
);
|
|
|
|
const output = await executor.run(this.params, signal);
|
|
|
|
const resultContent = `Subagent '${this.definition.name}' finished.
|
|
Termination Reason: ${output.terminate_reason}
|
|
Result:
|
|
${output.result}`;
|
|
|
|
const displayContent = `
|
|
Subagent ${this.definition.name} Finished
|
|
|
|
Termination Reason:\n ${output.terminate_reason}
|
|
|
|
Result:
|
|
${output.result}
|
|
`;
|
|
|
|
return {
|
|
llmContent: [{ text: resultContent }],
|
|
returnDisplay: displayContent,
|
|
};
|
|
} catch (error) {
|
|
const errorMessage =
|
|
error instanceof Error ? error.message : String(error);
|
|
|
|
return {
|
|
llmContent: `Subagent '${this.definition.name}' failed. Error: ${errorMessage}`,
|
|
returnDisplay: `Subagent Failed: ${this.definition.name}\nError: ${errorMessage}`,
|
|
error: {
|
|
message: errorMessage,
|
|
type: ToolErrorType.EXECUTION_FAILED,
|
|
},
|
|
};
|
|
}
|
|
}
|
|
}
|