Merge branch 'main' into perplexity/pr-checklist-ci
Some checks failed
PR Checklist / pr-checklist (pull_request) Failing after 1m18s
Some checks failed
PR Checklist / pr-checklist (pull_request) Failing after 1m18s
This commit is contained in:
10
SOUL.md
10
SOUL.md
@@ -1,3 +1,13 @@
|
|||||||
|
<!--
|
||||||
|
NOTE: This is the BITCOIN INSCRIPTION version of SOUL.md.
|
||||||
|
It is the immutable on-chain conscience. Do not modify this content.
|
||||||
|
|
||||||
|
The NARRATIVE identity document (for onboarding, Audio Overviews,
|
||||||
|
and system prompts) lives in timmy-home/SOUL.md.
|
||||||
|
|
||||||
|
See: #388, #378 for the divergence audit.
|
||||||
|
-->
|
||||||
|
|
||||||
# SOUL.md
|
# SOUL.md
|
||||||
|
|
||||||
## Inscription 1 — The Immutable Conscience
|
## Inscription 1 — The Immutable Conscience
|
||||||
|
|||||||
@@ -1,28 +1,37 @@
|
|||||||
"""Retrieval Order Enforcer — L0 through L5 memory hierarchy.
|
"""Retrieval Order Enforcer — L0 through L5 memory hierarchy.
|
||||||
|
|
||||||
Ensures the agent checks durable memory before falling back to free generation.
|
Ensures the agent checks durable memory before falling back to free generation.
|
||||||
Gracefully degrades if any layer is unavailable (ONNX issues, missing files, etc).
|
Gracefully degrades if any layer is unavailable (missing files, etc).
|
||||||
|
|
||||||
Layer order:
|
Layer order:
|
||||||
L0: Identity (~/.mempalace/identity.txt)
|
L0: Identity (~/.mempalace/identity.txt)
|
||||||
L1: Palace rooms (mempalace CLI search)
|
L1: Palace rooms (SovereignStore — SQLite + FTS5 + HRR, zero API calls)
|
||||||
L2: Session scratch (~/.hermes/scratchpad/{session_id}.json)
|
L2: Session scratch (~/.hermes/scratchpad/{session_id}.json)
|
||||||
L3: Gitea artifacts (API search for issues/PRs)
|
L3: Gitea artifacts (API search for issues/PRs)
|
||||||
L4: Procedures (skills directory search)
|
L4: Procedures (skills directory search)
|
||||||
L5: Free generation (only if L0-L4 produced nothing)
|
L5: Free generation (only if L0-L4 produced nothing)
|
||||||
|
|
||||||
Refs: Epic #367, Sub-issue #369
|
Refs: Epic #367, Sub-issue #369, Wiring: #383
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import subprocess
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Sovereign Store (replaces mempalace CLI subprocess)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
try:
|
||||||
|
from .sovereign_store import SovereignStore
|
||||||
|
except ImportError:
|
||||||
|
try:
|
||||||
|
from sovereign_store import SovereignStore
|
||||||
|
except ImportError:
|
||||||
|
SovereignStore = None # type: ignore[misc,assignment]
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Constants
|
# Constants
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -30,7 +39,7 @@ from typing import Optional
|
|||||||
IDENTITY_PATH = Path.home() / ".mempalace" / "identity.txt"
|
IDENTITY_PATH = Path.home() / ".mempalace" / "identity.txt"
|
||||||
SCRATCHPAD_DIR = Path.home() / ".hermes" / "scratchpad"
|
SCRATCHPAD_DIR = Path.home() / ".hermes" / "scratchpad"
|
||||||
SKILLS_DIR = Path.home() / ".hermes" / "skills"
|
SKILLS_DIR = Path.home() / ".hermes" / "skills"
|
||||||
MEMPALACE_BIN = "/Library/Frameworks/Python.framework/Versions/3.12/bin/mempalace"
|
SOVEREIGN_DB = Path.home() / ".hermes" / "palace" / "sovereign.db"
|
||||||
|
|
||||||
# Patterns that indicate a recall-style query
|
# Patterns that indicate a recall-style query
|
||||||
RECALL_PATTERNS = re.compile(
|
RECALL_PATTERNS = re.compile(
|
||||||
@@ -42,6 +51,23 @@ RECALL_PATTERNS = re.compile(
|
|||||||
r")\b"
|
r")\b"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Singleton store instance (lazy-init)
|
||||||
|
_store: Optional["SovereignStore"] = None
|
||||||
|
|
||||||
|
|
||||||
|
def _get_store() -> Optional["SovereignStore"]:
|
||||||
|
"""Lazy-init the SovereignStore singleton."""
|
||||||
|
global _store
|
||||||
|
if _store is not None:
|
||||||
|
return _store
|
||||||
|
if SovereignStore is None:
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
_store = SovereignStore(db_path=str(SOVEREIGN_DB))
|
||||||
|
return _store
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# L0: Identity
|
# L0: Identity
|
||||||
@@ -62,25 +88,33 @@ def load_identity() -> str:
|
|||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# L1: Palace search
|
# L1: Palace search (now via SovereignStore — zero subprocess, zero API)
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
def search_palace(query: str) -> str:
|
def search_palace(query: str, room: Optional[str] = None) -> str:
|
||||||
"""Search the mempalace for relevant memories. Gracefully degrades on failure."""
|
"""Search the sovereign memory store for relevant memories.
|
||||||
|
|
||||||
|
Uses SovereignStore (SQLite + FTS5 + HRR) for hybrid keyword + semantic
|
||||||
|
search. No subprocess calls, no ONNX, no API keys.
|
||||||
|
|
||||||
|
Gracefully degrades to empty string if store is unavailable.
|
||||||
|
"""
|
||||||
|
store = _get_store()
|
||||||
|
if store is None:
|
||||||
|
return ""
|
||||||
try:
|
try:
|
||||||
bin_path = MEMPALACE_BIN if os.path.exists(MEMPALACE_BIN) else "mempalace"
|
results = store.search(query, room=room, limit=5, min_trust=0.2)
|
||||||
result = subprocess.run(
|
if not results:
|
||||||
[bin_path, "search", query],
|
return ""
|
||||||
capture_output=True,
|
lines = []
|
||||||
text=True,
|
for r in results:
|
||||||
timeout=10,
|
trust = r.get("trust_score", 0.5)
|
||||||
)
|
room_name = r.get("room", "general")
|
||||||
if result.returncode == 0 and result.stdout.strip():
|
content = r.get("content", "")
|
||||||
return result.stdout.strip()
|
lines.append(f" [{room_name}] (trust:{trust:.2f}) {content}")
|
||||||
except (FileNotFoundError, subprocess.TimeoutExpired, OSError):
|
return "\n".join(lines)
|
||||||
# ONNX issues (#373) or mempalace not installed — degrade gracefully
|
except Exception:
|
||||||
pass
|
return ""
|
||||||
return ""
|
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -177,7 +211,6 @@ def search_skills(query: str) -> str:
|
|||||||
try:
|
try:
|
||||||
content = skill_md.read_text(encoding="utf-8").lower()
|
content = skill_md.read_text(encoding="utf-8").lower()
|
||||||
if any(t in content for t in terms):
|
if any(t in content for t in terms):
|
||||||
# Extract title from frontmatter
|
|
||||||
title = skill_dir.name
|
title = skill_dir.name
|
||||||
matches.append(f" skill: {title}")
|
matches.append(f" skill: {title}")
|
||||||
except OSError:
|
except OSError:
|
||||||
@@ -236,7 +269,7 @@ def enforce_retrieval_order(
|
|||||||
result["context"] += f"## Identity\n{identity}\n\n"
|
result["context"] += f"## Identity\n{identity}\n\n"
|
||||||
result["layers_checked"].append("L0")
|
result["layers_checked"].append("L0")
|
||||||
|
|
||||||
# L1: Palace search
|
# L1: Palace search (SovereignStore — zero API, zero subprocess)
|
||||||
palace_results = search_palace(query)
|
palace_results = search_palace(query)
|
||||||
if palace_results:
|
if palace_results:
|
||||||
result["context"] += f"## Palace Memory\n{palace_results}\n\n"
|
result["context"] += f"## Palace Memory\n{palace_results}\n\n"
|
||||||
|
|||||||
Reference in New Issue
Block a user