mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-12 23:21:27 -07:00
feat(core): experimental in-progress steering hints (2 of 2) (#19307)
This commit is contained in:
@@ -45,6 +45,18 @@ describe('<HistoryItemDisplay />', () => {
|
||||
expect(lastFrame()).toContain('Hello');
|
||||
});
|
||||
|
||||
it('renders HintMessage for "hint" type', () => {
|
||||
const item: HistoryItem = {
|
||||
...baseItem,
|
||||
type: 'hint',
|
||||
text: 'Try using ripgrep first',
|
||||
};
|
||||
const { lastFrame } = renderWithProviders(
|
||||
<HistoryItemDisplay {...baseItem} item={item} />,
|
||||
);
|
||||
expect(lastFrame()).toContain('Try using ripgrep first');
|
||||
});
|
||||
|
||||
it('renders UserMessage for "user" type with slash command', () => {
|
||||
const item: HistoryItem = {
|
||||
...baseItem,
|
||||
|
||||
@@ -35,6 +35,7 @@ import { ChatList } from './views/ChatList.js';
|
||||
import { HooksList } from './views/HooksList.js';
|
||||
import { ModelMessage } from './messages/ModelMessage.js';
|
||||
import { ThinkingMessage } from './messages/ThinkingMessage.js';
|
||||
import { HintMessage } from './messages/HintMessage.js';
|
||||
import { getInlineThinkingMode } from '../utils/inlineThinkingMode.js';
|
||||
import { useSettings } from '../contexts/SettingsContext.js';
|
||||
|
||||
@@ -65,6 +66,9 @@ export const HistoryItemDisplay: React.FC<HistoryItemDisplayProps> = ({
|
||||
{itemForDisplay.type === 'thinking' && inlineThinkingMode !== 'off' && (
|
||||
<ThinkingMessage thought={itemForDisplay.thought} />
|
||||
)}
|
||||
{itemForDisplay.type === 'hint' && (
|
||||
<HintMessage text={itemForDisplay.text} />
|
||||
)}
|
||||
{itemForDisplay.type === 'user' && (
|
||||
<UserMessage text={itemForDisplay.text} width={terminalWidth} />
|
||||
)}
|
||||
@@ -96,6 +100,7 @@ export const HistoryItemDisplay: React.FC<HistoryItemDisplayProps> = ({
|
||||
text={itemForDisplay.text}
|
||||
icon={itemForDisplay.icon}
|
||||
color={itemForDisplay.color}
|
||||
marginBottom={itemForDisplay.marginBottom}
|
||||
/>
|
||||
)}
|
||||
{itemForDisplay.type === 'warning' && (
|
||||
|
||||
@@ -226,6 +226,7 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
|
||||
backgroundShells,
|
||||
backgroundShellHeight,
|
||||
shortcutsHelpVisible,
|
||||
hintMode,
|
||||
} = useUIState();
|
||||
const [suppressCompletion, setSuppressCompletion] = useState(false);
|
||||
const { handlePress: registerPlainTabPress, resetCount: resetPlainTabPress } =
|
||||
@@ -267,7 +268,7 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
|
||||
]);
|
||||
const [expandedSuggestionIndex, setExpandedSuggestionIndex] =
|
||||
useState<number>(-1);
|
||||
const shellHistory = useShellHistory(config.getProjectRoot());
|
||||
const shellHistory = useShellHistory(config.getProjectRoot(), config.storage);
|
||||
const shellHistoryData = shellHistory.history;
|
||||
|
||||
const completion = useCommandCompletion({
|
||||
@@ -1420,7 +1421,9 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
|
||||
/>
|
||||
) : null}
|
||||
<HalfLinePaddedBox
|
||||
backgroundBaseColor={theme.text.secondary}
|
||||
backgroundBaseColor={
|
||||
hintMode ? theme.text.accent : theme.text.secondary
|
||||
}
|
||||
backgroundOpacity={
|
||||
showCursor
|
||||
? DEFAULT_INPUT_BACKGROUND_OPACITY
|
||||
|
||||
53
packages/cli/src/ui/components/messages/HintMessage.tsx
Normal file
53
packages/cli/src/ui/components/messages/HintMessage.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2026 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import type React from 'react';
|
||||
import { Text, Box } from 'ink';
|
||||
import { theme } from '../../semantic-colors.js';
|
||||
import { SCREEN_READER_USER_PREFIX } from '../../textConstants.js';
|
||||
import { HalfLinePaddedBox } from '../shared/HalfLinePaddedBox.js';
|
||||
import { useConfig } from '../../contexts/ConfigContext.js';
|
||||
|
||||
interface HintMessageProps {
|
||||
text: string;
|
||||
}
|
||||
|
||||
export const HintMessage: React.FC<HintMessageProps> = ({ text }) => {
|
||||
const prefix = '💡 ';
|
||||
const prefixWidth = prefix.length;
|
||||
const config = useConfig();
|
||||
const useBackgroundColor = config.getUseBackgroundColor();
|
||||
|
||||
return (
|
||||
<HalfLinePaddedBox
|
||||
backgroundBaseColor={theme.text.accent}
|
||||
backgroundOpacity={0.1}
|
||||
useBackgroundColor={useBackgroundColor}
|
||||
>
|
||||
<Box
|
||||
flexDirection="row"
|
||||
paddingY={0}
|
||||
marginY={useBackgroundColor ? 0 : 1}
|
||||
paddingX={useBackgroundColor ? 1 : 0}
|
||||
alignSelf="flex-start"
|
||||
>
|
||||
<Box width={prefixWidth} flexShrink={0}>
|
||||
<Text
|
||||
color={theme.text.accent}
|
||||
aria-label={SCREEN_READER_USER_PREFIX}
|
||||
>
|
||||
{prefix}
|
||||
</Text>
|
||||
</Box>
|
||||
<Box flexGrow={1}>
|
||||
<Text wrap="wrap" italic color={theme.text.accent}>
|
||||
{`Steering Hint: ${text}`}
|
||||
</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
</HalfLinePaddedBox>
|
||||
);
|
||||
};
|
||||
@@ -13,19 +13,21 @@ interface InfoMessageProps {
|
||||
text: string;
|
||||
icon?: string;
|
||||
color?: string;
|
||||
marginBottom?: number;
|
||||
}
|
||||
|
||||
export const InfoMessage: React.FC<InfoMessageProps> = ({
|
||||
text,
|
||||
icon,
|
||||
color,
|
||||
marginBottom,
|
||||
}) => {
|
||||
color ??= theme.status.warning;
|
||||
const prefix = icon ?? 'ℹ ';
|
||||
const prefixWidth = prefix.length;
|
||||
|
||||
return (
|
||||
<Box flexDirection="row" marginTop={1}>
|
||||
<Box flexDirection="row" marginTop={1} marginBottom={marginBottom ?? 0}>
|
||||
<Box width={prefixWidth}>
|
||||
<Text color={color}>{prefix}</Text>
|
||||
</Box>
|
||||
|
||||
Reference in New Issue
Block a user