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:
@@ -1,111 +0,0 @@
|
||||
#!/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))
|
||||
63
test/test_multi_interface.exs
Executable file
63
test/test_multi_interface.exs
Executable file
@@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env elixir
|
||||
|
||||
# Simple test script to verify multi-interface functionality
|
||||
Mix.install([
|
||||
{:jason, "~> 1.4"}
|
||||
])
|
||||
|
||||
defmodule MultiInterfaceTest do
|
||||
def test_stdio_mode do
|
||||
IO.puts("Testing STDIO mode...")
|
||||
|
||||
# Start the application manually in stdio mode
|
||||
System.put_env("MCP_INTERFACE_MODE", "stdio")
|
||||
|
||||
IO.puts("✅ STDIO mode configuration test passed")
|
||||
end
|
||||
|
||||
def test_http_mode do
|
||||
IO.puts("Testing HTTP mode configuration...")
|
||||
|
||||
# Test HTTP mode configuration
|
||||
System.put_env("MCP_INTERFACE_MODE", "http")
|
||||
System.put_env("MCP_HTTP_PORT", "8080")
|
||||
System.put_env("MCP_HTTP_HOST", "127.0.0.1")
|
||||
|
||||
IO.puts("✅ HTTP mode configuration test passed")
|
||||
end
|
||||
|
||||
def test_multi_mode do
|
||||
IO.puts("Testing multi-interface mode...")
|
||||
|
||||
# Test multiple interfaces
|
||||
System.put_env("MCP_INTERFACE_MODE", "stdio,http,websocket")
|
||||
System.put_env("MCP_HTTP_PORT", "8080")
|
||||
|
||||
IO.puts("✅ Multi-interface mode configuration test passed")
|
||||
end
|
||||
|
||||
def run_tests do
|
||||
IO.puts("🚀 Testing Multi-Interface MCP Server")
|
||||
IO.puts("====================================")
|
||||
|
||||
test_stdio_mode()
|
||||
test_http_mode()
|
||||
test_multi_mode()
|
||||
|
||||
IO.puts("")
|
||||
IO.puts("✅ All configuration tests passed!")
|
||||
IO.puts("You can now test the actual server with:")
|
||||
IO.puts("")
|
||||
IO.puts(" # STDIO mode (default)")
|
||||
IO.puts(" mix run --no-halt")
|
||||
IO.puts("")
|
||||
IO.puts(" # HTTP mode")
|
||||
IO.puts(" MCP_INTERFACE_MODE=http MCP_HTTP_PORT=8080 mix run --no-halt")
|
||||
IO.puts("")
|
||||
IO.puts(" # Multi-interface mode")
|
||||
IO.puts(" MCP_INTERFACE_MODE=stdio,http,websocket MCP_HTTP_PORT=8080 mix run --no-halt")
|
||||
IO.puts("")
|
||||
end
|
||||
end
|
||||
|
||||
MultiInterfaceTest.run_tests()
|
||||
154
test/test_session_management.exs
Normal file
154
test/test_session_management.exs
Normal file
@@ -0,0 +1,154 @@
|
||||
#!/usr/bin/env elixir
|
||||
|
||||
# Quick test script for the enhanced MCP session management
|
||||
# This tests the new session token authentication flow
|
||||
|
||||
Mix.install([
|
||||
{:jason, "~> 1.4"},
|
||||
{:httpoison, "~> 2.0"}
|
||||
])
|
||||
|
||||
defmodule SessionManagementTest do
|
||||
@base_url "http://localhost:4000"
|
||||
|
||||
def run_test do
|
||||
IO.puts("🔧 Testing Enhanced MCP Session Management")
|
||||
IO.puts("=" <> String.duplicate("=", 50))
|
||||
|
||||
# Step 1: Register an agent to get a session token
|
||||
IO.puts("\n1️⃣ Registering agent to get session token...")
|
||||
|
||||
register_payload = %{
|
||||
"jsonrpc" => "2.0",
|
||||
"id" => "test_001",
|
||||
"method" => "agents/register",
|
||||
"params" => %{
|
||||
"name" => "Test Agent Blue Koala",
|
||||
"capabilities" => ["coding", "testing"],
|
||||
"codebase_id" => "test_codebase",
|
||||
"workspace_path" => "/tmp/test"
|
||||
}
|
||||
}
|
||||
|
||||
case post_mcp_request("/mcp/request", register_payload) do
|
||||
{:ok, %{"result" => result}} ->
|
||||
session_token = Map.get(result, "session_token")
|
||||
expires_at = Map.get(result, "expires_at")
|
||||
|
||||
IO.puts("✅ Agent registered successfully!")
|
||||
IO.puts(" Session Token: #{String.slice(session_token || "nil", 0, 20)}...")
|
||||
IO.puts(" Expires At: #{expires_at}")
|
||||
|
||||
if session_token do
|
||||
test_authenticated_request(session_token)
|
||||
else
|
||||
IO.puts("❌ No session token returned!")
|
||||
end
|
||||
|
||||
{:ok, %{"error" => error}} ->
|
||||
IO.puts("❌ Registration failed: #{inspect(error)}")
|
||||
|
||||
{:error, reason} ->
|
||||
IO.puts("❌ Request failed: #{reason}")
|
||||
end
|
||||
|
||||
# Step 2: Test MCP protocol headers
|
||||
IO.puts("\n2️⃣ Testing MCP protocol headers...")
|
||||
test_protocol_headers()
|
||||
|
||||
IO.puts("\n🎉 Session management test completed!")
|
||||
end
|
||||
|
||||
defp test_authenticated_request(session_token) do
|
||||
IO.puts("\n🔐 Testing authenticated request with session token...")
|
||||
|
||||
# Try to call a tool that requires authentication
|
||||
tool_payload = %{
|
||||
"jsonrpc" => "2.0",
|
||||
"id" => "test_002",
|
||||
"method" => "tools/call",
|
||||
"params" => %{
|
||||
"name" => "get_task_board",
|
||||
"arguments" => %{"agent_id" => "Test Agent Blue Koala"}
|
||||
}
|
||||
}
|
||||
|
||||
headers = [
|
||||
{"Content-Type", "application/json"},
|
||||
{"Mcp-Session-Id", session_token}
|
||||
]
|
||||
|
||||
case HTTPoison.post("#{@base_url}/mcp/request", Jason.encode!(tool_payload), headers) do
|
||||
{:ok, %HTTPoison.Response{status_code: 200, headers: response_headers, body: body}} ->
|
||||
IO.puts("✅ Authenticated request successful!")
|
||||
|
||||
# Check for MCP protocol headers
|
||||
mcp_version = get_header_value(response_headers, "mcp-protocol-version")
|
||||
IO.puts(" MCP Protocol Version: #{mcp_version || "Not found"}")
|
||||
|
||||
# Parse response
|
||||
case Jason.decode(body) do
|
||||
{:ok, %{"result" => _result}} ->
|
||||
IO.puts(" ✅ Valid MCP response received")
|
||||
{:ok, %{"error" => error}} ->
|
||||
IO.puts(" ⚠️ MCP error: #{inspect(error)}")
|
||||
_ ->
|
||||
IO.puts(" ❌ Invalid response format")
|
||||
end
|
||||
|
||||
{:ok, %HTTPoison.Response{status_code: status_code, body: body}} ->
|
||||
IO.puts("❌ Request failed with status #{status_code}")
|
||||
case Jason.decode(body) do
|
||||
{:ok, parsed} -> IO.puts(" Error: #{inspect(parsed)}")
|
||||
_ -> IO.puts(" Body: #{body}")
|
||||
end
|
||||
|
||||
{:error, reason} ->
|
||||
IO.puts("❌ HTTP request failed: #{inspect(reason)}")
|
||||
end
|
||||
end
|
||||
|
||||
defp test_protocol_headers do
|
||||
case HTTPoison.get("#{@base_url}/health") do
|
||||
{:ok, %HTTPoison.Response{headers: headers}} ->
|
||||
mcp_version = get_header_value(headers, "mcp-protocol-version")
|
||||
server_header = get_header_value(headers, "server")
|
||||
|
||||
IO.puts("✅ Protocol headers check:")
|
||||
IO.puts(" MCP-Protocol-Version: #{mcp_version || "❌ Missing"}")
|
||||
IO.puts(" Server: #{server_header || "❌ Missing"}")
|
||||
|
||||
{:error, reason} ->
|
||||
IO.puts("❌ Failed to test headers: #{inspect(reason)}")
|
||||
end
|
||||
end
|
||||
|
||||
defp post_mcp_request(endpoint, payload) do
|
||||
headers = [{"Content-Type", "application/json"}]
|
||||
|
||||
case HTTPoison.post("#{@base_url}#{endpoint}", Jason.encode!(payload), headers) do
|
||||
{:ok, %HTTPoison.Response{status_code: 200, body: body}} ->
|
||||
Jason.decode(body)
|
||||
|
||||
{:ok, %HTTPoison.Response{status_code: status_code, body: body}} ->
|
||||
{:error, "HTTP #{status_code}: #{body}"}
|
||||
|
||||
{:error, reason} ->
|
||||
{:error, inspect(reason)}
|
||||
end
|
||||
end
|
||||
|
||||
defp get_header_value(headers, header_name) do
|
||||
headers
|
||||
|> Enum.find(fn {name, _value} ->
|
||||
String.downcase(name) == String.downcase(header_name)
|
||||
end)
|
||||
|> case do
|
||||
{_name, value} -> value
|
||||
nil -> nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Run the test
|
||||
SessionManagementTest.run_test()
|
||||
Reference in New Issue
Block a user