feat(memory): add history management tools with dynamic registration

This commit is contained in:
jinli.yl 2026-01-23 00:11:00 +08:00
parent af44052a57
commit 3c272ac859
6 changed files with 106 additions and 46 deletions

View file

@ -11,6 +11,6 @@ __all__ = [
"ThinkTool",
]
R.op.register()(ExecuteCode)
R.op.register()(ExecuteShell)
R.op.register()(ThinkTool)
for name in __all__:
tool_class = globals()[name]
R.op.register()(tool_class)

View file

@ -1,15 +1,20 @@
"""memory tools"""
from .add_history import AddHistory
from .base_memory_tool import BaseMemoryTool
from .read_history import ReadHistory
from .read_user_profile import ReadUserProfile
from .update_user_profile import UpdateUserProfile
from ...core import R
__all__ = [
"AddHistory",
"BaseMemoryTool",
"ReadHistory",
"ReadUserProfile",
"UpdateUserProfile",
]
R.op.register()(ReadUserProfile)
R.op.register()(UpdateUserProfile)
for name in __all__:
tool_class = globals()[name]
R.op.register()(tool_class)

View file

@ -0,0 +1,47 @@
"""Add history tool"""
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
class AddHistory(BaseMemoryTool):
"""Tool to add historical dialogue to vector store"""
def __init__(self, **kwargs):
kwargs["enable_multiple"] = False
super().__init__(**kwargs)
def _build_tool_call(self) -> ToolCall:
"""Build and return the tool call schema"""
return ToolCall(
**{
"description": "Add original history dialogue.",
"parameters": {
"type": "object",
"properties": {},
"required": [],
},
}
)
async def execute(self):
"""Execute the add history operation"""
self.context.messages = [Message(**m) if isinstance(m, dict) else m for m in self.context.messages]
history_content: str = (self.context.description + "\n" + format_messages(self.context.messages)).strip()
history_node = MemoryNode(
memory_type=MemoryType.HISTORY,
when_to_use=history_content[:100],
content=history_content,
author=self.author,
)
logger.info(f"Adding history node: {history_node.model_dump_json(indent=2, exclude={'content'})}")
vector_node = history_node.to_vector_node()
await self.vector_store.delete(vector_node.memory_id)
await self.vector_store.insert([vector_node])
return f"Successfully added history: {history_node.memory_id}"

View file

@ -0,0 +1,46 @@
"""Read history memory tool"""
from loguru import logger
from .base_memory_tool import BaseMemoryTool
from ...core.schema import MemoryNode, ToolCall
class ReadHistory(BaseMemoryTool):
"""Read history memory tool"""
def __init__(self, **kwargs):
kwargs["enable_multiple"] = False
super().__init__(**kwargs)
def _build_tool_call(self) -> ToolCall:
"""Build and return the tool call schema"""
return ToolCall(
**{
"description": "Read original history dialogue.",
"parameters": {
"type": "object",
"properties": {
"history_id": {
"type": "string",
"description": "history_id",
},
},
"required": ["history_id"],
},
},
)
async def execute(self):
history_id = self.context.history_id
nodes = await self.vector_store.get(vector_ids=[history_id])
if not nodes:
output = f"No history: {history_id}"
logger.warning(output)
return output
memory = MemoryNode.from_vector_node(nodes[0])
output = f"Historical Dialogue[{history_id}]\n{memory.content}"
logger.info(f"Successfully read history memory: {history_id}")
return output

View file

@ -11,6 +11,6 @@ __all__ = [
"TavilySearch",
]
R.op.register()(DashscopeSearch)
R.op.register()(MockSearch)
R.op.register()(TavilySearch)
for name in __all__:
tool_class = globals()[name]
R.op.register()(tool_class)

View file

@ -1,38 +0,0 @@
from loguru import logger
from ..base_memory_tool import BaseMemoryTool
from ...core.schema import MemoryNode
class ReadHistory(BaseMemoryTool):
def __init__(self, **kwargs):
kwargs["enable_multiple"] = False
super().__init__(**kwargs)
def _build_tool_description(self) -> str:
return "Read original history dialogue."
def _build_parameters(self) -> dict:
return {
"type": "object",
"properties": {
"history_id": {
"type": "string",
"description": "history_id",
},
},
"required": ["history_id"],
}
async def execute(self):
history_id = self.context.get("history_id", "")
nodes = await self.vector_store.get(vector_ids=[history_id])
if not nodes:
self.output = f"No history: {history_id}"
logger.warning(self.output)
return
memory = MemoryNode.from_vector_node(nodes[0])
self.output = f"### Historical Dialogue\n{memory.content}"
logger.info(f"Successfully read history memory: {history_id}")