Files
ai-agent-book/chapter9/gaia-experience/AWorld/aworld/memory/models.py
T
liqiang b119135836
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
ai-agent-book 精选快照(<2MB 代码与文档,来自 github.com/bojieli/ai-agent-book)
2026-08-20 13:12:50 +00:00

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")