How I built a real-time news aggregation agent, integrated it with Telex.im, and learned about AI agent architecture along the way.
Introduction
For the HNG Stage 3 backend challenge, I set out to build something practical: an AI agent that delivers fresh news headlines on demand. The result? Daily Headline Digest Agent β an intelligent system that fetches trending news, summarizes it with AI, and integrates seamlessly with Telex.im.
This blog post walks through my journey: why I chose Mastra, how I built the agent, the integration challenges I faced, and what I learned about building AI systems at scale.
What I Built
Daily Headline Digest Agent is an AI-powered news assistant that:
- Fetches real-time news from the GNews API across multiple categories (tech, business, sports, health, entertainment, science)
- Supports country-specific news (Nigeria, USA, UK, Canada, Australia, India, and more)
- Uses Google's Gemini 2.0 Flash model for intelligent summarization
- Integrates with Telex.im for seamless workplace collaboration
- Provides formatted, emoji-enhanced news digests with source attribution
Example interaction:
User: "Give me today's tech news"
Agent: "ποΈ Tech Headlines - Friday, November 7, 2025
1οΈβ£ OnePlus 15 launching in India on November 13...
2οΈβ£ iOS 26 Marks a New Divide in the iPhone Lineup..."
Why Mastra?
When I started this project, I had three options:
- Build from scratch with raw APIs
- Use LangChain/LlamaIndex
- Use Mastra
I chose Mastra for several reasons:
1. Built for Telex Integration
Mastra has first-class support for Telex.im through the A2A protocol. This wasn't a hack β it was designed for this use case.
2. Simpler Agent Definition
With Mastra, defining an agent is straightforward:
export const newsDigestAgent = new Agent({
name: 'newsDigestAgent',
instructions: '...',
model: google('gemini-2.0-flash'),
tools: { fetchNews },
});
No complex prompt engineering needed. Clear, declarative syntax.
3. Type Safety
Being a TypeScript-first framework, Mastra gave me confidence with full type checking. My tools had validated schemas using Zod:
const newsToolSchema = z.object({
topic: z.string().default('world'),
maxArticles: z.number().min(3).max(10).default(5),
});
4. Built-in Server/Routing
Mastra handles HTTP routing, JSON-RPC validation, and API structure automatically. I didn't have to write boilerplate.
Architecture
Here's how the system is structured:
src/
βββ mastra/
β βββ agents/
β β βββ news-agent.ts # Main AI agent
β βββ tools/
β β βββ news-tools.ts # GNews API integration
β βββ index.ts # Mastra instance
βββ routes/
β βββ a2a-agent-route.ts # Telex A2A protocol handler
βββ index.ts # Express server
βββ types/
βββ a2a.types.ts # Protocol types
Key Components:
- newsDigestAgent - The AI agent that understands natural language and decides when to use tools
- fetchNews - A tool that fetches news from GNews API with smart topic mapping
- a2aAgentRoute - Handles JSON-RPC 2.0 requests from Telex.im
- Express Server - Hosts everything on Railway
The Integration Journey
Phase 1: Local Development
I started by building the agent locally:
npm install @mastra/core @ai-sdk/google dotenv
npm run dev
The Mastra dev server gave me a Studio interface to test the agent instantly. This was powerful β I could iterate on instructions and see results in real-time.
Phase 2: Deployment Challenge
This is where I hit my first major hurdle: Node.js version compatibility.
My dependencies required Node 20+, but Railway was deploying Node 18. The error was cryptic at first:
ERR_MODULE_NOT_FOUND: Cannot find module '/app/dist/mastra/agents/news-agent'
Solution: Create a .node-version file to specify Node.js 20:
echo "20" > .node-version
Lesson: Always verify your runtime environment. A simple version mismatch can cause confusing module resolution errors with ES modules.
Phase 3: ES Module Path Issues
Another challenge: ES modules require explicit file extensions in imports.
Before (broken):
import { newsDigestAgent } from './agents/news-agent';
After (working):
import { newsDigestAgent } from './agents/news-agent.js';
This is a Node.js ES module requirement, not specific to Mastra, but it's easy to miss.
Phase 4: Environment Variables
My biggest debugging headache was environment variables not being passed to the deployed container.
Initially, I set them via Railway CLI:
railway variables --set GOOGLE_GENERATIVE_AI_API_KEY=...
But they didn't persist properly. The fix was to redeploy and verify they appeared in the logs.
Lesson: Always check railway logs after setting environment variables.
Phase 5: A2A Protocol Implementation
The real integration work came with implementing the A2A (Agent-to-Agent) protocol for Telex.
Telex expects JSON-RPC 2.0 format:
{
"jsonrpc": "2.0",
"id": 1,
"method": "message/send",
"params": {
"message": {
"parts": [{"text": "your message"}]
}
}
}
I built a dedicated route handler:
export const a2aAgentRoute = registerApiRoute('/a2a/agent/:agentId', {
method: 'POST',
handler: async (c) => {
// Validate JSON-RPC 2.0
// Extract message
// Call agent
// Return formatted response
},
});
Key challenge: Handling multiple message formats. Telex might send different structures depending on context. My solution:
let message = 'Hello';
if (params?.message?.parts?.[0]?.text) {
message = params.message.parts[0].text;
} else if (typeof params?.message === 'string') {
message = params.message;
} else if (params?.content) {
message = params.content;
}
What Worked Well
β Mastra's Structure - The framework enforces good patterns without feeling restrictive
β Tool System - Defining tools with Zod schemas is clean and type-safe
β Model Flexibility - Easy to switch between Google, OpenAI, Anthropic models
β Railway Deployment - Once environment issues were solved, deployments were smooth
β GNews API - Free, reliable news data with good coverage across categories and countries
What Was Tricky
β Telex Integration Documentation - Limited docs on custom A2A implementations (Telex seems designed primarily for Mastra Cloud)
β Module Resolution - ES modules require explicit extensions and proper tsconfig settings
β Environment Variables - Railroad between CLI setup and deployment wasn't intuitive
β Debugging A2A Failures - Hard to know exactly what Telex was sending without better error messages
Lessons Learned
1. Start with Local Testing
Always validate your agent works locally before deploying. The Mastra Studio is invaluable.
2. Read the Logs
Railway logs showed exactly what was failing. "No service linked" β "Missing environment variables" β "Module not found". The logs told the story.
3. Type Safety Saves Time
TypeScript + Zod caught errors before runtime. Schema validation prevented bad data from reaching the API.
4. Keep the Agent Instructions Clear
I spent time crafting detailed agent instructions with examples. This actually improved the agent's behavior significantly. Good instructions > complex prompts.
5. Handle Multiple Input Formats
Real-world integrations are messy. Building flexibility into message parsing was essential.
The Code
You can find the complete implementation here:
- GitHub: https://github.com/Ursulaonyi/news-digest-agent
- Deployed API: https://daily-headline-digest-production.up.railway.app
- Health Check: https://daily-headline-digest-production.up.railway.app/health
-
Test Endpoint:
POST /api/chatwith{"message": "your query"}
What's Next
Possible improvements:
- Add caching to reduce API calls
- Implement sentiment analysis on headlines
- Add multi-language support
- Create a web UI for the agent
- Build a scheduled digest for Slack integration
Final Thoughts
Building the Daily Headline Digest Agent taught me that modern AI agent frameworks like Mastra handle a lot of complexity beautifully. The hardest parts weren't about AI β they were about infrastructure, environment setup, and protocol integration.
If you're building AI agents, I'd recommend:
- Use Mastra if you want structure and Telex integration
- Invest time in good instructions β they matter more than you think
- Test locally first β catch issues before deploying
- Read the logs β they tell you everything
- Build for flexibility β real integrations are messier than documentation suggests
The Daily Headline Digest Agent is live, integrated with Telex.im, and delivering real news to users. Not bad for a stage 3 backend challenge! π
Built with: TypeScript, Mastra, Google Gemini 2.0 Flash, GNews API, Express, Railway
Deployed: November 7, 2025
Top comments (0)