Skip to main content

Agent Orchestration

WASP supports multiple concurrent autonomous agents, each with its own goal queue, context, and execution lifecycle. The AgentOrchestrator manages the full multi-agent system.

AgentOrchestrator (src/agent_manager/__init__.py)

The orchestrator:

  • Creates and destroys agent instances
  • Manages the global token budget (100,000 tokens/minute across all agents)
  • Enforces CPU threshold (85% → pause all agent work)
  • Routes messages between agents
  • Provides the agent_manager skill interface

Global Resource Limits

SettingDefaultDescription
AGENTS_MAX_ACTIVE10Max concurrent active agents
AGENTS_MAX_CONCURRENT_STEPS5Max steps across all agents per tick
AGENTS_CPU_THRESHOLD85%CPU pause threshold
AGENTS_GLOBAL_TOKEN_BUDGET_PER_MINUTE100,000Rate limit across all agents

Agent Structure

Each agent is a persistent entity with:

@dataclass
class Agent:
id: str # UUID
name: str # Human-readable name
objective: str # Current high-level objective
status: AgentStatus # IDLE, RUNNING, PAUSED, ERROR, ARCHIVED
priority: int # 1-10 (default: 6 for agent-created goals)
goal_queue: list[str] # Queue of goal IDs
current_goal_id: str # Active goal
chat_id: str # Notification target
created_at: datetime
last_active: datetime

Agents are stored in:

  • Redis: agents hash (fast reads)
  • PostgreSQL: agents table (durable, survives Redis flush)

Agent Lifecycle

create_agent("Monitor BTC", priority=6)


Agent(status=IDLE)

▼ goal assigned via create_goal()
Agent(status=RUNNING, current_goal=...)

├── goal completes → Agent(status=IDLE)
│ │
│ ▼ next goal in queue, or IDLE

├── manual pause → Agent(status=PAUSED)
│ │
│ ▼ resume → Agent(status=RUNNING)

└── archive → Agent(status=ARCHIVED)
→ deleted from Redis + PostgreSQL

Creating Agents via Skill

agent_manager(
action="create",
name="crypto_watcher",
objective="Monitor BTC and ETH prices, alert if >5% change",
priority=7
)

The AgentManagerSkill is registered as a built-in skill and late-wired to the AgentOrchestrator at startup.

Agent Communication

Agents communicate via the event bus (Redis Streams):

  • Agents can publish events via EventType.AGENT_MESSAGE
  • The orchestrator routes agent messages to the correct handler
  • Agents can trigger sub-goals in other agents

AgentTickJob (every 15 sec)

async def run(self):
# Check CPU backpressure
cpu = await asyncio.to_thread(psutil.cpu_percent, interval=0.1)
if cpu > threshold:
return

# Get all running agents, sorted by priority
running_agents = sorted(
[a for a in agents if a.status == RUNNING],
key=lambda a: a.priority,
reverse=True,
)

# Process up to MAX_CONCURRENT_STEPS across all agents
tasks = []
for agent in running_agents[:max_concurrent]:
tasks.append(orchestrator.tick_agent(agent))
await asyncio.gather(*tasks)

Recurring Agent Goals

When a reminder has an agent_id attached (set when an agent creates a reminder):

  • ReminderCheckerJob fires the reminder
  • Calls agent_orchestrator.create_agent_goal() to restart the agent's cycle
  • The agent picks up the new goal on the next tick

This enables agents to create recurring self-sustaining loops.

Deleting Agents

agent_manager(action="archive", agent_id="...")

delete_agent() removes from both Redis AND PostgreSQL to prevent stale duplicates from reappearing after restarts.

Meta-Agent Supervisor (optional)

When META_AGENT_ENABLED=true, the MetaSupervisor:

  • Coordinates teams of up to 5 agents
  • Decomposes complex objectives across multiple specialized agents
  • Manages inter-agent dependencies
  • Triggered via meta_orchestrate skill

Currently disabled by default — enable for advanced multi-agent scenarios.