mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-12 12:54:07 -07:00
Show inline thoughts as individual bubbles
This commit is contained in:
@@ -380,7 +380,25 @@ const SETTINGS_SCHEMA = {
|
|||||||
requiresRestart: false,
|
requiresRestart: false,
|
||||||
default: false,
|
default: false,
|
||||||
description:
|
description:
|
||||||
'Show model thinking summaries inline in the conversation.',
|
'Show model thinking summaries inline in the conversation (deprecated; prefer the specific thinking modes).',
|
||||||
|
showInDialog: true,
|
||||||
|
},
|
||||||
|
showInlineThinkingFull: {
|
||||||
|
type: 'boolean',
|
||||||
|
label: 'Show Inline Thinking (Full)',
|
||||||
|
category: 'UI',
|
||||||
|
requiresRestart: false,
|
||||||
|
default: false,
|
||||||
|
description: 'Show full model thinking details inline.',
|
||||||
|
showInDialog: true,
|
||||||
|
},
|
||||||
|
showInlineThinkingSummary: {
|
||||||
|
type: 'boolean',
|
||||||
|
label: 'Show Inline Thinking (Summary)',
|
||||||
|
category: 'UI',
|
||||||
|
requiresRestart: false,
|
||||||
|
default: false,
|
||||||
|
description: 'Show a short summary of model thinking inline.',
|
||||||
showInDialog: true,
|
showInDialog: true,
|
||||||
},
|
},
|
||||||
showStatusInTitle: {
|
showStatusInTitle: {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
import { Box, Text } from 'ink';
|
import { Box, Text } from 'ink';
|
||||||
import { useUIState } from '../contexts/UIStateContext.js';
|
import { useUIState } from '../contexts/UIStateContext.js';
|
||||||
|
import { useSettings } from '../contexts/SettingsContext.js';
|
||||||
import { AppHeader } from './AppHeader.js';
|
import { AppHeader } from './AppHeader.js';
|
||||||
import { HistoryItemDisplay } from './HistoryItemDisplay.js';
|
import { HistoryItemDisplay } from './HistoryItemDisplay.js';
|
||||||
import { QuittingDisplay } from './QuittingDisplay.js';
|
import { QuittingDisplay } from './QuittingDisplay.js';
|
||||||
@@ -15,15 +16,18 @@ import { useConfirmingTool } from '../hooks/useConfirmingTool.js';
|
|||||||
import { useConfig } from '../contexts/ConfigContext.js';
|
import { useConfig } from '../contexts/ConfigContext.js';
|
||||||
import { ToolStatusIndicator, ToolInfo } from './messages/ToolShared.js';
|
import { ToolStatusIndicator, ToolInfo } from './messages/ToolShared.js';
|
||||||
import { theme } from '../semantic-colors.js';
|
import { theme } from '../semantic-colors.js';
|
||||||
|
import { getInlineThinkingMode } from '../utils/inlineThinkingMode.js';
|
||||||
|
|
||||||
export const AlternateBufferQuittingDisplay = () => {
|
export const AlternateBufferQuittingDisplay = () => {
|
||||||
const { version } = useAppContext();
|
const { version } = useAppContext();
|
||||||
const uiState = useUIState();
|
const uiState = useUIState();
|
||||||
|
const settings = useSettings();
|
||||||
const config = useConfig();
|
const config = useConfig();
|
||||||
|
|
||||||
const confirmingTool = useConfirmingTool();
|
const confirmingTool = useConfirmingTool();
|
||||||
const showPromptedTool =
|
const showPromptedTool =
|
||||||
config.isEventDrivenSchedulerEnabled() && confirmingTool !== null;
|
config.isEventDrivenSchedulerEnabled() && confirmingTool !== null;
|
||||||
|
const inlineEnabled = getInlineThinkingMode(settings) !== 'off';
|
||||||
|
|
||||||
// We render the entire chat history and header here to ensure that the
|
// We render the entire chat history and header here to ensure that the
|
||||||
// conversation history is visible to the user after the app quits and the
|
// conversation history is visible to the user after the app quits and the
|
||||||
@@ -47,6 +51,7 @@ export const AlternateBufferQuittingDisplay = () => {
|
|||||||
item={h}
|
item={h}
|
||||||
isPending={false}
|
isPending={false}
|
||||||
commands={uiState.slashCommands}
|
commands={uiState.slashCommands}
|
||||||
|
inlineEnabled={inlineEnabled}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
{uiState.pendingHistoryItems.map((item, i) => (
|
{uiState.pendingHistoryItems.map((item, i) => (
|
||||||
@@ -59,6 +64,7 @@ export const AlternateBufferQuittingDisplay = () => {
|
|||||||
isFocused={false}
|
isFocused={false}
|
||||||
activeShellPtyId={uiState.activePtyId}
|
activeShellPtyId={uiState.activePtyId}
|
||||||
embeddedShellFocused={uiState.embeddedShellFocused}
|
embeddedShellFocused={uiState.embeddedShellFocused}
|
||||||
|
inlineEnabled={inlineEnabled}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
{showPromptedTool && (
|
{showPromptedTool && (
|
||||||
|
|||||||
@@ -237,7 +237,7 @@ describe('<HistoryItemDisplay />', () => {
|
|||||||
const item: HistoryItem = {
|
const item: HistoryItem = {
|
||||||
...baseItem,
|
...baseItem,
|
||||||
type: 'thinking',
|
type: 'thinking',
|
||||||
thoughts: [{ subject: 'Thinking', description: 'test' }],
|
thought: { subject: 'Thinking', description: 'test' },
|
||||||
};
|
};
|
||||||
const { lastFrame } = renderWithProviders(
|
const { lastFrame } = renderWithProviders(
|
||||||
<HistoryItemDisplay {...baseItem} item={item} inlineEnabled={true} />,
|
<HistoryItemDisplay {...baseItem} item={item} inlineEnabled={true} />,
|
||||||
@@ -250,7 +250,7 @@ describe('<HistoryItemDisplay />', () => {
|
|||||||
const item: HistoryItem = {
|
const item: HistoryItem = {
|
||||||
...baseItem,
|
...baseItem,
|
||||||
type: 'thinking',
|
type: 'thinking',
|
||||||
thoughts: [{ subject: 'Thinking', description: 'test' }],
|
thought: { subject: 'Thinking', description: 'test' },
|
||||||
};
|
};
|
||||||
const { lastFrame } = renderWithProviders(
|
const { lastFrame } = renderWithProviders(
|
||||||
<HistoryItemDisplay {...baseItem} item={item} inlineEnabled={false} />,
|
<HistoryItemDisplay {...baseItem} item={item} inlineEnabled={false} />,
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ export const HistoryItemDisplay: React.FC<HistoryItemDisplayProps> = ({
|
|||||||
{/* Render standard message types */}
|
{/* Render standard message types */}
|
||||||
{itemForDisplay.type === 'thinking' && inlineEnabled && (
|
{itemForDisplay.type === 'thinking' && inlineEnabled && (
|
||||||
<ThinkingMessage
|
<ThinkingMessage
|
||||||
thoughts={itemForDisplay.thoughts}
|
thought={itemForDisplay.thought}
|
||||||
terminalWidth={terminalWidth}
|
terminalWidth={terminalWidth}
|
||||||
availableTerminalHeight={
|
availableTerminalHeight={
|
||||||
isPending ? availableTerminalHeight : undefined
|
isPending ? availableTerminalHeight : undefined
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import { MAX_GEMINI_MESSAGE_LINES } from '../constants.js';
|
|||||||
import { useConfirmingTool } from '../hooks/useConfirmingTool.js';
|
import { useConfirmingTool } from '../hooks/useConfirmingTool.js';
|
||||||
import { ToolConfirmationQueue } from './ToolConfirmationQueue.js';
|
import { ToolConfirmationQueue } from './ToolConfirmationQueue.js';
|
||||||
import { useConfig } from '../contexts/ConfigContext.js';
|
import { useConfig } from '../contexts/ConfigContext.js';
|
||||||
|
import { getInlineThinkingMode } from '../utils/inlineThinkingMode.js';
|
||||||
|
|
||||||
const MemoizedHistoryItemDisplay = memo(HistoryItemDisplay);
|
const MemoizedHistoryItemDisplay = memo(HistoryItemDisplay);
|
||||||
const MemoizedAppHeader = memo(AppHeader);
|
const MemoizedAppHeader = memo(AppHeader);
|
||||||
@@ -55,7 +56,7 @@ export const MainContent = () => {
|
|||||||
availableTerminalHeight,
|
availableTerminalHeight,
|
||||||
} = uiState;
|
} = uiState;
|
||||||
|
|
||||||
const inlineEnabled = settings.merged.ui?.showInlineThinking;
|
const inlineEnabled = getInlineThinkingMode(settings) !== 'off';
|
||||||
|
|
||||||
const historyItems = useMemo(
|
const historyItems = useMemo(
|
||||||
() =>
|
() =>
|
||||||
|
|||||||
@@ -12,6 +12,17 @@ import { useUIState, type UIState } from '../contexts/UIStateContext.js';
|
|||||||
import { useTerminalSize } from '../hooks/useTerminalSize.js';
|
import { useTerminalSize } from '../hooks/useTerminalSize.js';
|
||||||
|
|
||||||
vi.mock('../contexts/UIStateContext.js');
|
vi.mock('../contexts/UIStateContext.js');
|
||||||
|
vi.mock('../contexts/SettingsContext.js', () => ({
|
||||||
|
useSettings: () => ({
|
||||||
|
merged: {
|
||||||
|
ui: {
|
||||||
|
showInlineThinking: false,
|
||||||
|
showInlineThinkingFull: false,
|
||||||
|
showInlineThinkingSummary: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}));
|
||||||
vi.mock('../hooks/useTerminalSize.js');
|
vi.mock('../hooks/useTerminalSize.js');
|
||||||
vi.mock('./HistoryItemDisplay.js', async () => {
|
vi.mock('./HistoryItemDisplay.js', async () => {
|
||||||
const { Text } = await vi.importActual('ink');
|
const { Text } = await vi.importActual('ink');
|
||||||
|
|||||||
@@ -6,14 +6,18 @@
|
|||||||
|
|
||||||
import { Box } from 'ink';
|
import { Box } from 'ink';
|
||||||
import { useUIState } from '../contexts/UIStateContext.js';
|
import { useUIState } from '../contexts/UIStateContext.js';
|
||||||
|
import { useSettings } from '../contexts/SettingsContext.js';
|
||||||
import { HistoryItemDisplay } from './HistoryItemDisplay.js';
|
import { HistoryItemDisplay } from './HistoryItemDisplay.js';
|
||||||
import { useTerminalSize } from '../hooks/useTerminalSize.js';
|
import { useTerminalSize } from '../hooks/useTerminalSize.js';
|
||||||
|
import { getInlineThinkingMode } from '../utils/inlineThinkingMode.js';
|
||||||
|
|
||||||
export const QuittingDisplay = () => {
|
export const QuittingDisplay = () => {
|
||||||
const uiState = useUIState();
|
const uiState = useUIState();
|
||||||
|
const settings = useSettings();
|
||||||
const { rows: terminalHeight, columns: terminalWidth } = useTerminalSize();
|
const { rows: terminalHeight, columns: terminalWidth } = useTerminalSize();
|
||||||
|
|
||||||
const availableTerminalHeight = terminalHeight;
|
const availableTerminalHeight = terminalHeight;
|
||||||
|
const inlineEnabled = getInlineThinkingMode(settings) !== 'off';
|
||||||
|
|
||||||
if (!uiState.quittingMessages) {
|
if (!uiState.quittingMessages) {
|
||||||
return null;
|
return null;
|
||||||
@@ -30,6 +34,7 @@ export const QuittingDisplay = () => {
|
|||||||
terminalWidth={terminalWidth}
|
terminalWidth={terminalWidth}
|
||||||
item={item}
|
item={item}
|
||||||
isPending={false}
|
isPending={false}
|
||||||
|
inlineEnabled={inlineEnabled}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -9,38 +9,35 @@ import { render } from '../../../test-utils/render.js';
|
|||||||
import { ThinkingMessage } from './ThinkingMessage.js';
|
import { ThinkingMessage } from './ThinkingMessage.js';
|
||||||
|
|
||||||
describe('ThinkingMessage', () => {
|
describe('ThinkingMessage', () => {
|
||||||
it('renders thinking header with count', () => {
|
it('renders thinking header', () => {
|
||||||
const { lastFrame } = render(
|
const { lastFrame } = render(
|
||||||
<ThinkingMessage
|
<ThinkingMessage
|
||||||
thoughts={[
|
thought={{ subject: 'Planning', description: 'test' }}
|
||||||
{ subject: 'Planning', description: 'test' },
|
|
||||||
{ subject: 'Analyzing', description: 'test' },
|
|
||||||
]}
|
|
||||||
terminalWidth={80}
|
terminalWidth={80}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(lastFrame()).toContain('Thinking');
|
expect(lastFrame()).toContain('Thinking');
|
||||||
expect(lastFrame()).toContain('(2)');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders with single thought', () => {
|
it('renders with thought subject', () => {
|
||||||
const { lastFrame } = render(
|
const { lastFrame } = render(
|
||||||
<ThinkingMessage
|
<ThinkingMessage
|
||||||
thoughts={[{ subject: 'Processing', description: 'test' }]}
|
thought={{ subject: 'Processing', description: 'test' }}
|
||||||
terminalWidth={80}
|
terminalWidth={80}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(lastFrame()).toContain('(1)');
|
expect(lastFrame()).toContain('Processing');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders thought content', () => {
|
it('renders thought content', () => {
|
||||||
const { lastFrame } = render(
|
const { lastFrame } = render(
|
||||||
<ThinkingMessage
|
<ThinkingMessage
|
||||||
thoughts={[
|
thought={{
|
||||||
{ subject: 'Planning', description: 'I am planning the solution.' },
|
subject: 'Planning',
|
||||||
]}
|
description: 'I am planning the solution.',
|
||||||
|
}}
|
||||||
terminalWidth={80}
|
terminalWidth={80}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
@@ -51,9 +48,12 @@ describe('ThinkingMessage', () => {
|
|||||||
|
|
||||||
it('renders empty state gracefully', () => {
|
it('renders empty state gracefully', () => {
|
||||||
const { lastFrame } = render(
|
const { lastFrame } = render(
|
||||||
<ThinkingMessage thoughts={[]} terminalWidth={80} />,
|
<ThinkingMessage
|
||||||
|
thought={{ subject: '', description: '' }}
|
||||||
|
terminalWidth={80}
|
||||||
|
/>,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(lastFrame()).toContain('(0)');
|
expect(lastFrame()).toContain('Thinking');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -10,16 +10,18 @@ import type { ThoughtSummary } from '@google/gemini-cli-core';
|
|||||||
import { MaxSizedBox, MINIMUM_MAX_HEIGHT } from '../shared/MaxSizedBox.js';
|
import { MaxSizedBox, MINIMUM_MAX_HEIGHT } from '../shared/MaxSizedBox.js';
|
||||||
|
|
||||||
interface ThinkingMessageProps {
|
interface ThinkingMessageProps {
|
||||||
thoughts: ThoughtSummary[];
|
thought: ThoughtSummary;
|
||||||
terminalWidth: number;
|
terminalWidth: number;
|
||||||
availableTerminalHeight?: number;
|
availableTerminalHeight?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ThinkingMessage: React.FC<ThinkingMessageProps> = ({
|
export const ThinkingMessage: React.FC<ThinkingMessageProps> = ({
|
||||||
thoughts,
|
thought,
|
||||||
terminalWidth,
|
terminalWidth,
|
||||||
availableTerminalHeight,
|
availableTerminalHeight,
|
||||||
}) => {
|
}) => {
|
||||||
|
const subject = thought.subject.trim();
|
||||||
|
const description = thought.description.trim();
|
||||||
const contentMaxHeight =
|
const contentMaxHeight =
|
||||||
availableTerminalHeight !== undefined
|
availableTerminalHeight !== undefined
|
||||||
? Math.max(availableTerminalHeight - 4, MINIMUM_MAX_HEIGHT)
|
? Math.max(availableTerminalHeight - 4, MINIMUM_MAX_HEIGHT)
|
||||||
@@ -39,23 +41,22 @@ export const ThinkingMessage: React.FC<ThinkingMessageProps> = ({
|
|||||||
<Text bold color="magenta">
|
<Text bold color="magenta">
|
||||||
Thinking
|
Thinking
|
||||||
</Text>
|
</Text>
|
||||||
<Text dimColor> ({thoughts.length})</Text>
|
|
||||||
</Box>
|
</Box>
|
||||||
<MaxSizedBox
|
<MaxSizedBox
|
||||||
maxHeight={contentMaxHeight}
|
maxHeight={contentMaxHeight}
|
||||||
maxWidth={terminalWidth - 2}
|
maxWidth={terminalWidth - 2}
|
||||||
overflowDirection="top"
|
overflowDirection="top"
|
||||||
>
|
>
|
||||||
{thoughts.map((thought, index) => (
|
{(subject || description) && (
|
||||||
<Box key={index} marginTop={1} flexDirection="column">
|
<Box marginTop={1} flexDirection="column">
|
||||||
{thought.subject && (
|
{subject && (
|
||||||
<Text bold color="magenta">
|
<Text bold color="magenta">
|
||||||
{thought.subject}
|
{subject}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
<Text>{thought.description || ' '}</Text>
|
{description && <Text>{description}</Text>}
|
||||||
</Box>
|
</Box>
|
||||||
))}
|
)}
|
||||||
</MaxSizedBox>
|
</MaxSizedBox>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ import { isAtCommand, isSlashCommand } from '../utils/commandUtils.js';
|
|||||||
import { useShellCommandProcessor } from './shellCommandProcessor.js';
|
import { useShellCommandProcessor } from './shellCommandProcessor.js';
|
||||||
import { handleAtCommand } from './atCommandProcessor.js';
|
import { handleAtCommand } from './atCommandProcessor.js';
|
||||||
import { findLastSafeSplitPoint } from '../utils/markdownUtilities.js';
|
import { findLastSafeSplitPoint } from '../utils/markdownUtilities.js';
|
||||||
|
import { getInlineThinkingMode } from '../utils/inlineThinkingMode.js';
|
||||||
import { useStateAndRef } from './useStateAndRef.js';
|
import { useStateAndRef } from './useStateAndRef.js';
|
||||||
import type { UseHistoryManagerReturn } from './useHistoryManager.js';
|
import type { UseHistoryManagerReturn } from './useHistoryManager.js';
|
||||||
import { useLogger } from './useLogger.js';
|
import { useLogger } from './useLogger.js';
|
||||||
@@ -78,6 +79,29 @@ import {
|
|||||||
} from './useToolScheduler.js';
|
} from './useToolScheduler.js';
|
||||||
import { promises as fs } from 'node:fs';
|
import { promises as fs } from 'node:fs';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
|
|
||||||
|
const MAX_THOUGHT_SUMMARY_LENGTH = 140;
|
||||||
|
|
||||||
|
function summarizeThought(thought: ThoughtSummary): ThoughtSummary {
|
||||||
|
const subject = thought.subject.trim();
|
||||||
|
if (subject) {
|
||||||
|
return { subject, description: '' };
|
||||||
|
}
|
||||||
|
|
||||||
|
const description = thought.description.trim();
|
||||||
|
if (!description) {
|
||||||
|
return { subject: '', description: '' };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (description.length <= MAX_THOUGHT_SUMMARY_LENGTH) {
|
||||||
|
return { subject: description, description: '' };
|
||||||
|
}
|
||||||
|
|
||||||
|
const trimmed = description
|
||||||
|
.slice(0, MAX_THOUGHT_SUMMARY_LENGTH - 3)
|
||||||
|
.trimEnd();
|
||||||
|
return { subject: `${trimmed}...`, description: '' };
|
||||||
|
}
|
||||||
import { useSessionStats } from '../contexts/SessionContext.js';
|
import { useSessionStats } from '../contexts/SessionContext.js';
|
||||||
import { useKeypress } from './useKeypress.js';
|
import { useKeypress } from './useKeypress.js';
|
||||||
import type { LoadedSettings } from '../../config/settings.js';
|
import type { LoadedSettings } from '../../config/settings.js';
|
||||||
@@ -762,7 +786,7 @@ export const useGeminiStream = (
|
|||||||
pendingHistoryItemRef.current?.type !== 'gemini' &&
|
pendingHistoryItemRef.current?.type !== 'gemini' &&
|
||||||
pendingHistoryItemRef.current?.type !== 'gemini_content'
|
pendingHistoryItemRef.current?.type !== 'gemini_content'
|
||||||
) {
|
) {
|
||||||
// Flush any pending item (including thinking items) before starting gemini content
|
// Flush any pending item before starting gemini content
|
||||||
if (pendingHistoryItemRef.current) {
|
if (pendingHistoryItemRef.current) {
|
||||||
addItem(pendingHistoryItemRef.current, userMessageTimestamp);
|
addItem(pendingHistoryItemRef.current, userMessageTimestamp);
|
||||||
}
|
}
|
||||||
@@ -810,34 +834,25 @@ export const useGeminiStream = (
|
|||||||
(eventValue: ThoughtSummary, userMessageTimestamp: number) => {
|
(eventValue: ThoughtSummary, userMessageTimestamp: number) => {
|
||||||
setThought(eventValue);
|
setThought(eventValue);
|
||||||
|
|
||||||
// Only accumulate thoughts in history if inline thinking is enabled
|
const inlineThinkingMode = getInlineThinkingMode(settings);
|
||||||
if (!settings.merged.ui?.showInlineThinking) {
|
if (inlineThinkingMode === 'off') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pendingHistoryItemRef.current?.type === 'thinking') {
|
const thoughtForDisplay =
|
||||||
// Accumulate thoughts in the existing thinking item
|
inlineThinkingMode === 'summary'
|
||||||
setPendingHistoryItem((prev) => ({
|
? summarizeThought(eventValue)
|
||||||
|
: eventValue;
|
||||||
|
|
||||||
|
addItem(
|
||||||
|
{
|
||||||
type: 'thinking',
|
type: 'thinking',
|
||||||
thoughts: [...(prev as HistoryItemThinking).thoughts, eventValue],
|
thought: thoughtForDisplay,
|
||||||
}));
|
} as HistoryItemThinking,
|
||||||
} else {
|
userMessageTimestamp,
|
||||||
// Flush any existing pending item and start a new thinking item
|
);
|
||||||
if (pendingHistoryItemRef.current) {
|
|
||||||
addItem(pendingHistoryItemRef.current, userMessageTimestamp);
|
|
||||||
}
|
|
||||||
setPendingHistoryItem({
|
|
||||||
type: 'thinking',
|
|
||||||
thoughts: [eventValue],
|
|
||||||
} as HistoryItemThinking);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
[
|
[addItem, settings],
|
||||||
addItem,
|
|
||||||
pendingHistoryItemRef,
|
|
||||||
setPendingHistoryItem,
|
|
||||||
settings.merged.ui?.showInlineThinking,
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleUserCancelledEvent = useCallback(
|
const handleUserCancelledEvent = useCallback(
|
||||||
@@ -1279,10 +1294,6 @@ export const useGeminiStream = (
|
|||||||
}
|
}
|
||||||
startNewPrompt();
|
startNewPrompt();
|
||||||
setThought(null); // Reset thought when starting a new prompt
|
setThought(null); // Reset thought when starting a new prompt
|
||||||
// Clear any pending thinking item from previous prompt
|
|
||||||
if (pendingHistoryItemRef.current?.type === 'thinking') {
|
|
||||||
setPendingHistoryItem(null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setIsResponding(true);
|
setIsResponding(true);
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ export interface ChatDetail {
|
|||||||
|
|
||||||
export type HistoryItemThinking = HistoryItemBase & {
|
export type HistoryItemThinking = HistoryItemBase & {
|
||||||
type: 'thinking';
|
type: 'thinking';
|
||||||
thoughts: ThoughtSummary[];
|
thought: ThoughtSummary;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type HistoryItemChatList = HistoryItemBase & {
|
export type HistoryItemChatList = HistoryItemBase & {
|
||||||
|
|||||||
Reference in New Issue
Block a user