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:
76
agent_registry.py
Normal file
76
agent_registry.py
Normal file
@@ -0,0 +1,76 @@
|
||||
"""Agent Registry - Thread-safe global singleton for MCP tool access.
|
||||
|
||||
MCP tools are module-level functions that cannot access the Agent instance
|
||||
directly. This registry provides a thread-safe bridge so that tools like
|
||||
delegate_task can call Agent.delegate() without circular imports.
|
||||
|
||||
Usage:
|
||||
# At bot startup (bot_runner.py):
|
||||
from agent_registry import register_agent
|
||||
agent = Agent(...)
|
||||
register_agent(agent)
|
||||
|
||||
# In MCP tools (mcp_tools.py):
|
||||
from agent_registry import get_agent
|
||||
agent = get_agent()
|
||||
if agent:
|
||||
result = agent.delegate(task, specialist_prompt)
|
||||
"""
|
||||
|
||||
import threading
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from agent import Agent
|
||||
|
||||
# Module-level singleton state
|
||||
_agent: Optional['Agent'] = None
|
||||
_lock = threading.Lock()
|
||||
|
||||
|
||||
def register_agent(agent: 'Agent') -> None:
|
||||
"""Register the main Agent instance for MCP tool access.
|
||||
|
||||
Must be called exactly once at bot startup, after Agent is initialized.
|
||||
Thread-safe.
|
||||
|
||||
Args:
|
||||
agent: The main Agent instance (not a sub-agent).
|
||||
|
||||
Raises:
|
||||
ValueError: If agent is None or is a sub-agent.
|
||||
"""
|
||||
global _agent
|
||||
|
||||
if agent is None:
|
||||
raise ValueError("Cannot register None as the main agent")
|
||||
if getattr(agent, 'is_sub_agent', False):
|
||||
raise ValueError("Cannot register a sub-agent as the main agent")
|
||||
|
||||
with _lock:
|
||||
_agent = agent
|
||||
print(f"[AgentRegistry] Main agent registered (provider={agent.llm.provider})")
|
||||
|
||||
|
||||
def get_agent() -> Optional['Agent']:
|
||||
"""Get the registered main Agent instance.
|
||||
|
||||
Thread-safe. Returns None if no agent has been registered yet.
|
||||
|
||||
Returns:
|
||||
The main Agent instance, or None.
|
||||
"""
|
||||
with _lock:
|
||||
return _agent
|
||||
|
||||
|
||||
def clear_agent() -> None:
|
||||
"""Clear the registered agent (for testing or shutdown).
|
||||
|
||||
Thread-safe.
|
||||
"""
|
||||
global _agent
|
||||
|
||||
with _lock:
|
||||
_agent = None
|
||||
print("[AgentRegistry] Agent registry cleared")
|
||||
Reference in New Issue
Block a user