feat: add mempalace_tool for vector memory #234

Closed
gemini wants to merge 2 commits from feat/mempalace-tool-1775642243437 into main
2 changed files with 134 additions and 0 deletions

View File

@@ -158,6 +158,7 @@ def _discover_tools():
"tools.send_message_tool",
# "tools.honcho_tools", # Removed — Honcho is now a memory provider plugin
"tools.homeassistant_tool",
"tools.mempalace_tool",
]
import importlib
for mod_name in _modules:

133
tools/mempalace_tool.py Normal file
View File

@@ -0,0 +1,133 @@
"""
mempalace_tool.py — Interface for the MemPalace vector memory system.
This tool allows the agent to search and record memories in a ChromaDB-backed
vector database via the fleet_api.
"""
import json
import os
import requests
import logging
from typing import Dict, Any, List, Optional
from tools.registry import registry
logger = logging.getLogger(__name__)
# Default to the fleet_api port defined in the-nexus
MEMPALACE_API_URL = os.environ.get("MEMPALACE_API_URL", "http://127.0.0.1:7771")
def mempalace_tool(
action: str,
query: str = "",
text: str = "",
room: Optional[str] = None,
wing: Optional[str] = None,
n_results: int = 10,
metadata: Optional[Dict[str, Any]] = None,
) -> str:
"""
Interface for the MemPalace vector memory system.
Actions:
search: Search the palace for relevant memories.
record: Add a new memory to the palace.
wings: List available wizard wings.
"""
try:
if action == "search":
if not query:
return json.dumps({"success": False, "error": "Query is required for search."})
params = {"q": query, "n": n_results}
if room:
params["room"] = room
response = requests.get(f"{MEMPALACE_API_URL}/search", params=params, timeout=10)
response.raise_for_status()
return json.dumps({"success": True, "data": response.json()})
elif action == "record":
if not text:
return json.dumps({"success": False, "error": "Text is required for record."})
payload = {
"text": text,
"room": room or "general",
"wing": wing,
"metadata": metadata or {}
}
response = requests.post(f"{MEMPALACE_API_URL}/record", json=payload, timeout=10)
response.raise_for_status()
return json.dumps({"success": True, "data": response.json()})
elif action == "wings":
response = requests.get(f"{MEMPALACE_API_URL}/wings", timeout=10)
response.raise_for_status()
return json.dumps({"success": True, "data": response.json()})
else:
return json.dumps({"success": False, "error": f"Unknown action: {action}"})
except requests.exceptions.ConnectionError:
return json.dumps({
"success": False,
"error": f"Could not connect to MemPalace API at {MEMPALACE_API_URL}. Ensure fleet_api.py is running."
})
except Exception as e:
logger.error(f"MemPalace tool error: {e}")
return json.dumps({"success": False, "error": str(e)})
MEMPALACE_SCHEMA = {
"name": "mempalace",
"description": (
"Search or record memories in the MemPalace vector database. "
"Use this for long-term, high-volume memory that exceeds the curated memory limits. "
"The palace is organized into 'rooms' (e.g., forge, hermes, nexus, issues, experiments)."
),
"parameters": {
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": ["search", "record", "wings"],
"description": "The action to perform."
},
"query": {
"type": "string",
"description": "The search query (required for 'search')."
},
"text": {
"type": "string",
"description": "The memory text to record (required for 'record')."
},
"room": {
"type": "string",
"description": "Optional room filter or target room (e.g., forge, hermes, nexus, issues, experiments)."
},
"wing": {
"type": "string",
"description": "Optional wizard wing filter."
},
"n_results": {
"type": "integer",
"default": 10,
"description": "Maximum number of results to return."
},
"metadata": {
"type": "object",
"description": "Optional metadata for the memory (only for 'record')."
}
},
"required": ["action"]
}
}
registry.register(
name="mempalace",
toolset="mempalace",
schema=MEMPALACE_SCHEMA,
handler=lambda args, **kw: mempalace_tool(**args),
emoji="🏛️",
)