mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-17 08:41:19 -07:00
feat(core): infrastructure for event-driven subagent history (#23914)
This commit is contained in:
@@ -510,5 +510,36 @@ describe('LocalSubagentInvocation', () => {
|
||||
'Operation cancelled by user',
|
||||
);
|
||||
});
|
||||
|
||||
it('should publish SUBAGENT_ACTIVITY events to the MessageBus', async () => {
|
||||
const { MessageBusType } = await import('../confirmation-bus/types.js');
|
||||
|
||||
mockExecutorInstance.run.mockImplementation(async () => {
|
||||
const onActivity = MockLocalAgentExecutor.create.mock.calls[0][2];
|
||||
|
||||
if (onActivity) {
|
||||
onActivity({
|
||||
isSubagentActivityEvent: true,
|
||||
agentName: 'MockAgent',
|
||||
type: 'THOUGHT_CHUNK',
|
||||
data: { text: 'Thinking...' },
|
||||
} as SubagentActivityEvent);
|
||||
}
|
||||
return { result: 'Done', terminate_reason: AgentTerminateMode.GOAL };
|
||||
});
|
||||
|
||||
await invocation.execute(signal, updateOutput);
|
||||
|
||||
expect(mockMessageBus.publish).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
type: MessageBusType.SUBAGENT_ACTIVITY,
|
||||
subagentName: 'Mock Agent',
|
||||
activity: expect.objectContaining({
|
||||
type: 'thought',
|
||||
content: 'Thinking...',
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
import { type AgentLoopContext } from '../config/agent-loop-context.js';
|
||||
import { MessageBusType } from '../confirmation-bus/types.js';
|
||||
import { LocalAgentExecutor } from './local-executor.js';
|
||||
import {
|
||||
BaseToolInvocation,
|
||||
@@ -33,7 +34,6 @@ import {
|
||||
|
||||
const INPUT_PREVIEW_MAX_LENGTH = 50;
|
||||
const DESCRIPTION_MAX_LENGTH = 200;
|
||||
const MAX_RECENT_ACTIVITY = 3;
|
||||
|
||||
/**
|
||||
* Represents a validated, executable instance of a subagent tool.
|
||||
@@ -87,6 +87,14 @@ export class LocalSubagentInvocation extends BaseToolInvocation<
|
||||
return description.slice(0, DESCRIPTION_MAX_LENGTH);
|
||||
}
|
||||
|
||||
private publishActivity(activity: SubagentActivityItem): void {
|
||||
void this.messageBus.publish({
|
||||
type: MessageBusType.SUBAGENT_ACTIVITY,
|
||||
subagentName: this.definition.displayName ?? this.definition.name,
|
||||
activity,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the subagent.
|
||||
*
|
||||
@@ -99,7 +107,7 @@ export class LocalSubagentInvocation extends BaseToolInvocation<
|
||||
signal: AbortSignal,
|
||||
updateOutput?: (output: ToolLiveOutput) => void,
|
||||
): Promise<ToolResult> {
|
||||
let recentActivity: SubagentActivityItem[] = [];
|
||||
const recentActivity: SubagentActivityItem[] = [];
|
||||
|
||||
try {
|
||||
if (updateOutput) {
|
||||
@@ -140,6 +148,11 @@ export class LocalSubagentInvocation extends BaseToolInvocation<
|
||||
});
|
||||
}
|
||||
updated = true;
|
||||
|
||||
const latestThought = recentActivity[recentActivity.length - 1];
|
||||
if (latestThought) {
|
||||
this.publishActivity(latestThought);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'TOOL_CALL_START': {
|
||||
@@ -163,6 +176,11 @@ export class LocalSubagentInvocation extends BaseToolInvocation<
|
||||
status: 'running',
|
||||
});
|
||||
updated = true;
|
||||
|
||||
const latestTool = recentActivity[recentActivity.length - 1];
|
||||
if (latestTool) {
|
||||
this.publishActivity(latestTool);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'TOOL_CALL_END': {
|
||||
@@ -178,6 +196,8 @@ export class LocalSubagentInvocation extends BaseToolInvocation<
|
||||
) {
|
||||
recentActivity[i].status = isError ? 'error' : 'completed';
|
||||
updated = true;
|
||||
|
||||
this.publishActivity(recentActivity[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -242,11 +262,6 @@ export class LocalSubagentInvocation extends BaseToolInvocation<
|
||||
}
|
||||
|
||||
if (updated) {
|
||||
// Keep only the last N items
|
||||
if (recentActivity.length > MAX_RECENT_ACTIVITY) {
|
||||
recentActivity = recentActivity.slice(-MAX_RECENT_ACTIVITY);
|
||||
}
|
||||
|
||||
const progress: SubagentProgress = {
|
||||
isSubagentProgress: true,
|
||||
agentName: this.definition.name,
|
||||
@@ -332,9 +347,7 @@ ${output.result}`;
|
||||
status: 'error',
|
||||
});
|
||||
// Maintain size limit
|
||||
if (recentActivity.length > MAX_RECENT_ACTIVITY) {
|
||||
recentActivity = recentActivity.slice(-MAX_RECENT_ACTIVITY);
|
||||
}
|
||||
// No limit on UI events sent via bus
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import type {
|
||||
} from '../tools/tools.js';
|
||||
import type { ToolCall } from '../scheduler/types.js';
|
||||
import type { SandboxPermissions } from '../services/sandboxManager.js';
|
||||
import type { SubagentActivityItem } from '../agents/types.js';
|
||||
|
||||
export enum MessageBusType {
|
||||
TOOL_CONFIRMATION_REQUEST = 'tool-confirmation-request',
|
||||
@@ -23,6 +24,7 @@ export enum MessageBusType {
|
||||
TOOL_CALLS_UPDATE = 'tool-calls-update',
|
||||
ASK_USER_REQUEST = 'ask-user-request',
|
||||
ASK_USER_RESPONSE = 'ask-user-response',
|
||||
SUBAGENT_ACTIVITY = 'subagent-activity',
|
||||
}
|
||||
|
||||
export interface ToolCallsUpdateMessage {
|
||||
@@ -207,6 +209,12 @@ export interface AskUserResponse {
|
||||
cancelled?: boolean;
|
||||
}
|
||||
|
||||
export interface SubagentActivityMessage {
|
||||
type: MessageBusType.SUBAGENT_ACTIVITY;
|
||||
subagentName: string;
|
||||
activity: SubagentActivityItem;
|
||||
}
|
||||
|
||||
export type Message =
|
||||
| ToolConfirmationRequest
|
||||
| ToolConfirmationResponse
|
||||
@@ -216,4 +224,5 @@ export type Message =
|
||||
| UpdatePolicy
|
||||
| AskUserRequest
|
||||
| AskUserResponse
|
||||
| ToolCallsUpdateMessage;
|
||||
| ToolCallsUpdateMessage
|
||||
| SubagentActivityMessage;
|
||||
|
||||
@@ -22,7 +22,7 @@ export class MockMessageBus {
|
||||
/**
|
||||
* Mock publish method that captures messages and simulates responses
|
||||
*/
|
||||
publish = vi.fn((message: Message) => {
|
||||
publish = vi.fn(async (message: Message) => {
|
||||
this.publishedMessages.push(message);
|
||||
|
||||
// Handle tool confirmation requests
|
||||
|
||||
Reference in New Issue
Block a user