refactor(memory): restructure memory modules and add versioned personal memory agents

This commit is contained in:
jinli.yl 2026-01-29 11:21:50 +08:00
parent 12911e5148
commit cf62a73228
42 changed files with 463 additions and 151 deletions

View file

@ -42,6 +42,7 @@ class EvalConfig:
batch_size: int = 20
output_dir: str = "bench_results/reme"
eval_model_name: str = "qwen3-max"
algo_version: str = "v1"
# ==================== Utilities ====================
@ -217,7 +218,7 @@ async def answer_question_with_memories(
result = await reme.llm.simple_request_for_json(
prompt=prompt,
model_name=model_name
model_name="qwen3-30b-a3b-instruct-2507"
)
return result
@ -269,9 +270,10 @@ async def evaluation_for_question(
class MemoryProcessor:
"""Handles ReMe memory operations."""
def __init__(self, reme: ReMe, eval_model_name: str = "qwen3-max"):
def __init__(self, reme: ReMe, eval_model_name: str = "qwen3-max", algo_version: str = "v1"):
self.reme = reme
self.eval_model_name = eval_model_name
self.algo_version = algo_version
async def add_memories(
self,
@ -297,7 +299,7 @@ class MemoryProcessor:
result = await self.reme.summary_memory(
messages=batch,
user_name=user_id,
version="default",
version=self.algo_version,
return_dict=True,
)
@ -305,7 +307,7 @@ class MemoryProcessor:
total_duration_ms += duration_ms
extracted_memories.extend([m.model_dump(exclude_none=True) for m in result["answer"]])
summary_messages.extend([m.simple_dump() for m in result["messages"]])
summary_messages.extend([m.simple_dump(enable_argument_dict=True) for m in result["messages"]])
return extracted_memories, summary_messages, total_duration_ms
@ -329,13 +331,13 @@ class MemoryProcessor:
query=query,
retrieve_top_k=top_k,
user_name=user_id,
version="default",
version=self.algo_version,
return_dict=True,
)
# Extract memories from response
memories = result["answer"]
agent_messages = [x.model_dump(exclude_none=True) for x in result["messages"]]
agent_messages = [x.simple_dump(enable_argument_dict=True) for x in result["messages"]]
retrieved_nodes = [x.model_dump(exclude_none=True) for x in result["retrieved_nodes"]]
# Use LLM to generate structured answer from memories
@ -521,7 +523,11 @@ class HaluMemEvaluator:
self.reme.prompt_handler.load_prompt_by_file(prompts_yaml_path)
self.file_manager = FileManager(config.output_dir)
self.memory_processor = MemoryProcessor(self.reme, config.eval_model_name)
self.memory_processor = MemoryProcessor(
self.reme,
config.eval_model_name,
config.algo_version
)
self.qa_evaluator = QuestionAnsweringEvaluator(
self.memory_processor,
self.reme,
@ -763,7 +769,8 @@ async def main_async(
top_k: int,
user_num: int,
max_concurrency: int,
eval_model_name: str = "qwen3-max"
eval_model_name: str = "qwen3-max",
algo_version: str = "v1"
):
"""Main async entry point for ReMe evaluation with proper resource cleanup."""
config = EvalConfig(
@ -771,7 +778,8 @@ async def main_async(
top_k=top_k,
user_num=user_num,
max_concurrency=max_concurrency,
eval_model_name=eval_model_name
eval_model_name=eval_model_name,
algo_version=algo_version
)
# Use async context manager for automatic cleanup
@ -784,7 +792,8 @@ def main(
top_k: int,
user_num: int,
max_concurrency: int,
eval_model_name: str = "qwen3-max"
eval_model_name: str = "qwen3-max",
algo_version: str = "v1"
):
"""Main entry point for ReMe evaluation."""
asyncio.run(main_async(
@ -792,7 +801,8 @@ def main(
top_k=top_k,
user_num=user_num,
max_concurrency=max_concurrency,
eval_model_name=eval_model_name
eval_model_name=eval_model_name,
algo_version=algo_version
))
@ -833,6 +843,12 @@ if __name__ == "__main__":
# default="qwen3-235b-a22b-instruct-2507",
help="Model name for evaluation (default: qwen3-max)"
)
parser.add_argument(
"--algo_version",
type=str,
default="v1",
help="Algorithm version for summary and retrieval (default: v1)"
)
args = parser.parse_args()
@ -841,5 +857,6 @@ if __name__ == "__main__":
top_k=args.top_k,
user_num=args.user_num,
max_concurrency=args.max_concurrency,
eval_model_name=args.eval_model_name
eval_model_name=args.eval_model_name,
algo_version=args.algo_version
)

1
benchmark/halumem/scripts.sh Executable file
View file

@ -0,0 +1 @@
cat bench_results/reme/Martin\ Mark/session* | grep '"result_type": "' | awk -F'"' '{total++; if($4=="Correct") count++} END {printf "Correct Rate: %.2f%% (%d/%d)\n", (count/total)*100, count, total}'

View file

@ -1,9 +1,32 @@
"""memory agent"""
from . import default
from .base_memory_agent import BaseMemoryAgent
from .personal.personal_retriever import PersonalRetriever
from .personal.personal_summarizer import PersonalSummarizer
from .personal.personal_v1_retriever import PersonalV1Retriever
from .personal.personal_v1_summarizer import PersonalV1Summarizer
from .procedural.procedural_retriever import ProceduralRetriever
from .procedural.procedural_summarizer import ProceduralSummarizer
from .reme_retriever import ReMeRetriever
from .reme_summarizer import ReMeSummarizer
from .tool.tool_retriever import ToolRetriever
from .tool.tool_summarizer import ToolSummarizer
from ...core import R
__all__ = [
"default",
"BaseMemoryAgent",
"PersonalRetriever",
"PersonalSummarizer",
"PersonalV1Retriever",
"PersonalV1Summarizer",
"ProceduralRetriever",
"ProceduralSummarizer",
"ReMeRetriever",
"ReMeSummarizer",
"ToolRetriever",
"ToolSummarizer",
]
for name in __all__:
tool_class = globals()[name]
R.op.register()(tool_class)

View file

@ -1,26 +0,0 @@
"""Default memory agents for personal, procedural, tool and ReMe memory operations."""
from .personal_retriever import PersonalRetriever
from .personal_summarizer import PersonalSummarizer
from .procedural_retriever import ProceduralRetriever
from .procedural_summarizer import ProceduralSummarizer
from .reme_retriever import ReMeRetriever
from .reme_summarizer import ReMeSummarizer
from .tool_retriever import ToolRetriever
from .tool_summarizer import ToolSummarizer
from ....core import R
__all__ = [
"PersonalRetriever",
"PersonalSummarizer",
"ProceduralRetriever",
"ProceduralSummarizer",
"ReMeRetriever",
"ReMeSummarizer",
"ToolRetriever",
"ToolSummarizer",
]
for name in __all__:
tool_class = globals()[name]
R.op.register()(tool_class)

View file

@ -1,10 +0,0 @@
"""Tool memory retriever agent implementation."""
from ..base_memory_agent import BaseMemoryAgent
from ....core.enumeration import MemoryType
class ToolRetriever(BaseMemoryAgent):
"""Agent responsible for retrieving tool-related memories."""
memory_type: MemoryType = MemoryType.TOOL

View file

@ -1,10 +0,0 @@
"""Tool memory summarizer agent implementation."""
from ..base_memory_agent import BaseMemoryAgent
from ....core.enumeration import MemoryType
class ToolSummarizer(BaseMemoryAgent):
"""Agent responsible for summarizing tool-related memories."""
memory_type: MemoryType = MemoryType.TOOL

View file

View file

@ -0,0 +1,86 @@
"""Personal memory retriever agent for retrieving personal memories through vector search."""
from ..base_memory_agent import BaseMemoryAgent
from ....core.enumeration import Role, MemoryType
from ....core.op import BaseTool
from ....core.schema import Message
from ....core.utils import format_messages
class PersonalV1Retriever(BaseMemoryAgent):
"""Retrieve personal memories through vector search and history reading."""
memory_type: MemoryType = MemoryType.PERSONAL
async def build_messages(self) -> list[Message]:
if self.context.get("query"):
context = self.context.query
elif self.context.get("messages"):
context = self.description + "\n" + format_messages(self.context.messages)
else:
raise ValueError("input must have either `query` or `messages`")
read_all_profiles_tool: BaseTool | None = self.pop_tool("read_all_profiles")
if read_all_profiles_tool is not None:
all_profiles = await read_all_profiles_tool.call(
memory_target=self.memory_target,
service_context=self.service_context,
)
else:
all_profiles = ""
return [
Message(
role=Role.SYSTEM,
content=self.prompt_format(
prompt_name="system_prompt",
memory_type=self.memory_type.value,
memory_target=self.memory_target,
user_profile=all_profiles,
context=context.strip(),
),
),
Message(
role=Role.USER,
content=self.get_prompt("user_message"),
),
]
async def _acting_step(
self,
assistant_message: Message,
tools: list[BaseTool],
step: int,
stage: str = "",
**kwargs,
) -> tuple[list[BaseTool], list[Message]]:
"""Execute tool calls with memory context."""
return await super()._acting_step(
assistant_message,
tools,
step,
memory_type=self.memory_type.value,
memory_target=self.memory_target,
retrieved_nodes=self.retrieved_nodes,
**kwargs,
)
async def execute(self):
result = await super().execute()
answer = result["answer"]
if "MEMORY_NOT_FOUND" in answer:
result["answer"] = "\n".join(
[
n.format(
include_memory_id=False,
include_when_to_use=False,
include_content=True,
include_message_time=False,
ref_memory_id_key="",
)
for n in self.retrieved_nodes
],
)
result["retrieved_nodes"] = self.retrieved_nodes
return result

View file

@ -0,0 +1,117 @@
"""Personal memory summarizer agent for two-phase personal memory processing."""
from loguru import logger
from ..base_memory_agent import BaseMemoryAgent
from ....core.enumeration import Role, MemoryType
from ....core.op import BaseTool
from ....core.schema import Message
class PersonalV1Summarizer(BaseMemoryAgent):
"""Two-phase personal memory processor: retrieve/add memories then update profile."""
memory_type: MemoryType = MemoryType.PERSONAL
async def _build_s1_messages(self) -> list[Message]:
return [
Message(
role=Role.SYSTEM,
content=self.prompt_format(
prompt_name="system_prompt_s1",
context=self.context.history_node.content,
memory_type=self.memory_type.value,
memory_target=self.memory_target,
),
),
Message(
role=Role.USER,
content=self.get_prompt("user_message_s1"),
),
]
async def _build_s2_messages(self) -> list[Message]:
return [
Message(
role=Role.SYSTEM,
content=self.prompt_format(
prompt_name="system_prompt_s2",
context=self.context.history_node.content,
memory_type=self.memory_type.value,
memory_target=self.memory_target,
),
),
Message(
role=Role.USER,
content=self.get_prompt("user_message_s2"),
),
]
async def _acting_step(
self,
assistant_message: Message,
tools: list[BaseTool],
step: int,
stage: str = "",
**kwargs,
) -> tuple[list[BaseTool], list[Message]]:
"""Execute tool calls with memory context."""
return await super()._acting_step(
assistant_message,
tools,
step,
stage=stage,
memory_type=self.memory_type.value,
memory_target=self.memory_target,
history_node=self.history_node,
author=self.author,
retrieved_nodes=self.retrieved_nodes,
**kwargs,
)
async def execute(self):
memory_tools = []
profile_tools = []
for i, tool in enumerate(self.tools):
tool_name = tool.tool_call.name
if "_memory" in tool_name:
memory_tools.append(tool)
elif "_profile" in tool_name:
profile_tools.append(tool)
else:
raise ValueError(f"[{self.__class__.__name__}] unknown tool_name={tool_name}")
logger.info(f"[{self.__class__.__name__}] tool_call[{i}]={tool.tool_call.simple_input_dump(as_dict=False)}")
stage = "s1-memory"
messages_s1 = await self._build_s1_messages()
for i, message in enumerate(messages_s1):
role = message.name or message.role
logger.info(f"[{self.__class__.__name__} {stage}] role={role} {message.simple_dump(as_dict=False)}")
tools_s1, messages_s1, success_s1 = await self.react(messages_s1, memory_tools, stage=stage)
if profile_tools:
stage = "s2-profile"
messages_s2 = await self._build_s2_messages()
for i, message in enumerate(messages_s2):
role = message.name or message.role
logger.info(f"[{self.__class__.__name__} {stage}] role={role} {message.simple_dump(as_dict=False)}")
tools_s2, messages_s2, success_s2 = await self.react(messages_s2, profile_tools, stage=stage)
else:
tools_s2, messages_s2, success_s2 = [], [], True
answer = (messages_s1[-1].content if success_s1 else "") + (messages_s2[-1].content if success_s2 else "")
success = success_s1 and success_s2
messages = messages_s1 + messages_s2
tools = tools_s1 + tools_s2
memory_nodes = []
for tool in tools:
if tool.memory_nodes:
memory_nodes.extend(tool.memory_nodes)
return {
"answer": answer,
"success": success,
"messages": messages,
"tools": tools,
"memory_nodes": memory_nodes,
}

View file

@ -0,0 +1,65 @@
system_prompt_s1: |
You are a Memory Agent responsible for managing {memory_type} memories about {memory_target}.
## Latest Conversation
Format: round<index> [<timestamp>] <role/name>: <content>
{context}
## Task
### Step 1: Create Memory Draft
Create a memory draft in `add_draft_and_retrieve_similar_memory` based on the latest conversation.
- Use actual names from the conversation (e.g., "Bob likes apples") instead of generic references (e.g., "user likes apples")
- Always record memories with real names
- The tool will retrieve similar historical memories via vector search to help you consolidate in Step 2
### Step 2: Update Memory Store
Update the vector store using `update_memory` to keep it well-organized and consolidated:
**What to Delete** (via `memory_ids_to_delete`):
- Duplicate memories with identical or highly similar content
- Memories that should be merged into a single consolidated entry
**What to Add** (via `memories_to_add` with message_time and memory_content):
- For each topic with changes: add ONE consolidated memory that merges related information
- New distinct memories that don't overlap with existing ones
- Updated memories that capture the latest state while preserving temporal evolution
## Requirements
- Extract only what's explicitly stated—no inferences, assumptions, or fabrications
- Preserve temporal evolution: capture how things change over time within the same topic
- Maintain organization: group related memories by topic and eliminate all redundancy
user_message_s1: |
Complete the task by following Step 1 and Step 2 in order
system_prompt_s2: |
You are a Profile Agent responsible for managing profiles about {memory_target}.
## Latest Conversation
Format: round<index> [<timestamp>] <role/name>: <content>
{context}
## Task
### Step 1: Create Profile Draft
Create a profile draft in `add_draft_and_read_all_profiles` based on the latest conversation.
- The tool will return all existing profiles to help you maintain the profile store in Step 2
### Step 2: Update Profile Store
Update the profile store using `update_profile` to keep it well-organized and consolidated:
**What to Delete** (via `profile_ids_to_delete`):
- Duplicate profiles with identical keys or values
- Conflicting profiles that contradict the new information
- Profiles that should be merged into a single consolidated entry
**What to Add** (via `profiles_to_add` with message_time, profile_key, and profile_value):
- For each profile key with changes: add ONE consolidated profile that merges related information
- New distinct profiles that don't overlap with existing ones
- Updated profiles that capture the latest state
## Requirements
- Extract only what's explicitly stated—no inferences, assumptions, or fabrications
- Maintain organization: group related profiles by key and eliminate all redundancy
user_message_s2: |
Complete the task by following Step 1 and Step 2 in order

View file

@ -1,10 +1,10 @@
"""ReMe retriever agent that orchestrates multiple memory agents to retrieve information."""
from ..base_memory_agent import BaseMemoryAgent
from ....core.enumeration import Role
from ....core.op import BaseTool
from ....core.schema import Message
from ....core.utils import format_messages
from .base_memory_agent import BaseMemoryAgent
from ...core.enumeration import Role
from ...core.op import BaseTool
from ...core.schema import Message
from ...core.utils import format_messages
class ReMeRetriever(BaseMemoryAgent):

View file

@ -23,7 +23,5 @@ system_prompt: |
- Each memory_target should be assigned **only once** - do not duplicate assignments
3. Use the `delegate_task` tool **once** with all relevant memory_target(s) to enable parallel processing by specialized agents
Note: If the context contains no memorable information (e.g., simple greetings), return `<NO_MEMORY_NEEDED>`.
user_message: |
Please analyze the context and delegate retrieval tasks to the appropriate specialized agents.

View file

@ -1,10 +1,10 @@
"""ReMe summarizer agent that orchestrates multiple memory agents to summarize information."""
from ..base_memory_agent import BaseMemoryAgent
from ....core.enumeration import Role
from ....core.op import BaseTool
from ....core.schema import Message
from ....core.utils import format_messages
from .base_memory_agent import BaseMemoryAgent
from ...core.enumeration import Role
from ...core.op import BaseTool
from ...core.schema import Message
from ...core.utils import format_messages
class ReMeSummarizer(BaseMemoryAgent):

View file

@ -84,6 +84,7 @@ class Message(BaseModel):
add_reasoning: bool = True,
add_time_created: bool = False,
add_metadata: bool = False,
enable_argument_dict: bool = False,
as_dict: bool = True,
) -> dict | str:
"""Transforms the message into a simplified dictionary for standard APIs."""
@ -98,7 +99,13 @@ class Message(BaseModel):
result["reasoning_content"] = self.reasoning_content
if self.tool_calls:
result["tool_calls"] = [tc.simple_output_dump() for tc in self.tool_calls]
result["tool_calls"] = [
tc.simple_output_dump(
as_dict=True,
enable_argument_dict=enable_argument_dict,
)
for tc in self.tool_calls
]
if self.tool_call_id:
result["tool_call_id"] = self.tool_call_id

View file

@ -145,17 +145,13 @@ class ToolCall(BaseModel):
}
return result if as_dict else json.dumps(result, ensure_ascii=False)
def simple_output_dump(self, as_dict: bool = True) -> dict | str:
"""Convert ToolCall to output format dictionary or JSON string for API responses.
Args:
as_dict: If True, returns dict; if False, returns JSON string.
"""
def simple_output_dump(self, as_dict: bool = True, enable_argument_dict: bool = False) -> dict | str:
"""Convert ToolCall to output format dictionary or JSON string for API responses."""
result = {
"index": self.index,
"id": self.id,
self.type: {
"arguments": self.arguments,
"arguments": self.argument_dict if enable_argument_dict else self.arguments,
"name": self.name,
},
"type": self.type,

View file

@ -3,15 +3,17 @@
import sys
from pathlib import Path
from reme.agent.memory import BaseMemoryAgent
from .agent.memory.default import (
from .agent.memory import (
BaseMemoryAgent,
ReMeSummarizer,
ReMeRetriever,
PersonalV1Summarizer,
PersonalV1Retriever,
PersonalSummarizer,
PersonalRetriever,
ReMeRetriever,
ProceduralSummarizer,
ToolSummarizer,
ProceduralRetriever,
ToolSummarizer,
ToolRetriever,
)
from .config import ReMeConfigParser
@ -116,7 +118,7 @@ class ReMe(Application):
format_messages.append(message)
personal_summarizer: BaseMemoryAgent
if version:
if version == "default":
personal_summarizer = PersonalSummarizer(
tools=[
AddDraftAndRetrieveSimilarMemory(
@ -134,17 +136,33 @@ class ReMe(Application):
),
],
)
elif version == "v1":
personal_summarizer = PersonalV1Summarizer(
tools=[
AddDraftAndRetrieveSimilarMemory(
enable_thinking_params=enable_thinking_params,
top_k=retrieve_top_k,
),
UpdateMemoryV2(enable_thinking_params=enable_thinking_params),
AddDraftAndReadAllProfiles(
enable_thinking_params=enable_thinking_params,
profile_dir=self.profile_dir,
),
],
)
else:
raise NotImplementedError
procedural_summarizer: BaseMemoryAgent
if version == "default":
if version in ["default", "v1"]:
procedural_summarizer = ProceduralSummarizer(tools=[])
else:
raise NotImplementedError
tool_summarizer: BaseMemoryAgent
if version == "default":
if version in ["default", "v1"]:
tool_summarizer = ToolSummarizer(tools=[])
else:
raise NotImplementedError
@ -186,7 +204,7 @@ class ReMe(Application):
memory_agents = [personal_summarizer, procedural_summarizer, tool_summarizer]
reme_summarizer: BaseMemoryAgent
if version == "default":
if version in ["default", "v1"]:
reme_summarizer = ReMeSummarizer(tools=[AddHistory(), DelegateTask(memory_agents=memory_agents)])
else:
raise NotImplementedError
@ -221,7 +239,7 @@ class ReMe(Application):
"""Retrieve relevant personal, procedural and tool memories for a query."""
personal_retriever: BaseMemoryAgent
if version:
if version == "default":
personal_retriever = PersonalRetriever(
tools=[
ReadAllProfiles(
@ -236,17 +254,33 @@ class ReMe(Application):
ReadHistory(enable_thinking_params=enable_thinking_params),
],
)
elif version == "v1":
personal_retriever = PersonalV1Retriever(
tools=[
ReadAllProfiles(
enable_thinking_params=enable_thinking_params,
profile_dir=self.profile_dir,
),
RetrieveMemory(
enable_thinking_params=enable_thinking_params,
top_k=retrieve_top_k,
enable_time_filter=enable_time_filter,
),
],
)
else:
raise NotImplementedError
procedural_retriever: BaseMemoryAgent
if version == "default":
if version in ["default", "v1"]:
procedural_retriever = ProceduralRetriever(tools=[])
else:
raise NotImplementedError
tool_retriever: BaseMemoryAgent
if version == "default":
if version in ["default", "v1"]:
tool_retriever = ToolRetriever(tools=[])
else:
raise NotImplementedError
@ -286,7 +320,7 @@ class ReMe(Application):
memory_agents = [personal_retriever, procedural_retriever, tool_retriever]
reme_retriever: BaseMemoryAgent
if version == "default":
if version in ["default", "v1"]:
reme_retriever = ReMeRetriever(tools=[DelegateTask(memory_agents=memory_agents)])
else:
raise NotImplementedError

View file

@ -1,42 +1,48 @@
"""memory tools"""
from .add_draft_and_read_all_profiles import AddDraftAndReadAllProfiles
from .add_draft_and_retrieve_similar_memory import AddDraftAndRetrieveSimilarMemory
from .add_history import AddHistory
from .add_memory import AddMemory
from .base_memory_tool import BaseMemoryTool
from .delegate_task import DelegateTask
from .delete_memory import DeleteMemory
from .memory_handler import MemoryHandler
from .profile_handler import ProfileHandler
from .read_all_profiles import ReadAllProfiles
from .read_history import ReadHistory
from .retrieve_memory import RetrieveMemory
from .retrieve_recent_memory import RetrieveRecentMemory
from .update_memory import UpdateMemory
from .update_memory_v2 import UpdateMemoryV2
from .update_profile import UpdateProfile
from .history.add_history import AddHistory
from .history.read_history import ReadHistory
from .profiles.add_draft_and_read_all_profiles import AddDraftAndReadAllProfiles
from .profiles.profile_handler import ProfileHandler
from .profiles.read_all_profiles import ReadAllProfiles
from .profiles.update_profile import UpdateProfile
from .vector.add_draft_and_retrieve_similar_memory import AddDraftAndRetrieveSimilarMemory
from .vector.add_memory import AddMemory
from .vector.delete_memory import DeleteMemory
from .vector.memory_handler import MemoryHandler
from .vector.retrieve_memory import RetrieveMemory
from .vector.retrieve_recent_memory import RetrieveRecentMemory
from .vector.update_memory import UpdateMemory
from .vector.update_memory_v2 import UpdateMemoryV2
from ...core import R
__all__ = [
"AddDraftAndReadAllProfiles",
"AddDraftAndRetrieveSimilarMemory",
"AddHistory",
"AddMemory",
# Base
"BaseMemoryTool",
"DelegateTask",
"DeleteMemory",
"MemoryHandler",
# History
"AddHistory",
"ReadHistory",
# Profiles
"AddDraftAndReadAllProfiles",
"ProfileHandler",
"ReadAllProfiles",
"ReadHistory",
"UpdateProfile",
# Vector
"AddDraftAndRetrieveSimilarMemory",
"AddMemory",
"DeleteMemory",
"MemoryHandler",
"RetrieveMemory",
"RetrieveRecentMemory",
"UpdateMemory",
"UpdateMemoryV2",
"UpdateProfile",
]
for name in __all__:
tool_class = globals()[name]
R.op.register()(tool_class)
# Only register classes that inherit from BaseMemoryTool
if isinstance(tool_class, type) and issubclass(tool_class, BaseMemoryTool) and tool_class is not BaseMemoryTool:
R.op.register()(tool_class)

View file

View file

@ -2,10 +2,10 @@
from loguru import logger
from .base_memory_tool import BaseMemoryTool
from ...core.enumeration import MemoryType
from ...core.schema import ToolCall, MemoryNode, Message
from ...core.utils import format_messages
from ..base_memory_tool import BaseMemoryTool
from ....core.enumeration import MemoryType
from ....core.schema import ToolCall, MemoryNode, Message
from ....core.utils import format_messages
class AddHistory(BaseMemoryTool):

View file

@ -2,8 +2,8 @@
from loguru import logger
from .base_memory_tool import BaseMemoryTool
from ...core.schema import MemoryNode, ToolCall
from ..base_memory_tool import BaseMemoryTool
from ....core.schema import MemoryNode, ToolCall
class ReadHistory(BaseMemoryTool):

View file

View file

@ -2,9 +2,9 @@
from loguru import logger
from .base_memory_tool import BaseMemoryTool
from .profile_handler import ProfileHandler
from ...core.schema import ToolCall
from ..base_memory_tool import BaseMemoryTool
from ....core.schema import ToolCall
class AddDraftAndReadAllProfiles(BaseMemoryTool):

View file

@ -4,9 +4,9 @@ from pathlib import Path
from loguru import logger
from ...core.enumeration import MemoryType
from ...core.schema import MemoryNode
from ...core.utils import CacheHandler, deduplicate_memories
from ....core.enumeration import MemoryType
from ....core.schema import MemoryNode
from ....core.utils import CacheHandler, deduplicate_memories
class ProfileHandler:

View file

@ -2,9 +2,9 @@
from loguru import logger
from .base_memory_tool import BaseMemoryTool
from .profile_handler import ProfileHandler
from ...core.schema import ToolCall
from ..base_memory_tool import BaseMemoryTool
from ....core.schema import ToolCall
class ReadAllProfiles(BaseMemoryTool):

View file

@ -2,9 +2,9 @@
from loguru import logger
from .base_memory_tool import BaseMemoryTool
from .profile_handler import ProfileHandler
from ...core.schema import ToolCall
from ..base_memory_tool import BaseMemoryTool
from ....core.schema import ToolCall
class UpdateProfile(BaseMemoryTool):

View file

View file

@ -2,10 +2,10 @@
from loguru import logger
from .base_memory_tool import BaseMemoryTool
from .memory_handler import MemoryHandler
from ...core.schema import ToolCall, MemoryNode
from ...core.utils import deduplicate_memories
from ..base_memory_tool import BaseMemoryTool
from ....core.schema import ToolCall, MemoryNode
from ....core.utils import deduplicate_memories
class AddDraftAndRetrieveSimilarMemory(BaseMemoryTool):

View file

@ -2,9 +2,9 @@
from loguru import logger
from .base_memory_tool import BaseMemoryTool
from .memory_handler import MemoryHandler
from ...core.schema import ToolCall
from ..base_memory_tool import BaseMemoryTool
from ....core.schema import ToolCall
class AddMemory(BaseMemoryTool):

View file

@ -2,9 +2,9 @@
from loguru import logger
from .base_memory_tool import BaseMemoryTool
from .memory_handler import MemoryHandler
from ...core.schema import ToolCall
from ..base_memory_tool import BaseMemoryTool
from ....core.schema import ToolCall
class DeleteMemory(BaseMemoryTool):

View file

@ -1,9 +1,9 @@
"""Memory handler"""
from ...core.context import ServiceContext
from ...core.enumeration import MemoryType
from ...core.schema import MemoryNode
from ...core.vector_store import BaseVectorStore
from ....core.context import ServiceContext
from ....core.enumeration import MemoryType
from ....core.schema import MemoryNode
from ....core.vector_store import BaseVectorStore
class MemoryHandler:

View file

@ -2,10 +2,10 @@
from loguru import logger
from .base_memory_tool import BaseMemoryTool
from .memory_handler import MemoryHandler
from ...core.schema import ToolCall, MemoryNode
from ...core.utils import deduplicate_memories
from ..base_memory_tool import BaseMemoryTool
from ....core.schema import ToolCall, MemoryNode
from ....core.utils import deduplicate_memories
class RetrieveMemory(BaseMemoryTool):

View file

@ -2,10 +2,10 @@
from loguru import logger
from .base_memory_tool import BaseMemoryTool
from .memory_handler import MemoryHandler
from ...core.schema import ToolCall, MemoryNode
from ...core.utils import deduplicate_memories
from ..base_memory_tool import BaseMemoryTool
from ....core.schema import ToolCall, MemoryNode
from ....core.utils import deduplicate_memories
class RetrieveRecentMemory(BaseMemoryTool):

View file

@ -2,9 +2,9 @@
from loguru import logger
from .base_memory_tool import BaseMemoryTool
from .memory_handler import MemoryHandler
from ...core.schema import ToolCall
from ..base_memory_tool import BaseMemoryTool
from ....core.schema import ToolCall
class UpdateMemory(BaseMemoryTool):

View file

@ -2,9 +2,9 @@
from loguru import logger
from .base_memory_tool import BaseMemoryTool
from .memory_handler import MemoryHandler
from ...core.schema import ToolCall
from ..base_memory_tool import BaseMemoryTool
from ....core.schema import ToolCall
class UpdateMemoryV2(BaseMemoryTool):

View file

@ -17,34 +17,42 @@ async def test_reme():
{
"role": "user",
"content": "你好我是张伟今年28岁是一名软件工程师。",
"time_created": "2026-01-29 10:00:00",
},
{
"role": "assistant",
"content": "你好张伟!很高兴认识你。作为一名软件工程师,你主要从事什么方向的开发工作呢?",
"time_created": "2026-01-29 10:00:05",
},
{
"role": "user",
"content": "我主要做后端开发擅长Python和Go语言。最近在研究AI Agent相关的技术。",
"time_created": "2026-01-29 10:00:30",
},
{
"role": "assistant",
"content": "很棒Python和Go都是非常实用的语言。AI Agent是当前很热门的方向你在这方面有什么具体的研究重点吗",
"time_created": "2026-01-29 10:00:35",
},
{
"role": "user",
"content": "我特别关注记忆系统的设计希望能让AI Agent具有长期记忆能力。我的工作地点在北京平时喜欢看技术博客和参加技术分享会。",
"time_created": "2026-01-29 10:01:00",
},
{
"role": "assistant",
"content": "记忆系统确实是AI Agent的核心能力之一。北京有很多优秀的技术社区和活动相信你能找到很多志同道合的朋友。",
"time_created": "2026-01-29 10:01:05",
},
{
"role": "user",
"content": "是的我每周末都会去参加一些技术沙龙。对了我的邮箱是zhangwei@example.com如果有好的技术资料可以发给我。",
"time_created": "2026-01-29 10:01:30",
},
{
"role": "assistant",
"content": "好的我记下了。保持学习的热情很重要祝你在AI Agent领域的研究越来越深入",
"time_created": "2026-01-29 10:01:35",
},
]