/*
┌──────────────────────────────────────────────────────────────────────────────┐
│ @author: Davidson Gomes │
│ @file: /app/chat/components/ChatMessage.tsx │
│ Developed by: Davidson Gomes │
│ Creation date: May 13, 2025 │
│ Contact: contato@evolution-api.com │
├──────────────────────────────────────────────────────────────────────────────┤
│ @copyright © Evolution API 2025. All rights reserved. │
│ Licensed under the Apache License, Version 2.0 │
│ │
│ You may not use this file except in compliance with the License. │
│ You may obtain a copy of the License at │
│ │
│ http://www.apache.org/licenses/LICENSE-2.0 │
│ │
│ Unless required by applicable law or agreed to in writing, software │
│ distributed under the License is distributed on an "AS IS" BASIS, │
│ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. │
│ See the License for the specific language governing permissions and │
│ limitations under the License. │
├──────────────────────────────────────────────────────────────────────────────┤
│ @important │
│ For any future changes to the code in this file, it is recommended to │
│ include, together with the modification, the information of the developer │
│ who changed it and the date of modification. │
└──────────────────────────────────────────────────────────────────────────────┘
*/
"use client";
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import { ChatMessage as ChatMessageType } from "@/services/sessionService";
import { ChevronDown, ChevronRight, Copy, Check, User, Bot, Terminal } from "lucide-react";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import { useState } from "react";
import { InlineDataAttachments } from "./InlineDataAttachments";
import { cn } from "@/lib/utils";
interface FunctionMessageContent {
title: string;
content: string;
author?: string;
}
interface AttachedFile {
filename: string;
content_type: string;
data: string;
size: number;
preview_url?: string;
}
interface ChatMessageProps {
message: ChatMessageType;
agentColor: string;
isExpanded: boolean;
toggleExpansion: (messageId: string) => void;
containsMarkdown: (text: string) => boolean;
messageContent: string | FunctionMessageContent;
sessionId?: string;
}
export function ChatMessage({
message,
agentColor,
isExpanded,
toggleExpansion,
containsMarkdown,
messageContent,
sessionId,
}: ChatMessageProps) {
const [isCopied, setIsCopied] = useState(false);
const isUser = message.author === "user";
const hasFunctionCall = message.content.parts.some(
(part) => part.functionCall || part.function_call
);
const hasFunctionResponse = message.content.parts.some(
(part) => part.functionResponse || part.function_response
);
const isFunctionMessage = hasFunctionCall || hasFunctionResponse;
const isTaskExecutor = typeof messageContent === "object" &&
"author" in messageContent &&
typeof messageContent.author === "string" &&
messageContent.author.endsWith("- Task executor");
const inlineDataParts = message.content.parts.filter(part => part.inline_data);
const hasInlineData = inlineDataParts.length > 0;
const copyToClipboard = () => {
const textToCopy = typeof messageContent === "string"
? messageContent
: messageContent.content;
navigator.clipboard.writeText(textToCopy).then(() => {
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
});
};
// Generate appropriate avatar content
const getAvatar = () => {
if (isUser) {
return (
{(messageContent as FunctionMessageContent).content}
{children}
);
}
return (
{children}