import html import json import re from typing import List, Union from pydantic import BaseModel, Field from letta.schemas.enums import MessageStreamStatus from letta.schemas.letta_message import LettaMessage, LettaMessageUnion from letta.schemas.usage import LettaUsageStatistics from letta.utils import json_dumps # TODO: consider moving into own file class LettaResponse(BaseModel): """ Response object from an agent interaction, consisting of the new messages generated by the agent and usage statistics. The type of the returned messages can be either `Message` or `LettaMessage`, depending on what was specified in the request. Attributes: messages (List[Union[Message, LettaMessage]]): The messages returned by the agent. usage (LettaUsageStatistics): The usage statistics """ messages: List[LettaMessageUnion] = Field( ..., description="The messages returned by the agent.", json_schema_extra={ "items": { "oneOf": [ {"x-ref-name": "SystemMessage"}, {"x-ref-name": "UserMessage"}, {"x-ref-name": "ReasoningMessage"}, {"x-ref-name": "ToolCallMessage"}, {"x-ref-name": "ToolReturnMessage"}, {"x-ref-name": "AssistantMessage"}, ], "discriminator": {"propertyName": "message_type"}, } }, ) usage: LettaUsageStatistics = Field( ..., description="The usage statistics of the agent.", json_schema_extra={"x-ref-name": "LettaUsageStatistics"} ) def __str__(self): return json_dumps( { "messages": [message.model_dump() for message in self.messages], # Assume `Message` and `LettaMessage` have a `dict()` method "usage": self.usage.model_dump(), # Assume `LettaUsageStatistics` has a `dict()` method }, indent=4, ) def _repr_html_(self): def get_formatted_content(msg): if msg.message_type == "internal_monologue": return f'
{html.escape(msg.internal_monologue)}
' if msg.message_type == "reasoning_message": return f'
{html.escape(msg.reasoning)}
' elif msg.message_type == "function_call": args = format_json(msg.function_call.arguments) return f'
{html.escape(msg.function_call.name)}({args})
' elif msg.message_type == "tool_call_message": args = format_json(msg.tool_call.arguments) return f'
{html.escape(msg.tool_call.name)}({args})
' elif msg.message_type == "function_return": return_value = format_json(msg.function_return) # return f'
Status: {html.escape(msg.status)}
{return_value}
' return f'
{return_value}
' elif msg.message_type == "tool_return_message": return_value = format_json(msg.tool_return) # return f'
Status: {html.escape(msg.status)}
{return_value}
' return f'
{return_value}
' elif msg.message_type == "user_message": if is_json(msg.message): return f'
{format_json(msg.message)}
' else: return f'
{html.escape(msg.message)}
' elif msg.message_type in ["assistant_message", "system_message"]: return f'
{html.escape(msg.message)}
' else: return f'
{html.escape(str(msg))}
' def is_json(string): try: json.loads(string) return True except ValueError: return False def format_json(json_str): try: parsed = json.loads(json_str) formatted = json.dumps(parsed, indent=2, ensure_ascii=False) formatted = formatted.replace("&", "&").replace("<", "<").replace(">", ">") formatted = formatted.replace("\n", "
").replace(" ", "  ") formatted = re.sub(r'(".*?"):', r'\1:', formatted) formatted = re.sub(r': (".*?")', r': \1', formatted) formatted = re.sub(r": (\d+)", r': \1', formatted) formatted = re.sub(r": (true|false)", r': \1', formatted) return formatted except json.JSONDecodeError: return html.escape(json_str) html_output = """
""" for msg in self.messages: content = get_formatted_content(msg) title = msg.message_type.replace("_", " ").upper() html_output += f"""
{title}
{content}
""" html_output += "
" # Formatting the usage statistics usage_html = json.dumps(self.usage.model_dump(), indent=2) html_output += f"""
USAGE STATISTICS
{format_json(usage_html)}
""" return html_output # The streaming response is either [DONE], [DONE_STEP], [DONE], an error, or a LettaMessage LettaStreamingResponse = Union[LettaMessage, MessageStreamStatus, LettaUsageStatistics]