# news_tools.py - CrewAI Native Version import os import requests from crewai.tools import BaseTool from typing import Type from pydantic import BaseModel, Field class NewsSearchInput(BaseModel): """Input schema for NewsSearchTool.""" query: str = Field(..., description="Query string to search for cryptocurrency news") class NewsSearchTool(BaseTool): name: str = "Search Crypto News" description: str = "Searches for cryptocurrency news articles based on a given query" args_schema: Type[NewsSearchInput] = NewsSearchInput def _run(self, query: str) -> str: try: # Using NewsAPI (free tier) or fall back to mock data api_key = os.getenv("NEWS_API_KEY") if api_key: url = "https://newsapi.org/v2/everything" params = { 'q': f"{query} cryptocurrency", 'sortBy': 'publishedAt', 'pageSize': 3, 'apiKey': api_key, 'language': 'en' } response = requests.get(url, params=params, timeout=10) response.raise_for_status() data = response.json() articles = data.get('articles', []) if articles: news_summary = [] for article in articles[:3]: title = article.get('title', 'No title') source = article.get('source', {}).get('name', 'Unknown source') news_summary.append(f"• {title} - {source}") return f"Recent news for {query}:\n" + "\n".join(news_summary) else: return f"No recent news found for {query}" else: # Mock news data when API key is not available mock_headlines = [ f"{query.title()} shows strong technical indicators amid market volatility", f"Institutional adoption of {query.title()} continues to grow", f"Market analysts remain optimistic about {query.title()}'s long-term prospects" ] return f"Recent news for {query}:\n" + "\n".join([f"• {headline}" for headline in mock_headlines]) except Exception as e: return f"Error fetching news: {str(e)}"