Files
timmy-config/hermes-sovereign/mempalace/wakeup.py

162 lines
4.9 KiB
Python
Raw Normal View History

"""Wake-up Protocol — session start context injection.
Generates 300-900 tokens of context when a new Hermes session starts.
Loads identity, recent palace context, and fleet status.
Refs: Epic #367, Sub-issue #372
"""
from __future__ import annotations
import json
import os
import subprocess
import time
from pathlib import Path
# ---------------------------------------------------------------------------
# Constants
# ---------------------------------------------------------------------------
IDENTITY_PATH = Path.home() / ".mempalace" / "identity.txt"
MEMPALACE_BIN = "/Library/Frameworks/Python.framework/Versions/3.12/bin/mempalace"
FLEET_STATUS_PATH = Path.home() / ".hermes" / "fleet_status.json"
WAKEUP_CACHE_PATH = Path.home() / ".hermes" / "last_wakeup.txt"
WAKEUP_CACHE_TTL = 300 # 5 minutes — don't regenerate if recent
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
def _load_identity() -> str:
"""Read the agent identity file."""
try:
if IDENTITY_PATH.exists():
text = IDENTITY_PATH.read_text(encoding="utf-8").strip()
# Cap at ~150 tokens for wake-up brevity
words = text.split()
if len(words) > 150:
text = " ".join(words[:150]) + "..."
return text
except (OSError, PermissionError):
pass
return ""
def _palace_context() -> str:
"""Run mempalace wake-up command for recent context. Degrades gracefully."""
try:
bin_path = MEMPALACE_BIN if os.path.exists(MEMPALACE_BIN) else "mempalace"
result = subprocess.run(
[bin_path, "wake-up"],
capture_output=True,
text=True,
timeout=10,
)
if result.returncode == 0 and result.stdout.strip():
return result.stdout.strip()
except (FileNotFoundError, subprocess.TimeoutExpired, OSError):
# ONNX issues (#373) or CLI not available — degrade gracefully
pass
return ""
def fleet_status_summary() -> str:
"""Read cached fleet status for lightweight session context."""
try:
if FLEET_STATUS_PATH.exists():
data = json.loads(FLEET_STATUS_PATH.read_text(encoding="utf-8"))
lines = ["## Fleet Status"]
if isinstance(data, dict):
for agent, status in data.items():
if isinstance(status, dict):
state = status.get("state", "unknown")
last_seen = status.get("last_seen", "?")
lines.append(f" {agent}: {state} (last: {last_seen})")
else:
lines.append(f" {agent}: {status}")
if len(lines) > 1:
return "\n".join(lines)
except (OSError, json.JSONDecodeError):
pass
return ""
def _check_cache() -> str:
"""Return cached wake-up if fresh enough."""
try:
if WAKEUP_CACHE_PATH.exists():
age = time.time() - WAKEUP_CACHE_PATH.stat().st_mtime
if age < WAKEUP_CACHE_TTL:
return WAKEUP_CACHE_PATH.read_text(encoding="utf-8").strip()
except OSError:
pass
return ""
def _write_cache(content: str) -> None:
"""Cache the wake-up content."""
try:
WAKEUP_CACHE_PATH.parent.mkdir(parents=True, exist_ok=True)
WAKEUP_CACHE_PATH.write_text(content, encoding="utf-8")
except OSError:
pass
# ---------------------------------------------------------------------------
# Main entry point
# ---------------------------------------------------------------------------
def palace_wakeup(force: bool = False) -> str:
"""Generate wake-up context for a new session. ~300-900 tokens.
Args:
force: If True, bypass the 5-minute cache and regenerate.
Returns:
Formatted context string suitable for prepending to the system prompt.
"""
# Check cache first (avoids redundant work on rapid session restarts)
if not force:
cached = _check_cache()
if cached:
return cached
parts = []
# L0: Identity
identity = _load_identity()
if identity:
parts.append(f"## Identity\n{identity}")
# L1: Recent palace context
palace = _palace_context()
if palace:
parts.append(palace)
# Fleet status (lightweight)
fleet = fleet_status_summary()
if fleet:
parts.append(fleet)
# Timestamp
parts.append(f"## Session\nWake-up generated: {time.strftime('%Y-%m-%d %H:%M:%S')}")
content = "\n\n".join(parts)
# Cache for TTL
_write_cache(content)
return content
# ---------------------------------------------------------------------------
# CLI entry point for testing
# ---------------------------------------------------------------------------
if __name__ == "__main__":
print(palace_wakeup(force=True))