/** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import type React from 'react'; import { useMemo } from 'react'; import { Box, Text } from 'ink'; import type { ThoughtSummary } from '@google/gemini-cli-core'; import { theme } from '../../semantic-colors.js'; import { normalizeEscapedNewlines } from '../../utils/textUtils.js'; interface ThinkingMessageProps { thought: ThoughtSummary; terminalWidth: number; isFirstThinking?: boolean; } const THINKING_LEFT_PADDING = 1; function normalizeThoughtLines(thought: ThoughtSummary): string[] { const subject = normalizeEscapedNewlines(thought.subject).trim(); const description = normalizeEscapedNewlines(thought.description).trim(); if (!subject && !description) { return []; } if (!subject) { return description.split('\n'); } if (!description) { return [subject]; } const bodyLines = description.split('\n'); return [subject, ...bodyLines]; } /** * Renders a model's thought as a distinct bubble. * Leverages Ink layout for wrapping and borders. */ export const ThinkingMessage: React.FC = ({ thought, terminalWidth, isFirstThinking, }) => { const fullLines = useMemo(() => normalizeThoughtLines(thought), [thought]); if (fullLines.length === 0) { return null; } return ( {isFirstThinking && ( {' '} Thinking...{' '} )} {fullLines.length > 0 && ( {fullLines[0]} )} {fullLines.slice(1).map((line, index) => ( {line} ))} ); };