mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-10 14:10:37 -07:00
feat(core): add support for MCP progress updates (#19046)
This commit is contained in:
@@ -320,4 +320,31 @@ describe('<ToolMessage />', () => {
|
||||
);
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders progress information appended to description for executing tools', () => {
|
||||
const { lastFrame } = renderWithContext(
|
||||
<ToolMessage
|
||||
{...baseProps}
|
||||
status={CoreToolCallStatus.Executing}
|
||||
progressMessage="Working on it..."
|
||||
progressPercent={42}
|
||||
/>,
|
||||
StreamingState.Responding,
|
||||
);
|
||||
expect(lastFrame()).toContain(
|
||||
'A tool for testing (Working on it... - 42%)',
|
||||
);
|
||||
});
|
||||
|
||||
it('renders only percentage when progressMessage is missing', () => {
|
||||
const { lastFrame } = renderWithContext(
|
||||
<ToolMessage
|
||||
{...baseProps}
|
||||
status={CoreToolCallStatus.Executing}
|
||||
progressPercent={75}
|
||||
/>,
|
||||
StreamingState.Responding,
|
||||
);
|
||||
expect(lastFrame()).toContain('A tool for testing (75%)');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -55,6 +55,8 @@ export const ToolMessage: React.FC<ToolMessageProps> = ({
|
||||
embeddedShellFocused,
|
||||
ptyId,
|
||||
config,
|
||||
progressMessage,
|
||||
progressPercent,
|
||||
}) => {
|
||||
const isThisShellFocused = checkIsShellFocused(
|
||||
name,
|
||||
@@ -89,6 +91,8 @@ export const ToolMessage: React.FC<ToolMessageProps> = ({
|
||||
status={status}
|
||||
description={description}
|
||||
emphasis={emphasis}
|
||||
progressMessage={progressMessage}
|
||||
progressPercent={progressPercent}
|
||||
/>
|
||||
<FocusHint
|
||||
shouldShowFocusHint={shouldShowFocusHint}
|
||||
|
||||
@@ -183,6 +183,8 @@ type ToolInfoProps = {
|
||||
description: string;
|
||||
status: CoreToolCallStatus;
|
||||
emphasis: TextEmphasis;
|
||||
progressMessage?: string;
|
||||
progressPercent?: number;
|
||||
};
|
||||
|
||||
export const ToolInfo: React.FC<ToolInfoProps> = ({
|
||||
@@ -190,6 +192,8 @@ export const ToolInfo: React.FC<ToolInfoProps> = ({
|
||||
description,
|
||||
status: coreStatus,
|
||||
emphasis,
|
||||
progressMessage,
|
||||
progressPercent,
|
||||
}) => {
|
||||
const status = mapCoreStatusToDisplayStatus(coreStatus);
|
||||
const nameColor = React.useMemo<string>(() => {
|
||||
@@ -210,6 +214,24 @@ export const ToolInfo: React.FC<ToolInfoProps> = ({
|
||||
// Hide description for completed Ask User tools (the result display speaks for itself)
|
||||
const isCompletedAskUser = isCompletedAskUserTool(name, status);
|
||||
|
||||
let displayDescription = description;
|
||||
if (status === ToolCallStatus.Executing) {
|
||||
const parts: string[] = [];
|
||||
if (progressMessage) {
|
||||
parts.push(progressMessage);
|
||||
}
|
||||
if (progressPercent !== undefined) {
|
||||
parts.push(`${Math.round(progressPercent)}%`);
|
||||
}
|
||||
|
||||
if (parts.length > 0) {
|
||||
const progressInfo = parts.join(' - ');
|
||||
displayDescription = description
|
||||
? `${description} (${progressInfo})`
|
||||
: progressInfo;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Box overflow="hidden" height={1} flexGrow={1} flexShrink={1}>
|
||||
<Text strikethrough={status === ToolCallStatus.Canceled} wrap="truncate">
|
||||
@@ -219,7 +241,7 @@ export const ToolInfo: React.FC<ToolInfoProps> = ({
|
||||
{!isCompletedAskUser && (
|
||||
<>
|
||||
{' '}
|
||||
<Text color={theme.text.secondary}>{description}</Text>
|
||||
<Text color={theme.text.secondary}>{displayDescription}</Text>
|
||||
</>
|
||||
)}
|
||||
</Text>
|
||||
|
||||
@@ -59,6 +59,8 @@ export function mapToDisplay(
|
||||
let outputFile: string | undefined = undefined;
|
||||
let ptyId: number | undefined = undefined;
|
||||
let correlationId: string | undefined = undefined;
|
||||
let progressMessage: string | undefined = undefined;
|
||||
let progressPercent: number | undefined = undefined;
|
||||
|
||||
switch (call.status) {
|
||||
case CoreToolCallStatus.Success:
|
||||
@@ -77,6 +79,8 @@ export function mapToDisplay(
|
||||
case CoreToolCallStatus.Executing:
|
||||
resultDisplay = call.liveOutput;
|
||||
ptyId = call.pid;
|
||||
progressMessage = call.progressMessage;
|
||||
progressPercent = call.progressPercent;
|
||||
break;
|
||||
case CoreToolCallStatus.Scheduled:
|
||||
case CoreToolCallStatus.Validating:
|
||||
@@ -100,6 +104,8 @@ export function mapToDisplay(
|
||||
outputFile,
|
||||
ptyId,
|
||||
correlationId,
|
||||
progressMessage,
|
||||
progressPercent,
|
||||
approvalMode: call.approvalMode,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -104,6 +104,8 @@ export function useToolScheduler(
|
||||
[config, messageBus],
|
||||
);
|
||||
|
||||
useEffect(() => () => scheduler.dispose(), [scheduler]);
|
||||
|
||||
const internalAdaptToolCalls = useCallback(
|
||||
(coreCalls: ToolCall[], prevTracked: TrackedToolCall[]) =>
|
||||
adaptToolCalls(coreCalls, prevTracked),
|
||||
|
||||
@@ -108,6 +108,8 @@ export interface IndividualToolCallDisplay {
|
||||
outputFile?: string;
|
||||
correlationId?: string;
|
||||
approvalMode?: ApprovalMode;
|
||||
progressMessage?: string;
|
||||
progressPercent?: number;
|
||||
}
|
||||
|
||||
export interface CompressionProps {
|
||||
|
||||
Reference in New Issue
Block a user