// Thinking content renderer component
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import { Box, Collapse, IconButton, Paper, Typography } from '@mui/material';
import { styled } from '@mui/material/styles';
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { MessageRendererProps } from './types';
const ThinkingWrapper = styled(Box)`
width: 100%;
`;
const ThinkingHeader = styled(Box)`
display: flex;
align-items: center;
cursor: pointer;
padding: 8px;
`;
const ThinkingContent = styled(Paper)`
padding: 12px;
margin-top: 8px;
background-color: ${props => props.theme.palette.grey[100]};
border-radius: 8px;
font-family: monospace;
`;
/**
* Extract thinking content from a message with various thinking tags
*/
function extractThinkingContent(content: string): { mainContent: string; thinkingContent: string } {
// Support multiple thinking tag formats:
// 1. Claude style: ... or ...
// 2. DeepSeek-R1 style: <|思考|>...|思考|> or ...
// 3. General XML style tags that might indicate thinking: ..., etc.
const thinkingRegexes = [
// Claude style
/<(thinking|think)>([\s\S]*?)<\/\1>/i,
// DeepSeek-R1 style
/<\|思考\|>([\s\S]*?)<\/\|思考\|>/i,
/<(reasoning|理性思考)>([\s\S]*?)<\/\1>/i,
// Other potential thinking tags
/<(reflection|reflect|internal-monologue|thought-process)>([\s\S]*?)<\/\1>/i,
];
let mainContent = content;
let thinkingContent = '';
// Try each regex pattern
for (const regex of thinkingRegexes) {
const match = content.match(regex);
if (match) {
// For DeepSeek style, the captured group index might be different
const capturedContent = match[2] || match[1];
thinkingContent = capturedContent.trim();
// Remove thinking tags from main content
mainContent = content.replace(match[0], '').trim();
break;
}
}
return { mainContent, thinkingContent };
}
/**
* Renderer for messages containing thinking content
* Displays thinking content in a collapsible section
* Supports both DeepSeek's dedicated reasoning_content and XML tag-based thinking content
*/
export const ThinkingMessageRenderer: React.FC = ({ message }) => {
const [expanded, setExpanded] = useState(false);
const { t } = useTranslation('agent');
// Handle both dedicated reasoning_content and embedded XML thinking tags
let mainContent: string;
let thinkingContent: string;
if (message.reasoning_content) {
// If reasoning_content is available (DeepSeek format), use it directly
mainContent = message.content;
thinkingContent = message.reasoning_content;
} else {
// Otherwise extract thinking content from XML tags in content (Claude, OpenAI format)
const extracted = extractThinkingContent(message.content);
mainContent = extracted.mainContent;
thinkingContent = extracted.thinkingContent;
}
const toggleExpanded = () => {
setExpanded(previous => !previous);
};
return (
{mainContent && (
{mainContent}
)}
{thinkingContent && (
<>
{t('Agent.ThinkingProcess')}
{expanded ? : }
{thinkingContent}
>
)}
);
};