# ========= Copyright 2023-2026 @ CAMEL-AI.org. All Rights Reserved. ========= # Licensed under the Apache License, Version 2.0 (the "License"); # 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. # ========= Copyright 2023-2026 @ CAMEL-AI.org. All Rights Reserved. ========= from typing import List, Optional from pydantic import BaseModel, Field from camel.agents import ChatAgent from camel.messages import BaseMessage from camel.models import BaseModelBackend, ModelFactory from camel.types import ModelPlatformType, ModelType class MessageSummary(BaseModel): r"""Schema for structured message summaries. Attributes: summary (str): A brief, one-sentence summary of the conversation. participants (List[str]): The roles of participants involved. key_topics_and_entities (List[str]): Important topics, concepts, and entities discussed. decisions_and_outcomes (List[str]): Key decisions, conclusions, or outcomes reached. action_items (List[str]): A list of specific tasks or actions to be taken, with assignees if mentioned. progress_on_main_task (str): A summary of progress made on the primary task. """ summary: str = Field( description="A brief, one-sentence summary of the conversation." ) participants: List[str] = Field( description="The roles of participants involved." ) key_topics_and_entities: List[str] = Field( description="Important topics, concepts, and entities discussed." ) decisions_and_outcomes: List[str] = Field( description="Key decisions, conclusions, or outcomes reached." ) action_items: List[str] = Field( description=( "A list of specific tasks or actions to be taken, with assignees " "if mentioned." ) ) progress_on_main_task: str = Field( description="A summary of progress made on the primary task." ) class MessageSummarizer: r"""Utility class for generating structured summaries of chat messages. Args: model_backend (Optional[BaseModelBackend], optional): The model backend to use for summarization. If not provided, a default model backend will be created. """ def __init__( self, model_backend: Optional[BaseModelBackend] = None, ): if model_backend is None: self.model_backend = ModelFactory.create( model_platform=ModelPlatformType.DEFAULT, model_type=ModelType.GPT_4O_MINI, ) else: self.model_backend = model_backend self.agent = ChatAgent( BaseMessage.make_assistant_message( role_name="Message Summarizer", content=( "You are an expert conversation summarizer. Your task is " "to analyze chat messages and create a structured summary " "in JSON format. The summary should capture:\n" "- summary: A brief, one-sentence summary of the " "conversation.\n" "- participants: The roles of participants involved.\n" "- key_topics_and_entities: Important topics, concepts, " "and entities discussed.\n" "- decisions_and_outcomes: Key decisions, conclusions, or " "outcomes reached.\n" "- action_items: A list of specific tasks or actions to " "be taken, with assignees if mentioned.\n" "- progress_on_main_task: A summary of progress made on " "the primary task.\n\n" "Your response must be a JSON object that strictly " "adheres to this structure. Be concise and accurate." ), ), model=self.model_backend, ) def summarize(self, messages: List[BaseMessage]) -> MessageSummary: r"""Generate a structured summary of the provided messages. Args: messages (List[BaseMessage]): List of messages to summarize. Returns: MessageSummary: Structured summary of the conversation. Raises: ValueError: If the messages list is empty or if the model's response cannot be parsed as valid JSON. """ if not messages: raise ValueError("Cannot summarize an empty list of messages.") # Construct prompt from messages message_text = "\n".join( f"{msg.role_name}: {msg.content}" for msg in messages ) prompt = ( "Please analyze the following chat messages and generate a " "structured summary.\n\n" f"MESSAGES:\n\"\"\"\n{message_text}\n\"\"\"\n\n" "Your response must be a JSON object that strictly adheres to the " "required format." ) # Get structured summary from model with forced JSON response response = self.agent.step(prompt, response_format=MessageSummary) if response.msg is None or response.msg.parsed is None: raise ValueError( "Failed to get a structured summary from the model." ) summary = response.msg.parsed if not isinstance(summary, MessageSummary): raise ValueError("The parsed response is not a MessageSummary.") return summary