Add MCP delegation bridge and diagram tools
**Features Added**: 1. **Agent Registry (agent_registry.py)** - Thread-safe global singleton for MCP tool access to Agent instance - Enables MCP tools to call Agent.delegate() without circular imports - Registered at bot startup in bot_runner.py 2. **Sub-Agent Manager (sub_agent_manager.py)** - Watchdog system monitoring sub-agent lifecycle - Detects hung agents (5min timeout, 30s check interval) - Auto-cleanup and status tracking 3. **delegate_task MCP Tool (mcp_tools.py)** - Exposes Agent.delegate() to Claude via MCP protocol - Enables parallel sub-agent execution via tool calls - Supports specialist prompts and agent ID caching 4. **Memory Write Locks (memory_system.py)** - Thread-safe writes to prevent file corruption - Protects write_memory(), update_soul(), update_user() 5. **Diagram Tools** - Mermaid MCP server (flowcharts, sequence diagrams, etc.) - Excalidraw MCP server (hand-drawn style diagrams) - Config files in config/ directory 6. **Adapter Improvements** - Enhanced error handling across all adapters - Unified logging patterns **Testing**: Ready for parallel sub-agent testing Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,7 @@ Inspired by OpenClaw's memory implementation but simplified.
|
||||
|
||||
import hashlib
|
||||
import sqlite3
|
||||
import threading
|
||||
import time
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
@@ -84,6 +85,11 @@ class MemorySystem:
|
||||
self.db = sqlite3.connect(str(self.db_path), check_same_thread=False)
|
||||
self.db.row_factory = sqlite3.Row
|
||||
|
||||
# Write lock for concurrent sub-agent access to shared memory files.
|
||||
# Prevents race conditions when multiple sub-agents write to the same
|
||||
# daily log or MEMORY.md simultaneously.
|
||||
self._write_lock = threading.Lock()
|
||||
|
||||
self._init_schema()
|
||||
self._init_special_files()
|
||||
|
||||
@@ -575,32 +581,34 @@ class MemorySystem:
|
||||
return compact
|
||||
|
||||
def write_memory(self, content: str, daily: bool = True) -> None:
|
||||
"""Write to memory file."""
|
||||
if daily:
|
||||
today = datetime.now().strftime("%Y-%m-%d")
|
||||
file_path = self.memory_dir / f"{today}.md"
|
||||
else:
|
||||
file_path = self.workspace_dir / "MEMORY.md"
|
||||
"""Write to memory file. Thread-safe via _write_lock."""
|
||||
with self._write_lock:
|
||||
if daily:
|
||||
today = datetime.now().strftime("%Y-%m-%d")
|
||||
file_path = self.memory_dir / f"{today}.md"
|
||||
else:
|
||||
file_path = self.workspace_dir / "MEMORY.md"
|
||||
|
||||
if file_path.exists():
|
||||
existing = file_path.read_text(encoding="utf-8")
|
||||
content = f"{existing}\n\n{content}"
|
||||
if file_path.exists():
|
||||
existing = file_path.read_text(encoding="utf-8")
|
||||
content = f"{existing}\n\n{content}"
|
||||
|
||||
file_path.write_text(content, encoding="utf-8")
|
||||
self.index_file(file_path)
|
||||
print(f"Written to {file_path.name}")
|
||||
file_path.write_text(content, encoding="utf-8")
|
||||
self.index_file(file_path)
|
||||
print(f"Written to {file_path.name}")
|
||||
|
||||
def update_soul(self, content: str, append: bool = False) -> None:
|
||||
"""Update SOUL.md (agent personality)."""
|
||||
soul_file = self.workspace_dir / "SOUL.md"
|
||||
"""Update SOUL.md (agent personality). Thread-safe via _write_lock."""
|
||||
with self._write_lock:
|
||||
soul_file = self.workspace_dir / "SOUL.md"
|
||||
|
||||
if append and soul_file.exists():
|
||||
existing = soul_file.read_text(encoding="utf-8")
|
||||
content = f"{existing}\n\n{content}"
|
||||
if append and soul_file.exists():
|
||||
existing = soul_file.read_text(encoding="utf-8")
|
||||
content = f"{existing}\n\n{content}"
|
||||
|
||||
soul_file.write_text(content, encoding="utf-8")
|
||||
self.index_file(soul_file)
|
||||
print("Updated SOUL.md")
|
||||
soul_file.write_text(content, encoding="utf-8")
|
||||
self.index_file(soul_file)
|
||||
print("Updated SOUL.md")
|
||||
|
||||
def update_user(
|
||||
self, username: str, content: str, append: bool = False
|
||||
|
||||
Reference in New Issue
Block a user