import { useMemo, useState } from 'react';
import { CodeBlock } from '@/components/ui/CodeBlock';
import {
IconCheckCircle,
IconCodeWrap,
IconCrossCircle,
IconLandingAI,
IconListUnordered,
IconTerminalWindow,
IconUser,
IconOutput,
IconLog,
IconGlowingDot,
} from '@/components/ui/Icons';
import { MessageUI } from '@/lib/types';
import { ChunkBody, CodeResult, formatStreamLogs } from '@/lib/utils/content';
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '../ui/Table';
import { Button } from '../ui/Button';
import { Separator } from '../ui/Separator';
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from '@/components/ui/Tooltip';
import { Dialog, DialogContent, DialogTrigger } from '../ui/Dialog';
import { Markdown } from './MemoizedReactMarkdown';
import Img from '../ui/Img';
export interface ChatMessageProps {
message: MessageUI;
isLoading: boolean;
}
export function ChatMessage({ message, isLoading }: ChatMessageProps) {
const { role, content, mediaUrl } = message;
return role === 'user' ? (
) : (
);
}
const UserChatMessage: React.FC<{
content: string;
mediaUrl?: string;
}> = ({ content, mediaUrl }) => {
return (
{content}
{mediaUrl && (
<>
{mediaUrl?.endsWith('.mp4') ? (
) : (
![{mediaUrl}]({mediaUrl})
)}
>
)}
);
};
const ChunkStatusToIconDict: Record = {
started: ,
completed: ,
running: ,
failed: ,
};
const ChunkTypeToTextDict: Record = {
plans: 'Creating instructions',
tools: 'Retrieving tools',
code: 'Generating code',
final_code: 'Final result',
};
const ChunkPayloadAction: React.FC<{
payload: ChunkBody['payload'];
}> = ({ payload }) => {
if (!payload) return null;
if (Array.isArray(payload)) {
// [{title: 123, content, 345}, {title: ..., content: ...}] => ['title', 'content']
const keyArray = Array.from(
payload.reduce((acc, curr) => {
Object.keys(curr).forEach(key => acc.add(key));
return acc;
}, new Set()),
);
return (
);
} else {
return (
);
}
};
const CodeResultDisplay: React.FC<{
codeResult: CodeResult;
}> = ({ codeResult }) => {
const { code, test, result } = codeResult;
const getDetail = () => {
if (!result) return {};
try {
const detail = JSON.parse(result);
return {
results: detail.results,
stderr: detail.logs.stderr,
stdout: detail.logs.stdout,
};
} catch {
return {};
}
};
const { results, stderr, stdout } = getDetail();
return (
{Array.isArray(stderr) && (
)}
{Array.isArray(stdout) && !!stdout.join('').trim() && (
<>
>
)}
{Array.isArray(results) && !!results.length && (
<>
{results.map((result, index) => {
if (result.png) {
return (
![{'answer-image'}]({result.png})
);
} else if (result.mp4) {
return (
);
} else if (result.text) {
return (
);
} else {
return null;
}
})}
>
)}
);
};
const AssistantChatMessage: React.FC<{
content: string;
}> = ({ content }) => {
const [formattedSections, codeResult] = useMemo(
() => formatStreamLogs(content),
[content],
);
return (
{formattedSections.map(section => (
{ChunkStatusToIconDict[section.status]}
{ChunkTypeToTextDict[section.type]}
))}
{codeResult &&
}
);
};
export default UserChatMessage;