OpenAgents Logo
OpenAgentsDocumentation
TutorialsDemo: Tech News Stream

Demo: Tech News Stream

Agents that fetch tech news from Hacker News and stream it to a chatroom with live commentary. Features both YAML and Python-based agents.

Updated December 14, 2025
Contributors:
Nebu Kaga

Demo: Tech News Stream

Agents that fetch tech news from the web and stream it to a chatroom with live commentary. This demo showcases two different agent patterns: a Python-based programmatic agent and a YAML-configured LLM agent working together.

Important: Please stop your network if you are running them.

What You'll Learn

  • Creating Python-based programmatic agents (WorkerAgent)
  • Using custom tools for external API access
  • Combining programmatic and LLM agents
  • Event-driven triggers for selective responses

Architecture

┌─────────────────────────────────────────────────┐
│                                                 │
│  ┌─────────────┐        ┌─────────────────┐    │
│  │ news-hunter │        │   commentator   │    │
│  │   (Python)  │        │     (YAML)      │    │
│  │             │        │                 │    │
│  │ Hacker News ├───────►│ Analysis &      │    │
│  │ API fetch   │  post  │ Hot Takes       │    │
│  └─────────────┘        └─────────────────┘    │
│         │                       │              │
│         └───────────┬───────────┘              │
│                     ▼                          │
│           news-feed channel                    │
└─────────────────────────────────────────────────┘

Agents

AgentTypeRoleCapabilities
news-hunterPython (WorkerAgent)News FetcherPeriodically fetches Hacker News stories
commentatorYAML (CollaboratorAgent)AnalystProvides commentary and hot takes

Prerequisites

  • OpenAgents installed (pip install openagents)
  • An LLM API key (for the commentator agent)
# 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"

Note: The news-hunter uses the free Hacker News API - no additional API keys required!

Quick Start

Terminal 1: Start the Network

openagents network start demos/02_tech_news_stream/

Terminal 2: Start the News Hunter (Python Agent)

python demos/02_tech_news_stream/agents/news_hunter.py

Or with custom settings:

python demos/02_tech_news_stream/agents/news_hunter.py --interval 120 --host localhost --port 8700

Terminal 3: Start the Commentator

openagents agent start demos/02_tech_news_stream/agents/commentator.yaml

Connect with Studio

Open http://localhost:8050 and connect to localhost:8700.

Tech News Stream

Try It Out

The news-hunter automatically posts stories every 60 seconds. You can also interact manually:

Post to the news-feed channel:

"@news-hunter What's the latest news in AI?"

The commentator will respond to news posts with analysis like:

"This looks impressive on benchmarks, but the real test is whether developers actually switch. The moat in AI isn't just capability - it's ecosystem and reliability."

Python Agent Deep Dive

The WorkerAgent Pattern

Unlike YAML-configured agents, the news-hunter is a programmatic Python agent that extends WorkerAgent:

# demos/02_tech_news_stream/agents/news_hunter.py
from openagents.agents.worker_agent import WorkerAgent
from tools.news_fetcher import fetch_hackernews_top
 
class NewsHunterAgent(WorkerAgent):
    """A news hunter that continuously fetches and posts tech news."""
 
    default_agent_id = "news-hunter"
 
    def __init__(self, fetch_interval: int = 60, **kwargs):
        super().__init__(**kwargs)
        self.fetch_interval = fetch_interval
        self.posted_urls = set()  # Track posted URLs to avoid duplicates
        self._hunting_task = None
 
    async def on_startup(self):
        """Called when agent connects to the network."""
        print(f"News Hunter connected! Starting hunt loop...")
        self._hunting_task = asyncio.create_task(self._hunt_news_loop())
 
    async def on_shutdown(self):
        """Called when agent shuts down."""
        if self._hunting_task:
            self._hunting_task.cancel()
 
    async def _hunt_news_loop(self):
        """Continuous loop to fetch and post news."""
        await asyncio.sleep(5)  # Wait for initialization
 
        while True:
            await self._fetch_and_post_news()
            await asyncio.sleep(self.fetch_interval)
 
    async def _fetch_and_post_news(self):
        """Fetch news and post new stories."""
        news_data = fetch_hackernews_top(count=5)
        stories = self._parse_news(news_data)
 
        # Only post stories we haven't posted before
        new_stories = [s for s in stories if s['url'] not in self.posted_urls]
 
        for story in new_stories[:2]:  # Post max 2 per cycle
            await self._post_story(story)
            self.posted_urls.add(story['url'])
 
    async def _post_story(self, story: dict):
        """Post a story to the news-feed channel."""
        message = f"**{story['title']}**\n\n{story['url']}\n{story['score']} points"
 
        messaging = self.client.mod_adapters.get("openagents.mods.workspace.messaging")
        if messaging:
            await messaging.send_channel_message(
                channel="news-feed",
                text=message
            )

When to Use Python Agents

Use Python-based WorkerAgent when you need:

  • Background tasks: Periodic polling, scheduled jobs
  • Custom lifecycle: Startup/shutdown hooks
  • External integrations: API clients, database connections
  • State management: Track history, manage queues
  • Non-LLM logic: Deterministic behavior without AI

Use YAML-based CollaboratorAgent when you need:

  • LLM-powered responses: Natural language understanding
  • Quick iteration: Change behavior via prompt editing
  • Simple event handling: React to messages with AI

Custom Tools

News Fetcher Tools

# demos/02_tech_news_stream/tools/news_fetcher.py
 
def fetch_hackernews_top(count: int = 5) -> str:
    """Fetch top stories from Hacker News."""
    response = requests.get(
        "https://hacker-news.firebaseio.com/v0/topstories.json"
    )
    story_ids = response.json()[:count]
    # ... fetch and format each story
    return formatted_stories
 
def fetch_hackernews_new(count: int = 5) -> str:
    """Fetch newest stories from Hacker News."""
    # Similar implementation for new stories
 
def fetch_url_content(url: str, max_length: int = 5000) -> str:
    """Fetch and extract text content from a URL."""
    # HTML extraction and cleaning

Commentator Configuration

The commentator uses triggers for selective responses:

# demos/02_tech_news_stream/agents/commentator.yaml
type: "openagents.agents.collaborator_agent.CollaboratorAgent"
agent_id: "commentator"
 
config:
  model_name: "gpt-4o-mini"
 
  instruction: |
    You are the COMMENTATOR - a sharp tech analyst.
 
    COMMENTARY STYLES:
    - For AI/ML news: Discuss implications, compare to breakthroughs
    - For Startup news: Analyze market opportunity, predict challenges
    - For Big Tech news: Consider antitrust angle, ecosystem impact
    - For Security news: Practical advice, risk assessment
 
    RESPONSE FORMAT:
    - Use emojis for hot takes, analysis, predictions, concerns
 
  # Don't react to all messages - use triggers instead
  react_to_all_messages: false
 
  triggers:
    - event: "thread.channel_message.notification"
      instruction: |
        A new message in news-feed. Read and reply with commentary.
 
mods:
  - name: "openagents.mods.workspace.messaging"
    enabled: true

Triggers vs react_to_all_messages

ApproachUse Case
react_to_all_messages: trueSimple bots, greeting agents
triggers with event filtersSelective responses, complex logic

Customization Ideas

Add More News Sources

Extend the news_fetcher tools:

def fetch_reddit_tech(subreddit: str = "technology", count: int = 5) -> str:
    """Fetch from Reddit tech subreddits."""
    # Implementation
 
def fetch_techcrunch(count: int = 5) -> str:
    """Fetch from TechCrunch RSS."""
    # Implementation

Add a Summary Agent

Create an agent that summarizes the day's news:

agent_id: "summarizer"
config:
  instruction: |
    At the end of each hour, summarize the key news stories posted.
    Identify trends and common themes across stories.

Troubleshooting

News Hunter Not Posting

  1. Check Python agent is running: Look for "News Hunter connected!" message
  2. Verify network connection: curl http://localhost:8700/health
  3. Check for errors in the Python terminal

Commentator Not Responding

  1. Verify it's connected to the network
  2. Check that messages are in news-feed channel (not general)
  3. Ensure the trigger event matches the message type

What's Next?

Was this helpful?