mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-23 20:40:41 -07:00
fix(cli): resolve subagent grouping and UI state persistence (#22252)
This commit is contained in:
@@ -207,8 +207,11 @@ describe('LocalSubagentInvocation', () => {
|
||||
),
|
||||
},
|
||||
]);
|
||||
expect(result.returnDisplay).toBe('Analysis complete.');
|
||||
expect(result.returnDisplay).not.toContain('Termination Reason');
|
||||
const display = result.returnDisplay as SubagentProgress;
|
||||
expect(display.isSubagentProgress).toBe(true);
|
||||
expect(display.state).toBe('completed');
|
||||
expect(display.result).toBe('Analysis complete.');
|
||||
expect(display.terminateReason).toBe(AgentTerminateMode.GOAL);
|
||||
});
|
||||
|
||||
it('should show detailed UI for non-goal terminations (e.g., TIMEOUT)', async () => {
|
||||
@@ -220,11 +223,11 @@ describe('LocalSubagentInvocation', () => {
|
||||
|
||||
const result = await invocation.execute(signal, updateOutput);
|
||||
|
||||
expect(result.returnDisplay).toContain(
|
||||
'### Subagent MockAgent Finished Early',
|
||||
);
|
||||
expect(result.returnDisplay).toContain('**Termination Reason:** TIMEOUT');
|
||||
expect(result.returnDisplay).toContain('Partial progress...');
|
||||
const display = result.returnDisplay as SubagentProgress;
|
||||
expect(display.isSubagentProgress).toBe(true);
|
||||
expect(display.state).toBe('completed');
|
||||
expect(display.result).toBe('Partial progress...');
|
||||
expect(display.terminateReason).toBe(AgentTerminateMode.TIMEOUT);
|
||||
});
|
||||
|
||||
it('should stream THOUGHT_CHUNK activities from the executor', async () => {
|
||||
@@ -250,8 +253,8 @@ describe('LocalSubagentInvocation', () => {
|
||||
|
||||
await invocation.execute(signal, updateOutput);
|
||||
|
||||
expect(updateOutput).toHaveBeenCalledTimes(3); // Initial + 2 updates
|
||||
const lastCall = updateOutput.mock.calls[2][0] as SubagentProgress;
|
||||
expect(updateOutput).toHaveBeenCalledTimes(4); // Initial + 2 updates + Final completion
|
||||
const lastCall = updateOutput.mock.calls[3][0] as SubagentProgress;
|
||||
expect(lastCall.recentActivity).toContainEqual(
|
||||
expect.objectContaining({
|
||||
type: 'thought',
|
||||
@@ -283,8 +286,8 @@ describe('LocalSubagentInvocation', () => {
|
||||
|
||||
await invocation.execute(signal, updateOutput);
|
||||
|
||||
expect(updateOutput).toHaveBeenCalledTimes(3);
|
||||
const lastCall = updateOutput.mock.calls[2][0] as SubagentProgress;
|
||||
expect(updateOutput).toHaveBeenCalledTimes(4); // Initial + 2 updates + Final completion
|
||||
const lastCall = updateOutput.mock.calls[3][0] as SubagentProgress;
|
||||
expect(lastCall.recentActivity).toContainEqual(
|
||||
expect.objectContaining({
|
||||
type: 'thought',
|
||||
@@ -312,7 +315,10 @@ describe('LocalSubagentInvocation', () => {
|
||||
// Execute without the optional callback
|
||||
const result = await invocation.execute(signal);
|
||||
expect(result.error).toBeUndefined();
|
||||
expect(result.returnDisplay).toBe('Done');
|
||||
const display = result.returnDisplay as SubagentProgress;
|
||||
expect(display.isSubagentProgress).toBe(true);
|
||||
expect(display.state).toBe('completed');
|
||||
expect(display.result).toBe('Done');
|
||||
});
|
||||
|
||||
it('should handle executor run failure', async () => {
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
import { type AgentLoopContext } from '../config/agent-loop-context.js';
|
||||
import { LocalAgentExecutor } from './local-executor.js';
|
||||
import { safeJsonToMarkdown } from '../utils/markdownUtils.js';
|
||||
import {
|
||||
BaseToolInvocation,
|
||||
type ToolResult,
|
||||
@@ -246,28 +245,27 @@ export class LocalSubagentInvocation extends BaseToolInvocation<
|
||||
throw cancelError;
|
||||
}
|
||||
|
||||
const displayResult = safeJsonToMarkdown(output.result);
|
||||
const progress: SubagentProgress = {
|
||||
isSubagentProgress: true,
|
||||
agentName: this.definition.name,
|
||||
recentActivity: [...recentActivity],
|
||||
state: 'completed',
|
||||
result: output.result,
|
||||
terminateReason: output.terminate_reason,
|
||||
};
|
||||
|
||||
if (updateOutput) {
|
||||
updateOutput(progress);
|
||||
}
|
||||
|
||||
const resultContent = `Subagent '${this.definition.name}' finished.
|
||||
Termination Reason: ${output.terminate_reason}
|
||||
Result:
|
||||
${output.result}`;
|
||||
|
||||
const displayContent =
|
||||
output.terminate_reason === AgentTerminateMode.GOAL
|
||||
? displayResult
|
||||
: `
|
||||
### Subagent ${this.definition.name} Finished Early
|
||||
|
||||
**Termination Reason:** ${output.terminate_reason}
|
||||
|
||||
**Result/Summary:**
|
||||
${displayResult}
|
||||
`;
|
||||
|
||||
return {
|
||||
llmContent: [{ text: resultContent }],
|
||||
returnDisplay: displayContent,
|
||||
returnDisplay: progress,
|
||||
};
|
||||
} catch (error) {
|
||||
const errorMessage =
|
||||
|
||||
@@ -87,6 +87,8 @@ export interface SubagentProgress {
|
||||
agentName: string;
|
||||
recentActivity: SubagentActivityItem[];
|
||||
state?: 'running' | 'completed' | 'error' | 'cancelled';
|
||||
result?: string;
|
||||
terminateReason?: AgentTerminateMode;
|
||||
}
|
||||
|
||||
export function isSubagentProgress(obj: unknown): obj is SubagentProgress {
|
||||
|
||||
@@ -118,6 +118,7 @@ export * from './utils/channel.js';
|
||||
export * from './utils/constants.js';
|
||||
export * from './utils/sessionUtils.js';
|
||||
export * from './utils/cache.js';
|
||||
export * from './utils/markdownUtils.js';
|
||||
|
||||
// Export services
|
||||
export * from './services/fileDiscoveryService.js';
|
||||
|
||||
Reference in New Issue
Block a user