stage-10: memory search with Ollama embeddings + SQLite

Semantic search over memory/*.md files using all-minilm embeddings.
Adds /search Discord command and `echo memory search/reindex` CLI.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
MoltBot Service
2026-02-13 16:49:57 +00:00
parent 0bc4b8cb3e
commit 0ecfa630eb
4 changed files with 1007 additions and 0 deletions

58
cli.py
View File

@@ -405,6 +405,52 @@ def _cron_disable(name: str):
print(f"Job '{name}' not found.")
def cmd_memory(args):
"""Handle memory subcommand."""
if args.memory_action == "search":
_memory_search(args.query)
elif args.memory_action == "reindex":
_memory_reindex()
def _memory_search(query: str):
"""Search memory and print results."""
from src.memory_search import search
try:
results = search(query)
except ConnectionError as e:
print(f"Error: {e}")
sys.exit(1)
if not results:
print("No results found (index may be empty — run `echo memory reindex`).")
return
for i, r in enumerate(results, 1):
score = r["score"]
print(f"\n--- Result {i} (score: {score:.3f}) ---")
print(f"File: {r['file']}")
preview = r["chunk"][:200]
if len(r["chunk"]) > 200:
preview += "..."
print(preview)
def _memory_reindex():
"""Rebuild memory search index."""
from src.memory_search import reindex
print("Reindexing memory files...")
try:
stats = reindex()
except ConnectionError as e:
print(f"Error: {e}")
sys.exit(1)
print(f"Done. Indexed {stats['files']} files, {stats['chunks']} chunks.")
def cmd_heartbeat(args):
"""Run heartbeat health checks."""
from src.heartbeat import run_heartbeat
@@ -515,6 +561,15 @@ def main():
secrets_sub.add_parser("test", help="Check required secrets")
# memory
memory_parser = sub.add_parser("memory", help="Memory search commands")
memory_sub = memory_parser.add_subparsers(dest="memory_action")
memory_search_p = memory_sub.add_parser("search", help="Search memory files")
memory_search_p.add_argument("query", help="Search query text")
memory_sub.add_parser("reindex", help="Rebuild memory search index")
# heartbeat
sub.add_parser("heartbeat", help="Run heartbeat health checks")
@@ -563,6 +618,9 @@ def main():
cmd_channel(a) if a.channel_action else (channel_parser.print_help() or sys.exit(0))
),
"send": cmd_send,
"memory": lambda a: (
cmd_memory(a) if a.memory_action else (memory_parser.print_help() or sys.exit(0))
),
"heartbeat": cmd_heartbeat,
"cron": lambda a: (
cmd_cron(a) if a.cron_action else (cron_parser.print_help() or sys.exit(0))