Files
agent-coordinator/examples/auto_heartbeat_demo.exs
Ra 943d8ad4d7 Fix inbox creation issues in agent coordinator
- Fixed Task.new/3 to handle both maps and keyword lists
- Added robust inbox existence checking in find_available_agent
- Ensure inbox creation during agent registration and task assignment
- Add helper function ensure_inbox_exists to avoid crashes
2025-08-23 14:46:28 -07:00

226 lines
7.3 KiB
Elixir

#!/usr/bin/env elixir
# Auto-heartbeat demo script
# This demonstrates the enhanced coordination system with automatic heartbeats
Mix.install([
{:jason, "~> 1.4"},
{:uuid, "~> 1.1"}
])
# Load the agent coordinator modules
Code.require_file("lib/agent_coordinator.ex")
Code.require_file("lib/agent_coordinator/agent.ex")
Code.require_file("lib/agent_coordinator/task.ex")
Code.require_file("lib/agent_coordinator/inbox.ex")
Code.require_file("lib/agent_coordinator/task_registry.ex")
Code.require_file("lib/agent_coordinator/mcp_server.ex")
Code.require_file("lib/agent_coordinator/auto_heartbeat.ex")
Code.require_file("lib/agent_coordinator/enhanced_mcp_server.ex")
Code.require_file("lib/agent_coordinator/client.ex")
defmodule AutoHeartbeatDemo do
@moduledoc """
Demonstrates the automatic heartbeat functionality
"""
def run do
IO.puts("🚀 Starting Auto-Heartbeat Demo")
IO.puts("================================")
# Start the core services
start_services()
# Demo 1: Basic client with auto-heartbeat
demo_basic_client()
# Demo 2: Multiple agents with coordination
demo_multiple_agents()
# Demo 3: Task creation and completion with heartbeats
demo_task_workflow()
IO.puts("\n✅ Demo completed!")
end
defp start_services do
IO.puts("\n📡 Starting coordination services...")
# Start registry for inboxes
Registry.start_link(keys: :unique, name: AgentCoordinator.InboxRegistry)
# Start dynamic supervisor
DynamicSupervisor.start_link(name: AgentCoordinator.InboxSupervisor, strategy: :one_for_one)
# Start task registry (without NATS for demo)
AgentCoordinator.TaskRegistry.start_link()
# Start MCP servers
AgentCoordinator.MCPServer.start_link()
AgentCoordinator.AutoHeartbeat.start_link()
AgentCoordinator.EnhancedMCPServer.start_link()
Process.sleep(500) # Let services initialize
IO.puts("✅ Services started")
end
defp demo_basic_client do
IO.puts("\n🤖 Demo 1: Basic Client with Auto-Heartbeat")
IO.puts("-------------------------------------------")
# Start a client session
{:ok, client} = AgentCoordinator.Client.start_session(
"DemoAgent1",
[:coding, :analysis],
auto_heartbeat: true,
heartbeat_interval: 3000 # 3 seconds for demo
)
# Get session info
{:ok, info} = AgentCoordinator.Client.get_session_info(client)
IO.puts("Agent registered: #{info.agent_name} (ID: #{info.agent_id})")
IO.puts("Auto-heartbeat enabled: #{info.auto_heartbeat_enabled}")
# Check task board to see the agent
{:ok, board} = AgentCoordinator.Client.get_task_board(client)
agent = Enum.find(board.agents, fn a -> a["agent_id"] == info.agent_id end)
IO.puts("Agent status: #{agent["status"]}")
IO.puts("Agent online: #{agent["online"]}")
IO.puts("Session active: #{agent["session_active"]}")
# Wait and check heartbeat activity
IO.puts("\n⏱️ Waiting 8 seconds to observe automatic heartbeats...")
Process.sleep(8000)
# Check board again
{:ok, updated_board} = AgentCoordinator.Client.get_task_board(client)
updated_agent = Enum.find(updated_board.agents, fn a -> a["agent_id"] == info.agent_id end)
IO.puts("Agent still online: #{updated_agent["online"]}")
IO.puts("Active sessions: #{updated_board.active_sessions}")
# Stop the client
AgentCoordinator.Client.stop_session(client)
IO.puts("✅ Client session stopped")
end
defp demo_multiple_agents do
IO.puts("\n👥 Demo 2: Multiple Agents Coordination")
IO.puts("--------------------------------------")
# Start multiple agents
agents = []
{:ok, agent1} = AgentCoordinator.Client.start_session("CodingAgent", [:coding, :testing])
{:ok, agent2} = AgentCoordinator.Client.start_session("AnalysisAgent", [:analysis, :documentation])
{:ok, agent3} = AgentCoordinator.Client.start_session("ReviewAgent", [:review, :analysis])
agents = [agent1, agent2, agent3]
# Check the task board
{:ok, board} = AgentCoordinator.Client.get_task_board(agent1)
IO.puts("Total agents: #{length(board.agents)}")
IO.puts("Active sessions: #{board.active_sessions}")
Enum.each(board.agents, fn agent ->
if agent["online"] do
IO.puts(" - #{agent["name"]}: #{Enum.join(agent["capabilities"], ", ")} (ONLINE)")
else
IO.puts(" - #{agent["name"]}: #{Enum.join(agent["capabilities"], ", ")} (offline)")
end
end)
# Demonstrate heartbeat coordination
IO.puts("\n💓 All agents sending heartbeats...")
# Each agent does some activity
Enum.each(agents, fn agent ->
AgentCoordinator.Client.heartbeat(agent)
end)
Process.sleep(1000)
# Check board after activity
{:ok, updated_board} = AgentCoordinator.Client.get_task_board(agent1)
online_count = Enum.count(updated_board.agents, fn a -> a["online"] end)
IO.puts("Agents online after heartbeat activity: #{online_count}/#{length(updated_board.agents)}")
# Cleanup
Enum.each(agents, &AgentCoordinator.Client.stop_session/1)
IO.puts("✅ All agents disconnected")
end
defp demo_task_workflow do
IO.puts("\n📋 Demo 3: Task Workflow with Heartbeats")
IO.puts("---------------------------------------")
# Start an agent
{:ok, agent} = AgentCoordinator.Client.start_session("WorkflowAgent", [:coding, :testing])
# Create a task
task_result = AgentCoordinator.Client.create_task(
agent,
"Fix Bug #123",
"Fix the authentication bug in user login",
%{
"priority" => "high",
"file_paths" => ["lib/auth.ex", "test/auth_test.exs"],
"required_capabilities" => ["coding", "testing"]
}
)
case task_result do
{:ok, task_data} ->
IO.puts("✅ Task created: #{task_data["task_id"]}")
# Check heartbeat metadata
if Map.has_key?(task_data, "_heartbeat_metadata") do
metadata = task_data["_heartbeat_metadata"]
IO.puts(" Heartbeat metadata: Agent #{metadata["agent_id"]} at #{metadata["timestamp"]}")
end
{:error, reason} ->
IO.puts("❌ Task creation failed: #{reason}")
end
# Try to get next task
case AgentCoordinator.Client.get_next_task(agent) do
{:ok, task} ->
if Map.has_key?(task, "task_id") do
IO.puts("📝 Got task: #{task["title"]}")
# Simulate some work
IO.puts("⚙️ Working on task...")
Process.sleep(2000)
# Complete the task
case AgentCoordinator.Client.complete_task(agent) do
{:ok, result} ->
IO.puts("✅ Task completed: #{result["task_id"]}")
{:error, reason} ->
IO.puts("❌ Task completion failed: #{reason}")
end
else
IO.puts("📝 No tasks available: #{task["message"]}")
end
{:error, reason} ->
IO.puts("❌ Failed to get task: #{reason}")
end
# Final status check
{:ok, final_info} = AgentCoordinator.Client.get_session_info(agent)
IO.puts("Final session info:")
IO.puts(" - Last heartbeat: #{final_info.last_heartbeat}")
IO.puts(" - Session duration: #{final_info.session_duration} seconds")
# Cleanup
AgentCoordinator.Client.stop_session(agent)
IO.puts("✅ Workflow demo completed")
end
end
# Run the demo
AutoHeartbeatDemo.run()