TutorialsDemo: Research Team
Demo: Research Team
A router agent coordinates research tasks between specialized agents using the project mod for structured task delegation.
Demo: Research Team with Router
A router agent coordinates research tasks between specialized agents using the project mod. This demo showcases structured task delegation, agent groups, and multi-step workflows.
Important: Please stop your network if you are running them.
What You'll Learn
- Using the project mod for task management
- Router-based coordination patterns
- Agent groups and permissions
- Event-driven task delegation with
send_event - Project templates
Architecture
┌─────────────────┐
Research │ Router │
Request ────►│ (coordinator) │
└────────┬────────┘
│ task.delegate
┌──────────────┴──────────────┐
│ │
▼ ▼
┌─────────────┐ ┌───────────┐
│ web-searcher│ │ analyst │
│ (find info) │ │ (reason) │
└──────┬──────┘ └─────┬─────┘
│ │
└──────────────┬──────────────┘
│ task.complete
▼
┌─────────────────┐
│ Router │
│ (compile report)│
└─────────────────┘Agents
| Agent | Group | Role | Responsibilities |
|---|---|---|---|
| router | coordinators | Coordinator | Receives requests, delegates tasks, compiles results |
| web-searcher | researchers | Information Gatherer | Web searches, Hacker News queries |
| analyst | researchers | Synthesizer | Analysis and conclusions |
Prerequisites
- OpenAgents installed (
pip install openagents) - An LLM API key
# Optional: Set the OpenAI base URL
export OPENAI_BASE_URL="your-base-url-here"
# Must: Set the OpenAI API key
export OPENAI_API_KEY="your-key-here"Optional for better web search:
export BRAVE_API_KEY="your-brave-key" # Falls back to DuckDuckGo if not setQuick Start
Terminal 1: Start the Network
openagents network start demos/03_research_team/Terminal 2: Start the Router
openagents agent start demos/03_research_team/agents/router.yamlTerminal 3: Start the Web Searcher
openagents agent start demos/03_research_team/agents/web_searcher.yamlTerminal 4: Start the Analyst
openagents agent start demos/03_research_team/agents/analyst.yamlConnect with Studio
Open http://localhost:8050 and connect to localhost:8700.
Try It Out
- Navigate to the Projects section in Studio
- Create a new project using the "Research Task" template
- Set the goal to something like:
"Research the pros and cons of Rust vs Go for backend development"

- Watch as the agents collaborate:
- Router receives the request and delegates to web-searcher
- Web-searcher gathers information and returns findings
- Router delegates analysis to the analyst
- Analyst synthesizes and provides conclusions
- Router compiles and delivers the final report
Configuration Deep Dive
Network Configuration with Agent Groups
# demos/03_research_team/network.yaml
network:
name: "ResearchTeam"
default_agent_group: guest
# Define agent groups with different permissions
agent_groups:
coordinators:
description: "Router agents that coordinate research tasks"
password_hash:
researchers:
description: "Worker agents that execute research tasks"
password_hash: ...
mods:
# Default workspace for event handling
- name: "openagents.mods.workspace.default"
enabled: true
config:
custom_events_enabled: true
# Project management mod
- name: "openagents.mods.workspace.project"
enabled: true
config:
max_concurrent_projects: 5
project_templates:
research_task:
name: "Research Task"
description: "Structured research with search and analysis"
agent_groups: ["coordinators", "researchers"]
context: |
Research Task Workflow:
1. Router receives request and delegates search
2. Web-searcher returns findings
3. Router delegates analysis
4. Analyst synthesizes conclusions
5. Router compiles final reportRouter Agent Configuration
# demos/03_research_team/agents/router.yaml
type: "openagents.agents.collaborator_agent.CollaboratorAgent"
agent_id: "router"
config:
model_name: "gpt-4o-mini"
# Limit iterations to prevent duplicate sends
max_iterations: 3
instruction: |
You are the ROUTER - a simple coordinator.
Make ONE action per event, then call finish().
YOUR TOOLS:
- send_project_message(project_id, content) - message the user
- send_event(event_name, destination_id, payload) - delegate tasks
- complete_project(project_id, summary) - finish the project
- finish() - MUST call this last
RULE: Make ONE tool call, then call finish(). Never call send_event twice.
react_to_all_messages: false
triggers:
- event: "project.notification.started"
instruction: |
Project started. Do these 2 things IN ORDER:
1. send_event(event_name="task.delegate", destination_id="web-searcher",
payload={"task_id": "s1", "query": "[the goal from payload]"})
2. finish()
- event: "task.complete"
instruction: |
A task completed. Check who sent it:
IF source is "web-searcher":
1. send_event to analyst with the results
2. finish()
IF source is "analyst":
1. send_project_message with summary
2. complete_project
3. finish()
mods:
- name: "openagents.mods.workspace.project"
enabled: true
- name: "openagents.mods.workspace.default"
enabled: true
connection:
host: "localhost"
port: 8700
transport: "grpc"
agent_group: "coordinators" # Join as coordinatorKey Patterns
Event-Driven Task Delegation
The router uses send_event to delegate work:
# Conceptual flow
send_event(
event_name="task.delegate",
destination_id="web-searcher",
payload={"task_id": "s1", "query": "Rust vs Go comparison"}
)Workers respond with:
send_event(
event_name="task.complete",
destination_id="router",
payload={"task_id": "s1", "results": "...findings..."}
)Preventing Duplicate Actions
The router uses max_iterations: 3 and explicit rules to prevent:
- Multiple event sends per trigger
- Infinite delegation loops
- Duplicate messages to users
Project Templates
Templates provide structure for different research types:
| Template | Use Case |
|---|---|
research_task | General research with search and analysis |
comparison_research | Compare two or more topics |
deep_dive | In-depth single topic investigation |
Web Search Tools
# demos/03_research_team/tools/web_search.py
def search_web(query: str, count: int = 5) -> str:
"""Search using Brave (if API key) or DuckDuckGo."""
# Tries Brave first, falls back to DuckDuckGo
def fetch_webpage(url: str, max_length: int = 8000) -> str:
"""Fetch and extract text content from a webpage."""
def search_hackernews(query: str, count: int = 5) -> str:
"""Search Hacker News using Algolia API."""Customization Ideas
Add More Specialists
# agents/fact_checker.yaml
agent_id: "fact-checker"
config:
instruction: |
You verify claims made by other agents.
Cross-reference sources and flag inconsistencies.Create Custom Templates
# In network.yaml
project_templates:
competitor_analysis:
name: "Competitor Analysis"
description: "Research competitors in a market"
context: |
1. Identify key competitors
2. Gather data on each
3. Compare strengths/weaknesses
4. Provide strategic recommendationsTroubleshooting
Router Sending Duplicate Events
- Verify
max_iterations: 3is set - Check that instructions say "make ONE tool call"
- Ensure
finish()is called after each action
Tasks Not Completing
- Check all agents are connected
- Verify agent_group assignments match permissions
- Look for errors in agent terminals
Web Search Failing
- Without BRAVE_API_KEY, it falls back to DuckDuckGo
- Check network connectivity
- Some queries may be rate-limited
What's Next?
- Grammar Check Forum - See the forum mod with automatic grammar checking
- Python Interface Tutorial - Deep dive into programmatic agent development
Was this helpful?