1
0

feat: distributed brain architecture with rqlite and local embeddings (#118)

- Add new brain module with rqlite-based distributed memory and task queue
- Implement BrainClient for memory operations (store, recall, search)
- Implement DistributedWorker for continuous task processing
- Add local embeddings via sentence-transformers (all-MiniLM-L6-v2)
  - No OpenAI dependency, runs 100% local on CPU
  - 384-dim embeddings, 80MB model download
- Deprecate persona system (swarm/personas.py, persona_node.py)
- Deprecate hands system (hands/__init__.py, routes)
- Update marketplace, tools, hands routes for brain integration
- Add sentence-transformers and numpy to dependencies
- All changes backward compatible with deprecation warnings

Co-authored-by: Alexander Payne <apayne@MM.local>
This commit is contained in:
Alexander Whitestone
2026-03-02 07:31:15 -05:00
committed by GitHub
parent d9bb26b9c5
commit f7c574e0b2
15 changed files with 1486 additions and 1086 deletions

View File

@@ -1,7 +1,6 @@
"""Tools dashboard route — /tools endpoints.
Provides a dashboard page showing available tools, which agents have access
to which tools, and usage statistics.
Shows available tools and usage statistics.
"""
from pathlib import Path
@@ -10,9 +9,8 @@ from fastapi import APIRouter, Request
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates
from swarm import registry as swarm_registry
from swarm.personas import PERSONAS
from timmy.tools import get_all_available_tools, get_tool_stats
from brain.client import BrainClient
from timmy.tools import get_all_available_tools
router = APIRouter(tags=["tools"])
templates = Jinja2Templates(directory=str(Path(__file__).parent.parent / "templates"))
@@ -21,72 +19,27 @@ templates = Jinja2Templates(directory=str(Path(__file__).parent.parent / "templa
@router.get("/tools", response_class=HTMLResponse)
async def tools_page(request: Request):
"""Render the tools dashboard page."""
# Get all available tools
available_tools = get_all_available_tools()
brain = BrainClient()
# Get registered agents and their personas
agents = swarm_registry.list_agents()
agent_tools = []
# Get recent tool usage from brain memory
recent_memories = await brain.get_recent(hours=24, limit=50, sources=["timmy"])
for agent in agents:
# Determine which tools this agent has based on its capabilities/persona
tools_for_agent = []
# Check if it's a persona by name
persona_id = None
for pid, pdata in PERSONAS.items():
if pdata["name"].lower() == agent.name.lower():
persona_id = pid
break
if persona_id:
# Get tools for this persona
for tool_id, tool_info in available_tools.items():
if persona_id in tool_info["available_in"]:
tools_for_agent.append({
"id": tool_id,
"name": tool_info["name"],
"description": tool_info["description"],
})
elif agent.name.lower() == "timmy":
# Timmy has all tools
for tool_id, tool_info in available_tools.items():
tools_for_agent.append({
"id": tool_id,
"name": tool_info["name"],
"description": tool_info["description"],
})
# Get tool stats for this agent
stats = get_tool_stats(agent.id)
agent_tools.append({
"id": agent.id,
"name": agent.name,
"status": agent.status,
"tools": tools_for_agent,
"stats": stats,
# Simple tool list - no persona filtering
tool_list = []
for tool_id, tool_info in available_tools.items():
tool_list.append({
"id": tool_id,
"name": tool_info.get("name", tool_id),
"description": tool_info.get("description", ""),
"available": True,
})
# Calculate overall stats
total_calls = sum(a["stats"]["total_calls"] for a in agent_tools if a["stats"])
return templates.TemplateResponse(
request,
"tools.html",
{
"page_title": "Tools & Capabilities",
"available_tools": available_tools,
"agent_tools": agent_tools,
"total_calls": total_calls,
},
"request": request,
"tools": tool_list,
"recent_activity": len(recent_memories),
}
)
@router.get("/tools/api/stats")
async def tools_api_stats():
"""Return tool usage statistics as JSON."""
return {
"all_stats": get_tool_stats(),
"available_tools": list(get_all_available_tools().keys()),
}