Build latest book artifacts / build (push) Canceled after 0s
dependency resolution / resolve (3.11) (push) Canceled after 0s
dependency resolution / resolve (3.13) (push) Canceled after 0s
deploy-pages / build (push) Canceled after 0s
deploy-pages / deploy (push) Canceled after 0s
i18n consistency check / check (push) Canceled after 0s
provider adoption tests / test (chapter2/context-compression) (push) Canceled after 0s
provider adoption tests / test (chapter2/prompt-injection) (push) Canceled after 0s
provider adoption tests / test (chapter2/system-hint) (push) Canceled after 0s
provider adoption tests / test (chapter3/log-sanitization) (push) Canceled after 0s
web-search-agent tests / test (push) Canceled after 0s
web-search-agent tests / agentbook (push) Canceled after 0s
499 lines
17 KiB
Python
499 lines
17 KiB
Python
import uuid
|
|
from abc import abstractmethod
|
|
from datetime import datetime
|
|
|
|
from pydantic import BaseModel, ConfigDict, Field
|
|
from typing import Any, Dict, List, Optional, Literal
|
|
|
|
from aworld.models.model_response import ToolCall
|
|
|
|
class MemoryItem(BaseModel):
|
|
id: str = Field(description="id")
|
|
content: Any = Field(description="content")
|
|
created_at: Optional[str] = Field(None, description="created at")
|
|
updated_at: Optional[str] = Field(None, description="updated at")
|
|
metadata: dict = Field(
|
|
description="metadata, use to store additional information, such as user_id, agent_id, run_id, task_id, etc.")
|
|
tags: list[str] = Field(description="tags")
|
|
histories: list["MemoryItem"] = Field(default_factory=list)
|
|
deleted: bool = Field(default=False)
|
|
memory_type: Literal["init", "message", "summary", "agent_experience", "user_profile", "fact", "conversation_summary"] = Field(default="message")
|
|
version: int = Field(description="version")
|
|
|
|
def __init__(self, **data):
|
|
# Set default values for optional fields
|
|
if "id" not in data:
|
|
data["id"] = str(uuid.uuid4())
|
|
if "created_at" not in data:
|
|
data["created_at"] = datetime.now().isoformat()
|
|
if "updated_at" not in data:
|
|
data["updated_at"] = data["created_at"]
|
|
if "metadata" not in data:
|
|
data["metadata"] = {}
|
|
if "tags" not in data:
|
|
data["tags"] = []
|
|
if "version" not in data:
|
|
data["version"] = 1
|
|
|
|
super().__init__(**data)
|
|
|
|
@classmethod
|
|
def from_dict(cls, data: dict) -> "MemoryItem":
|
|
"""Create a MemoryItem instance from a dictionary.
|
|
|
|
Args:
|
|
data (dict): A dictionary containing the memory item data.
|
|
|
|
Returns:
|
|
MemoryItem: An instance of MemoryItem.
|
|
"""
|
|
return cls(**data)
|
|
|
|
@property
|
|
def user_id(self) -> str:
|
|
return self.metadata.get('user_id')
|
|
|
|
@property
|
|
def session_id(self) -> str:
|
|
return self.metadata.get('session_id')
|
|
|
|
@property
|
|
def task_id(self) -> str:
|
|
return self.metadata.get('task_id')
|
|
|
|
@property
|
|
def agent_id(self) -> str:
|
|
return self.metadata.get('agent_id')
|
|
|
|
@property
|
|
def agent_name(self) -> str:
|
|
return self.metadata.get('agent_name')
|
|
|
|
@property
|
|
def application_id(self) -> str:
|
|
return self.metadata.get('application_id', 'default')
|
|
|
|
@property
|
|
def embedding_text(self) -> Optional[str]:
|
|
return self.content
|
|
|
|
def mark_has_summary(self):
|
|
self.metadata['summary'] = True
|
|
|
|
@property
|
|
def has_summary(self) -> bool:
|
|
return self.metadata.get('summary', False)
|
|
|
|
@property
|
|
def content_length(self) -> int:
|
|
return len(self.content)
|
|
|
|
@property
|
|
def status(self) -> str:
|
|
return self.metadata.get('status', 'ACCEPTED')
|
|
|
|
@status.setter
|
|
def status(self, value: Literal["DRAFT", "ACCEPTED", "DISCARD"]) -> None:
|
|
self.metadata['status'] = value
|
|
|
|
@abstractmethod
|
|
def to_openai_message(self) -> dict:
|
|
pass
|
|
|
|
|
|
class MessageMetadata(BaseModel):
|
|
"""
|
|
Metadata for memory messages, including user, session, task, and agent information.
|
|
Args:
|
|
user_id (str): The ID of the user.
|
|
session_id (str): The ID of the session.
|
|
task_id (str): The ID of the task.
|
|
agent_id (str): The ID of the agent.
|
|
"""
|
|
agent_id: str = Field(description="The ID of the agent")
|
|
agent_name: Optional[str] = Field(description="The name of the agent")
|
|
session_id: Optional[str] = Field(default=None,description="The ID of the session")
|
|
task_id: Optional[str] = Field(default=None,description="The ID of the task")
|
|
user_id: Optional[str] = Field(default=None, description="The ID of the user")
|
|
summary_content: Optional[str] = Field(default=None, description="The summary of the memory item")
|
|
|
|
model_config = ConfigDict(extra="allow")
|
|
|
|
@property
|
|
def to_dict(self) -> Dict[str, Any]:
|
|
return self.model_dump()
|
|
|
|
class AgentExperienceItem(BaseModel):
|
|
skill: str = Field(description="The skill demonstrated in the experience")
|
|
actions: List[str] = Field(description="The actions taken by the agent")
|
|
|
|
|
|
class AgentExperience(MemoryItem):
|
|
"""
|
|
Represents an agent's experience, including skills and actions.
|
|
All custom attributes are stored in content and metadata.
|
|
Args:
|
|
agent_id (str): The ID of the agent.
|
|
skill (str): The skill demonstrated in the experience.
|
|
actions (List[str]): The actions taken by the agent.
|
|
metadata (Optional[Dict[str, Any]]): Additional metadata.
|
|
"""
|
|
def __init__(self, agent_id: str, skill: str, actions: List[str], metadata: Optional[Dict[str, Any]] = None) -> None:
|
|
meta = metadata.copy() if metadata else {}
|
|
meta['agent_id'] = agent_id
|
|
agent_experience = AgentExperienceItem(skill=skill, actions=actions)
|
|
super().__init__(content=agent_experience, metadata=meta, memory_type="agent_experience")
|
|
|
|
@property
|
|
def agent_id(self) -> str:
|
|
return self.metadata['agent_id']
|
|
|
|
@property
|
|
def skill(self) -> str:
|
|
return self.content.skill
|
|
|
|
@property
|
|
def actions(self) -> List[str]:
|
|
return self.content.actions
|
|
|
|
@property
|
|
def embedding_text(self):
|
|
return f"skill:{self.skill}, actions:{self.actions}"
|
|
|
|
def to_openai_message(self) -> dict:
|
|
return {
|
|
"role": "system",
|
|
"content": self.content
|
|
}
|
|
|
|
|
|
class UserProfileItem(BaseModel):
|
|
key: str = Field(description="The key of the profile")
|
|
value: Any = Field(description="The value of the profile")
|
|
|
|
class UserProfile(MemoryItem):
|
|
"""
|
|
Represents a user profile key-value pair.
|
|
All custom attributes are stored in content and metadata.
|
|
Args:
|
|
user_id (str): The ID of the user.
|
|
key (str): The profile key.
|
|
value (Any): The profile value.
|
|
metadata (Optional[Dict[str, Any]]): Additional metadata.
|
|
"""
|
|
def __init__(self, user_id: str, key: str, value: Any, metadata: Optional[Dict[str, Any]] = None, **kwargs) -> None:
|
|
meta = metadata.copy() if metadata else {}
|
|
meta['user_id'] = user_id
|
|
user_profile = UserProfileItem(key=key, value=value)
|
|
super().__init__(content=user_profile, metadata=meta, memory_type="user_profile", **kwargs)
|
|
|
|
@property
|
|
def user_id(self) -> str:
|
|
return self.metadata['user_id']
|
|
|
|
@property
|
|
def key(self) -> str:
|
|
return self.content.key
|
|
|
|
@property
|
|
def value(self) -> Any:
|
|
return self.content.value
|
|
|
|
@property
|
|
def item(self) -> UserProfileItem:
|
|
return self.content
|
|
|
|
@property
|
|
def embedding_text(self):
|
|
return f"key:{self.key} value:{self.value}"
|
|
|
|
def to_openai_message(self) -> dict:
|
|
return {
|
|
"role": "system",
|
|
"content": self.content
|
|
}
|
|
|
|
class Fact(MemoryItem):
|
|
"""
|
|
Represents Fact from conversation.
|
|
Args:
|
|
user_id (str): The ID of the user.
|
|
content (str): fact.
|
|
metadata (Optional[Dict[str, Any]]): Additional metadata.
|
|
"""
|
|
def __init__(self, user_id: str = None, agent_id: str = None, content: str = None, metadata: Optional[Dict[str, Any]] = None, **kwargs) -> None:
|
|
meta = metadata.copy() if metadata else {}
|
|
if user_id:
|
|
meta['user_id'] = user_id
|
|
elif metadata.get('user_id'):
|
|
meta['user_id'] = metadata.get('user_id')
|
|
|
|
if 'memory_type' in kwargs:
|
|
kwargs.pop("memory_type")
|
|
super().__init__(content=content, metadata=meta, memory_type="fact", **kwargs)
|
|
|
|
@property
|
|
def key(self) -> str:
|
|
return self.content.key
|
|
|
|
@property
|
|
def value(self) -> Any:
|
|
return self.content.value
|
|
|
|
@property
|
|
def embedding_text(self):
|
|
return self.content
|
|
|
|
def to_openai_message(self) -> dict:
|
|
return {
|
|
"role": "user",
|
|
"content": self.content
|
|
}
|
|
|
|
class MemorySummary(MemoryItem):
|
|
"""
|
|
Represents a memory summary.
|
|
All custom attributes are stored in content and metadata.
|
|
Args:
|
|
item_ids (str): The IDS of the agent.
|
|
summary (str): The summary text.
|
|
metadata (Optional[Dict[str, Any]]): Additional metadata.
|
|
"""
|
|
def __init__(self, item_ids: list[str], summary: str, metadata: MessageMetadata, **kwargs) -> None:
|
|
meta = metadata.to_dict
|
|
meta['item_ids'] = item_ids
|
|
meta['role'] = "user"
|
|
super().__init__(content=summary, metadata=meta, memory_type="summary", **kwargs)
|
|
|
|
@property
|
|
def summary_item_ids(self):
|
|
return self.metadata['item_ids']
|
|
|
|
def to_openai_message(self) -> dict:
|
|
return {
|
|
"role": "user",
|
|
"content": self.content
|
|
}
|
|
|
|
|
|
class ConversationSummary(MemoryItem):
|
|
"""
|
|
Represents a conversation summary.
|
|
All custom attributes are stored in content and metadata.
|
|
Args:
|
|
user_id (str): The ID of the user.
|
|
session_id (str): The ID of the session.
|
|
summary (str): The summary text of the conversation.
|
|
metadata (MessageMetadata): Metadata object containing additional information.
|
|
"""
|
|
|
|
def __init__(self, user_id: str, session_id: str, summary: str, metadata: MessageMetadata, **kwargs) -> None:
|
|
meta = metadata.to_dict
|
|
meta['user_id'] = user_id
|
|
meta['session_id'] = session_id
|
|
super().__init__(content=summary, metadata=meta, memory_type="conversation_summary", **kwargs)
|
|
|
|
def to_openai_message(self) -> dict:
|
|
return {
|
|
"role": "assistant",
|
|
"content": self.content
|
|
}
|
|
|
|
|
|
class MemoryMessage(MemoryItem):
|
|
"""
|
|
Represents a memory message with role, user, session, task, and agent information.
|
|
Args:
|
|
role (str): The role of the message sender.
|
|
metadata (MessageMetadata): Metadata object containing user, session, task, and agent IDs.
|
|
content (Optional[Any]): Content of the message.
|
|
"""
|
|
def __init__(self, role: str, metadata: MessageMetadata, content: Optional[Any] = None, memory_type="message", **kwargs) -> None:
|
|
meta = metadata.to_dict
|
|
meta['role'] = role
|
|
super().__init__(content=content, metadata=meta, memory_type=memory_type, **kwargs)
|
|
|
|
@property
|
|
def role(self) -> str:
|
|
return self.metadata['role']
|
|
|
|
@property
|
|
def user_id(self) -> str:
|
|
return self.metadata['user_id']
|
|
|
|
@property
|
|
def session_id(self) -> str:
|
|
return self.metadata['session_id']
|
|
|
|
@property
|
|
def task_id(self) -> str:
|
|
return self.metadata['task_id']
|
|
|
|
def set_task_id(self, task_id):
|
|
self.metadata['task_id'] = task_id
|
|
|
|
@property
|
|
def agent_id(self) -> str:
|
|
return self.metadata['agent_id']
|
|
|
|
@abstractmethod
|
|
def to_openai_message(self) -> dict:
|
|
pass
|
|
|
|
class MemorySystemMessage(MemoryMessage):
|
|
"""
|
|
Represents a system message with role and content.
|
|
Args:
|
|
metadata (MessageMetadata): Metadata object containing user, session, task, and agent IDs.
|
|
content (str): The content of the message.
|
|
"""
|
|
def __init__(self, content: str, metadata: MessageMetadata, **kwargs) -> None:
|
|
super().__init__(role="system", metadata=metadata, content=content, memory_type="init", **kwargs)
|
|
|
|
def to_openai_message(self) -> dict:
|
|
return {
|
|
"role": self.role,
|
|
"content": self.content
|
|
}
|
|
|
|
@property
|
|
def embedding_text(self) -> Optional[str]:
|
|
return None
|
|
|
|
|
|
class MemoryHumanMessage(MemoryMessage):
|
|
"""
|
|
Represents a human message with role and content.
|
|
Args:
|
|
metadata (MessageMetadata): Metadata object containing user, session, task, and agent IDs.
|
|
content (str): The content of the message.
|
|
"""
|
|
def __init__(self, metadata: MessageMetadata, content: Any, memory_type = "init", **kwargs) -> None:
|
|
super().__init__(role="user", metadata=metadata, content=content, memory_type=memory_type, **kwargs)
|
|
|
|
def to_openai_message(self) -> dict:
|
|
return {
|
|
"role": self.role,
|
|
"content": self.content
|
|
}
|
|
|
|
class MemoryAIMessage(MemoryMessage):
|
|
"""
|
|
Represents an AI message with role and content.
|
|
Args:
|
|
metadata (MessageMetadata): Metadata object containing user, session, task, and agent IDs.
|
|
content (str): The content of the message.
|
|
"""
|
|
def __init__(self, content: str, tool_calls: Optional[List[ToolCall]] = [], metadata: MessageMetadata = None, **kwargs) -> None:
|
|
meta = metadata.to_dict
|
|
if tool_calls:
|
|
meta['tool_calls'] = [tool_call.to_dict() for tool_call in tool_calls]
|
|
super().__init__(role="assistant", metadata=MessageMetadata(**meta), content=content, **kwargs)
|
|
|
|
@property
|
|
def tool_calls(self) -> List[ToolCall]:
|
|
if "tool_calls" not in self.metadata or not self.metadata['tool_calls']:
|
|
return None
|
|
tc = [ToolCall(**tool_call) for tool_call in self.metadata['tool_calls']]
|
|
return tc if len(tc) > 0 else None
|
|
|
|
def to_openai_message(self) -> dict:
|
|
return {
|
|
"role": self.role,
|
|
"content": self.content,
|
|
"tool_calls": [tool_call.to_dict() for tool_call in self.tool_calls or []] or None
|
|
}
|
|
|
|
class MemoryToolMessage(MemoryMessage):
|
|
"""
|
|
Represents a tool message with role, content, tool_call_id, and status.
|
|
Args:
|
|
metadata (MessageMetadata): Metadata object containing user, session, task, and agent IDs.
|
|
tool_call_id (str): The ID of the tool call.
|
|
status (Literal["success", "error"]): The status of the tool call.
|
|
content (str): The content of the message.
|
|
"""
|
|
def __init__(self, tool_call_id: str, content: Any, status: Literal["success", "error"] = "success", metadata: MessageMetadata = None, **kwargs) -> None:
|
|
metadata.tool_call_id = tool_call_id
|
|
metadata.status = status
|
|
super().__init__(role="tool", metadata=metadata, content=content, **kwargs)
|
|
|
|
@property
|
|
def tool_call_id(self) -> str:
|
|
return self.metadata['tool_call_id']
|
|
|
|
@property
|
|
def status(self) -> str:
|
|
return self.metadata['status']
|
|
|
|
@property
|
|
def embedding_text(self) -> Optional[str]:
|
|
return None
|
|
|
|
def to_openai_message(self) -> dict:
|
|
return {
|
|
"role": self.role,
|
|
"content": self.content,
|
|
"tool_call_id": self.tool_call_id,
|
|
}
|
|
|
|
|
|
class LongTermExtractParams(BaseModel):
|
|
session_id: str = Field(description="The ID of the session")
|
|
task_id: Optional[str] = Field(description="The ID of the task")
|
|
memories: List[MemoryItem] = Field(default_factory=list, description="The list of memories to process")
|
|
|
|
application_id: Optional[str] = Field(default=None, description="The ID of the application")
|
|
extract_type: Literal["user_profile", "agent_experience"] = Field(description="The type of long-term extract")
|
|
|
|
def to_openai_messages(self) -> List[dict]:
|
|
return [memory.to_openai_message() for memory in self.memories]
|
|
|
|
class UserProfileExtractParams(LongTermExtractParams):
|
|
user_id: Optional[str] = Field(description="The ID of the user")
|
|
|
|
def __init__(self, user_id: str, session_id: str, task_id: str, memories: List[MemoryItem] = None, application_id: str = None, **kwargs) -> None:
|
|
kwargs = {
|
|
"user_id": user_id,
|
|
"session_id": session_id,
|
|
"task_id": task_id,
|
|
"memories": memories or [],
|
|
"application_id": application_id,
|
|
"extract_type": "user_profile",
|
|
**kwargs
|
|
}
|
|
super().__init__(**kwargs)
|
|
|
|
model_config = ConfigDict(extra="allow")
|
|
|
|
class AgentExperienceExtractParams(LongTermExtractParams):
|
|
agent_id: str = Field(default=None, description="The ID of the agent")
|
|
|
|
def __init__(self, agent_id: str, session_id: str, task_id: str, memories: List[MemoryItem] = None,
|
|
application_id: str = None,**kwargs) -> None:
|
|
super().__init__(session_id=session_id,
|
|
task_id=task_id,
|
|
memories=memories,
|
|
application_id=application_id,
|
|
extract_type="agent_experience", **kwargs)
|
|
self.agent_id = agent_id
|
|
|
|
model_config = ConfigDict(extra="allow")
|
|
|
|
class LongTermMemoryTriggerParams(BaseModel):
|
|
"""
|
|
Metadata for memory messages, including user, session, task, and agent information.
|
|
Args:
|
|
user_id (str): The ID of the user.
|
|
session_id (str): The ID of the session.
|
|
task_id (str): The ID of the task.
|
|
agent_id (str): The ID of the agent.
|
|
"""
|
|
agent_id: str = Field(default=None, description="The ID of the agent")
|
|
session_id: str = Field(default=None, description="The ID of the session")
|
|
task_id: str = Field(default=None, description="The ID of the task")
|
|
user_id: Optional[str] = Field(default=None, description="The ID of the user")
|
|
application_id: Optional[str] = Field(default="default", description="The ID of the application, namespace for memory")
|
|
force: Optional[bool] = Field(default=False, description="Whether to force trigger long-term memory")
|
|
|
|
model_config = ConfigDict(extra="allow") |