247 lines
7.7 KiB
Python
247 lines
7.7 KiB
Python
"""
|
|
Palace commands — bridge Evennia to the local MemPalace memory system.
|
|
"""
|
|
|
|
import json
|
|
import subprocess
|
|
from evennia.commands.command import Command
|
|
from evennia import create_object, search_object
|
|
|
|
PALACE_SCRIPT = "/root/wizards/bezalel/evennia/palace_search.py"
|
|
|
|
|
|
def _search_mempalace(query, wing=None, room=None, n=5, fleet=False):
|
|
"""Call the helper script and return parsed results."""
|
|
cmd = ["/root/wizards/bezalel/hermes/venv/bin/python", PALACE_SCRIPT, query]
|
|
cmd.append(wing or "none")
|
|
cmd.append(room or "none")
|
|
cmd.append(str(n))
|
|
if fleet:
|
|
cmd.append("--fleet")
|
|
try:
|
|
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
|
data = json.loads(result.stdout)
|
|
return data.get("results", [])
|
|
except Exception:
|
|
return []
|
|
|
|
|
|
def _get_wing(caller):
|
|
"""Return the caller's wing, defaulting to their key or 'general'."""
|
|
return caller.db.wing if caller.attributes.has("wing") else (caller.key.lower() if caller.key else "general")
|
|
|
|
|
|
class CmdPalaceSearch(Command):
|
|
"""
|
|
Search your memory palace.
|
|
|
|
Usage:
|
|
palace/search <query>
|
|
palace/search <query> [--room <room>]
|
|
palace/recall <topic>
|
|
palace/file <name> = <content>
|
|
palace/status
|
|
"""
|
|
|
|
key = "palace"
|
|
aliases = ["pal"]
|
|
locks = "cmd:all()"
|
|
help_category = "Mind Palace"
|
|
|
|
def func(self):
|
|
if not self.args.strip():
|
|
self.caller.msg("Usage: palace/search <query> | palace/recall <topic> | palace/file <name> = <content> | palace/status")
|
|
return
|
|
|
|
parts = self.args.strip().split(" ", 1)
|
|
subcmd = parts[0].lower()
|
|
rest = parts[1] if len(parts) > 1 else ""
|
|
|
|
if subcmd == "search":
|
|
self._do_search(rest)
|
|
elif subcmd == "recall":
|
|
self._do_recall(rest)
|
|
elif subcmd == "file":
|
|
self._do_file(rest)
|
|
elif subcmd == "status":
|
|
self._do_status()
|
|
else:
|
|
self._do_search(self.args.strip())
|
|
|
|
def _do_search(self, query):
|
|
if not query:
|
|
self.caller.msg("Search for what?")
|
|
return
|
|
self.caller.msg(f"Searching the palace for: |c{query}|n...")
|
|
wing = _get_wing(self.caller)
|
|
results = _search_mempalace(query, wing=wing)
|
|
if not results:
|
|
self.caller.msg("The palace is silent on that matter.")
|
|
return
|
|
|
|
lines = []
|
|
for i, r in enumerate(results[:5], 1):
|
|
room = r.get("room", "unknown")
|
|
source = r.get("source", "unknown")
|
|
content = r.get("content", "")[:400]
|
|
lines.append(f"\n|g[{i}]|n |c{room}|n — |x{source}|n")
|
|
lines.append(f"{content}\n")
|
|
self.caller.msg("\n".join(lines))
|
|
|
|
def _do_recall(self, topic):
|
|
if not topic:
|
|
self.caller.msg("Recall what topic?")
|
|
return
|
|
results = _search_mempalace(topic, wing=_get_wing(self.caller), n=1)
|
|
if not results:
|
|
self.caller.msg("Nothing to recall.")
|
|
return
|
|
|
|
r = results[0]
|
|
content = r.get("content", "")
|
|
source = r.get("source", "unknown")
|
|
|
|
from typeclasses.memory_object import MemoryObject
|
|
obj = create_object(
|
|
MemoryObject,
|
|
key=f"memory:{topic}",
|
|
location=self.caller.location,
|
|
)
|
|
obj.db.memory_content = content
|
|
obj.db.source_file = source
|
|
obj.db.room_name = r.get("room", "general")
|
|
self.caller.location.msg_contents(
|
|
f"$You() conjure() a memory shard from the palace: |m{obj.key}|n.",
|
|
from_obj=self.caller,
|
|
)
|
|
|
|
def _do_file(self, rest):
|
|
if "=" not in rest:
|
|
self.caller.msg("Usage: palace/file <name> = <content>")
|
|
return
|
|
name, content = rest.split("=", 1)
|
|
name = name.strip()
|
|
content = content.strip()
|
|
if not name or not content:
|
|
self.caller.msg("Both name and content are required.")
|
|
return
|
|
|
|
from typeclasses.memory_object import MemoryObject
|
|
obj = create_object(
|
|
MemoryObject,
|
|
key=f"memory:{name}",
|
|
location=self.caller.location,
|
|
)
|
|
obj.db.memory_content = content
|
|
obj.db.source_file = f"filed by {self.caller.key}"
|
|
obj.db.room_name = self.caller.location.key if self.caller.location else "general"
|
|
self.caller.location.msg_contents(
|
|
f"$You() file() a new memory in the palace: |m{obj.key}|n.",
|
|
from_obj=self.caller,
|
|
)
|
|
|
|
def _do_status(self):
|
|
cmd = [
|
|
"/root/wizards/bezalel/hermes/venv/bin/mempalace",
|
|
"--palace", "/root/wizards/bezalel/.mempalace/palace",
|
|
"status"
|
|
]
|
|
try:
|
|
result = subprocess.run(cmd, capture_output=True, text=True, timeout=15)
|
|
self.caller.msg(result.stdout or result.stderr)
|
|
except Exception as e:
|
|
self.caller.msg(f"Could not reach the palace: {e}")
|
|
|
|
|
|
class CmdRecall(Command):
|
|
"""
|
|
Recall a memory from the palace.
|
|
|
|
Usage:
|
|
recall <query>
|
|
recall <query> --fleet
|
|
recall <query> --room <room>
|
|
"""
|
|
|
|
key = "recall"
|
|
aliases = ["remember", "mem"]
|
|
locks = "cmd:all()"
|
|
help_category = "Mind Palace"
|
|
|
|
def func(self):
|
|
if not self.args.strip():
|
|
self.caller.msg("Recall what? Usage: recall <query> [--fleet] [--room <room>]")
|
|
return
|
|
|
|
args = self.args.strip()
|
|
fleet = "--fleet" in args
|
|
room = None
|
|
|
|
if "--room" in args:
|
|
parts = args.split("--room")
|
|
args = parts[0].strip()
|
|
room = parts[1].strip().split()[0] if len(parts) > 1 else None
|
|
|
|
if "--fleet" in args:
|
|
args = args.replace("--fleet", "").strip()
|
|
|
|
self.caller.msg(f"Recalling from the {'fleet' if fleet else 'personal'} palace: |c{args}|n...")
|
|
|
|
wing = None if fleet else _get_wing(self.caller)
|
|
results = _search_mempalace(args, wing=wing, room=room, n=5, fleet=fleet)
|
|
if not results:
|
|
self.caller.msg("The palace is silent on that matter.")
|
|
return
|
|
|
|
lines = []
|
|
for i, r in enumerate(results[:5], 1):
|
|
room_name = r.get("room", "unknown")
|
|
source = r.get("source", "unknown")
|
|
content = r.get("content", "")[:400]
|
|
wing_label = r.get("wing", "unknown")
|
|
wing_tag = f" |y[{wing_label}]|n" if fleet else ""
|
|
lines.append(f"\n|g[{i}]|n |c{room_name}|n{wing_tag} — |x{source}|n")
|
|
lines.append(f"{content}\n")
|
|
self.caller.msg("\n".join(lines))
|
|
|
|
|
|
class CmdEnterRoom(Command):
|
|
"""
|
|
Enter a room in the mind palace by topic.
|
|
|
|
Usage:
|
|
enter room <topic>
|
|
"""
|
|
|
|
key = "enter room"
|
|
aliases = ["enter palace", "go room"]
|
|
locks = "cmd:all()"
|
|
help_category = "Mind Palace"
|
|
|
|
def func(self):
|
|
if not self.args.strip():
|
|
self.caller.msg("Enter which room? Usage: enter room <topic>")
|
|
return
|
|
|
|
topic = self.args.strip().lower().replace(" ", "-")
|
|
wing = _get_wing(self.caller)
|
|
room_key = f"palace:{wing}:{topic}"
|
|
|
|
# Search for existing room
|
|
rooms = search_object(room_key, typeclass="typeclasses.palace_room.PalaceRoom")
|
|
if rooms:
|
|
room = rooms[0]
|
|
else:
|
|
# Create the room dynamically
|
|
from typeclasses.palace_room import PalaceRoom
|
|
room = create_object(
|
|
PalaceRoom,
|
|
key=room_key,
|
|
)
|
|
room.db.memory_topic = topic
|
|
room.db.wing = wing
|
|
room.update_description()
|
|
|
|
self.caller.move_to(room, move_type="teleport")
|
|
self.caller.msg(f"You step into the |c{topic}|n room of your mind palace.")
|