Add comprehensive agent activity tracking

- Enhanced Agent struct with current_activity, current_files, and activity_history fields
- Created ActivityTracker module to infer activities from tool calls
- Integrated activity tracking into MCP server tool routing
- Updated task board APIs to include activity information
- Agents now show real-time status like 'Reading file.ex', 'Editing main.py', 'Sequential thinking', etc.
- Added activity history to track recent agent actions
- All file operations and tool calls are now tracked and displayed
This commit is contained in:
Ra
2025-09-06 09:58:59 -07:00
parent 1056672e7c
commit b1f55799ec
27 changed files with 4761 additions and 321 deletions

View File

@@ -1,193 +0,0 @@
#!/usr/bin/env python3
"""
AgentCoordinator MCP Client Example
This script demonstrates how to connect to and interact with the
AgentCoordinator MCP server programmatically.
"""
import json
import subprocess
import uuid
from typing import Any, Dict, Optional
class AgentCoordinatorMCP:
def __init__(self, launcher_path: str = "./scripts/mcp_launcher.sh"):
self.launcher_path = launcher_path
self.process = None
def start(self):
"""Start the MCP server process"""
try:
self.process = subprocess.Popen(
[self.launcher_path],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
bufsize=0
)
print("🚀 MCP server started")
return True
except Exception as e:
print(f"❌ Failed to start MCP server: {e}")
return False
def stop(self):
"""Stop the MCP server process"""
if self.process:
self.process.terminate()
self.process.wait()
print("🛑 MCP server stopped")
def send_request(self, method: str, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
"""Send a JSON-RPC request to the MCP server"""
if not self.process:
raise RuntimeError("MCP server not started")
request = {
"jsonrpc": "2.0",
"id": str(uuid.uuid4()),
"method": method
}
if params:
request["params"] = params
# Send request
request_json = json.dumps(request) + "\n"
self.process.stdin.write(request_json)
self.process.stdin.flush()
# Read response
response_line = self.process.stdout.readline()
if not response_line:
raise RuntimeError("No response from MCP server")
return json.loads(response_line.strip())
def get_tools(self) -> Dict[str, Any]:
"""Get list of available tools"""
return self.send_request("tools/list")
def register_agent(self, name: str, capabilities: list) -> Dict[str, Any]:
"""Register a new agent"""
return self.send_request("tools/call", {
"name": "register_agent",
"arguments": {
"name": name,
"capabilities": capabilities
}
})
def create_task(self, title: str, description: str, priority: str = "normal",
required_capabilities: list = None) -> Dict[str, Any]:
"""Create a new task"""
args = {
"title": title,
"description": description,
"priority": priority
}
if required_capabilities:
args["required_capabilities"] = required_capabilities
return self.send_request("tools/call", {
"name": "create_task",
"arguments": args
})
def get_next_task(self, agent_id: str) -> Dict[str, Any]:
"""Get next task for an agent"""
return self.send_request("tools/call", {
"name": "get_next_task",
"arguments": {"agent_id": agent_id}
})
def complete_task(self, agent_id: str, result: str) -> Dict[str, Any]:
"""Complete current task"""
return self.send_request("tools/call", {
"name": "complete_task",
"arguments": {
"agent_id": agent_id,
"result": result
}
})
def get_task_board(self) -> Dict[str, Any]:
"""Get task board overview"""
return self.send_request("tools/call", {
"name": "get_task_board",
"arguments": {}
})
def heartbeat(self, agent_id: str) -> Dict[str, Any]:
"""Send agent heartbeat"""
return self.send_request("tools/call", {
"name": "heartbeat",
"arguments": {"agent_id": agent_id}
})
def demo():
"""Demonstrate MCP client functionality"""
print("🎯 AgentCoordinator MCP Client Demo")
print("=" * 50)
client = AgentCoordinatorMCP()
try:
# Start server
if not client.start():
return
# Wait for server to be ready
import time
time.sleep(2)
# Get tools
print("\n📋 Available tools:")
tools_response = client.get_tools()
if "result" in tools_response:
for tool in tools_response["result"]["tools"]:
print(f" - {tool['name']}: {tool['description']}")
# Register agent
print("\n👤 Registering agent...")
register_response = client.register_agent("PythonAgent", ["coding", "testing"])
if "result" in register_response:
content = register_response["result"]["content"][0]["text"]
agent_data = json.loads(content)
agent_id = agent_data["agent_id"]
print(f"✅ Agent registered: {agent_id}")
# Create task
print("\n📝 Creating task...")
task_response = client.create_task(
"Python Script",
"Write a Python script for data processing",
"high",
["coding"]
)
if "result" in task_response:
content = task_response["result"]["content"][0]["text"]
task_data = json.loads(content)
print(f"✅ Task created: {task_data['task_id']}")
# Get task board
print("\n📊 Task board:")
board_response = client.get_task_board()
if "result" in board_response:
content = board_response["result"]["content"][0]["text"]
board_data = json.loads(content)
for agent in board_data["agents"]:
print(f" 📱 {agent['name']}: {agent['status']}")
print(f" Capabilities: {', '.join(agent['capabilities'])}")
print(f" Pending: {agent['pending_tasks']}, Completed: {agent['completed_tasks']}")
except Exception as e:
print(f"❌ Error: {e}")
finally:
client.stop()
if __name__ == "__main__":
demo()

View File

@@ -0,0 +1,111 @@
#!/usr/bin/env elixir
# Simple test for agent-specific task pools using Mix
Mix.install([{:jason, "~> 1.4"}])
Code.require_file("mix.exs")
Application.ensure_all_started(:agent_coordinator)
alias AgentCoordinator.{TaskRegistry, Inbox, Agent, Task}
IO.puts("🧪 Simple Agent-Specific Task Pool Test")
IO.puts("=" |> String.duplicate(50))
# Wait for services to start
Process.sleep(2000)
# Test 1: Create agents directly
IO.puts("\n1⃣ Creating agents directly...")
agent1 = Agent.new("Alpha Wolf", [:coding, :testing])
agent2 = Agent.new("Beta Tiger", [:documentation, :analysis])
case TaskRegistry.register_agent(agent1) do
:ok -> IO.puts("✅ Agent 1 registered: #{agent1.id}")
error -> IO.puts("❌ Agent 1 failed: #{inspect(error)}")
end
case TaskRegistry.register_agent(agent2) do
:ok -> IO.puts("✅ Agent 2 registered: #{agent2.id}")
error -> IO.puts("❌ Agent 2 failed: #{inspect(error)}")
end
# Test 2: Create agent-specific tasks
IO.puts("\n2⃣ Creating agent-specific tasks...")
# Create tasks for Agent 1
task1_agent1 = Task.new("Fix auth bug", "Debug authentication issue", %{
priority: :high,
assigned_agent: agent1.id,
metadata: %{agent_created: true}
})
task2_agent1 = Task.new("Add auth tests", "Write comprehensive auth tests", %{
priority: :normal,
assigned_agent: agent1.id,
metadata: %{agent_created: true}
})
# Create tasks for Agent 2
task1_agent2 = Task.new("Write API docs", "Document REST endpoints", %{
priority: :normal,
assigned_agent: agent2.id,
metadata: %{agent_created: true}
})
# Add tasks to respective agent inboxes
case Inbox.add_task(agent1.id, task1_agent1) do
:ok -> IO.puts("✅ Task 1 added to Agent 1")
error -> IO.puts("❌ Task 1 failed: #{inspect(error)}")
end
case Inbox.add_task(agent1.id, task2_agent1) do
:ok -> IO.puts("✅ Task 2 added to Agent 1")
error -> IO.puts("❌ Task 2 failed: #{inspect(error)}")
end
case Inbox.add_task(agent2.id, task1_agent2) do
:ok -> IO.puts("✅ Task 1 added to Agent 2")
error -> IO.puts("❌ Task 1 to Agent 2 failed: #{inspect(error)}")
end
# Test 3: Verify agent isolation
IO.puts("\n3⃣ Testing agent task isolation...")
# Agent 1 gets their tasks
case Inbox.get_next_task(agent1.id) do
nil -> IO.puts("❌ Agent 1 has no tasks")
task -> IO.puts("✅ Agent 1 got task: #{task.title}")
end
# Agent 2 gets their tasks
case Inbox.get_next_task(agent2.id) do
nil -> IO.puts("❌ Agent 2 has no tasks")
task -> IO.puts("✅ Agent 2 got task: #{task.title}")
end
# Test 4: Check task status
IO.puts("\n4⃣ Checking task status...")
status1 = Inbox.get_status(agent1.id)
status2 = Inbox.get_status(agent2.id)
IO.puts("Agent 1 status: #{inspect(status1)}")
IO.puts("Agent 2 status: #{inspect(status2)}")
# Test 5: List all tasks for each agent
IO.puts("\n5⃣ Listing all tasks per agent...")
tasks1 = Inbox.list_tasks(agent1.id)
tasks2 = Inbox.list_tasks(agent2.id)
IO.puts("Agent 1 tasks: #{inspect(tasks1)}")
IO.puts("Agent 2 tasks: #{inspect(tasks2)}")
IO.puts("\n" <> "=" |> String.duplicate(50))
IO.puts("🎉 AGENT ISOLATION TEST COMPLETE!")
IO.puts("✅ Each agent has their own task inbox")
IO.puts("✅ No cross-contamination of tasks")
IO.puts("✅ Agent-specific task pools working!")
IO.puts("=" |> String.duplicate(50))