Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions python/configs/agent_cards/news_agent.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"name": "NewsAgent",
"display_name": "News Agent",
"url": "http://localhost:10005/",
"description": "Professional news agent specialized in gathering, analyzing, and presenting current events, breaking news, and financial market information from reliable sources with real-time web search capabilities.",
"capabilities": {
"streaming": true
},
"skills": [
{
"id": "web_search",
"name": "Real-time news search",
"description": "Search for current news articles and information across the web using advanced search capabilities.",
"examples": [
"What's the latest news about artificial intelligence?",
"Search for recent developments in renewable energy",
"Find news about the latest tech IPOs"
],
"tags": ["web search", "real-time", "current events", "research"]
},
{
"id": "get_breaking_news",
"name": "Breaking news monitoring",
"description": "Monitor and retrieve urgent breaking news updates and alerts from multiple sources.",
"examples": [
"Any breaking news right now?",
"What are the latest urgent news updates?",
"Show me breaking news from the past hour"
],
"tags": ["breaking news", "urgent", "alerts", "monitoring"]
},
{
"id": "get_financial_news",
"name": "Financial market news",
"description": "Provide comprehensive financial market news, business updates, and economic developments.",
"examples": [
"What's happening in the stock market today?",
"Latest financial news and market updates",
"Show me news about major economic indicators"
],
"tags": ["finance", "markets", "business", "stocks", "economics"]
}
],
"enabled": true,
"metadata": {
"version": "1.0.0",
"author": "ValueCell Team",
"tags": [
"news",
"current events",
"financial markets",
"real-time search"
]
}
}
109 changes: 109 additions & 0 deletions python/configs/agents/news_agent.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# ============================================
# News Agent Configuration
# ============================================
# The News Agent specializes in gathering, analyzing, and presenting news information.
# It provides real-time news search, categorized news retrieval, and comprehensive analysis.
# ============================================
# Configuration Priority (highest to lowest):
# 1. Environment Variables (highest priority)
# 2. .env file
# 3. YAML files (lowest priority, system defaults)
# ============================================

name: "News Agent"
enabled: true

# Model Configuration
# News Agent needs a capable model for news analysis and summarization
models:
# Primary model for news analysis, summarization, and query processing
primary:
model_id: "anthropic/claude-haiku-4.5"
provider: "openrouter" # Must explicitly specify provider (not null)

# Provider-specific model mappings for fallback
# Used when primary provider fails and fallback is attempted
provider_models:
siliconflow: "Qwen/Qwen3-235B-A22B-Thinking-2507" # Strong reasoning for news analysis
google: "gemini-2.5-flash" # Fast and efficient for news processing

parameters:
# temperature: 0.3 # Lower temperature for more factual news reporting
# max_tokens: 4096 # Sufficient for comprehensive news analysis

# Web search model for real-time information gathering
# Uses specialized models optimized for web search and real-time data
search:
model_id: "perplexity/sonar"
provider: "openrouter"

# Provider-specific search model mappings
provider_models:
google: "gemini-2.5-flash" # With search grounding enabled

parameters:
# max_tokens: 2048 # Optimized for search result processing

# Environment Variable Overrides
# Format: ENV_VAR_NAME -> config.path
# These allow runtime configuration through environment variables
env_overrides:
# Primary model overrides
NEWS_AGENT_MODEL_ID: "models.primary.model_id"
NEWS_AGENT_PROVIDER: "models.primary.provider"
NEWS_AGENT_TEMPERATURE: "models.primary.parameters.temperature"
NEWS_AGENT_MAX_TOKENS: "models.primary.parameters.max_tokens"

# Search model overrides
NEWS_SEARCH_MODEL_ID: "models.search.model_id"
NEWS_SEARCH_PROVIDER: "models.search.provider"

# Web search provider configuration
WEB_SEARCH_PROVIDER: "capabilities.web_search.provider"

# News Agent Capabilities
capabilities:
# Web search configuration
web_search:
enabled: true
provider: "perplexity" # Default: perplexity, alternative: google
max_results: 10

# Breaking news monitoring
breaking_news:
enabled: true # Enable breaking news monitoring
refresh_interval: 300 # seconds

# Financial news specialization
financial_news:
enabled: true
supported_markets: ["US", "Global"]
include_sectors: true
include_individual_stocks: true



# Multi-language support
languages:
enabled: true
supported: ["en", "zh", "ja", "ko", "es", "fr", "de"]
default: "en"

# News analysis features
analysis:
sentiment_analysis: true
topic_extraction: true
entity_recognition: true
summarization: true
fact_checking: false # Requires additional verification tools

# Tool Configuration
tools:
web_search:
enabled: true

get_breaking_news:
enabled: true

get_financial_news:
enabled: true
9 changes: 5 additions & 4 deletions python/scripts/launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,13 @@
TRADING_AGENTS_NAME = "TradingAgents"
RESEARCH_AGENT_NAME = "ResearchAgent"
AUTO_TRADING_AGENT_NAME = "AutoTradingAgent"
NEWS_AGENT_NAME = "NewsAgent"
# AGENTS = list(MAP_NAME_ANALYST.keys()) + [
# TRADING_AGENTS_NAME,
# RESEARCH_AGENT_NAME,
# AUTO_TRADING_AGENT_NAME,
# ]
AGENTS = [
RESEARCH_AGENT_NAME,
AUTO_TRADING_AGENT_NAME,
]
AGENTS = [RESEARCH_AGENT_NAME, AUTO_TRADING_AGENT_NAME, NEWS_AGENT_NAME]

PROJECT_DIR = Path(__file__).resolve().parent.parent.parent
PYTHON_DIR = PROJECT_DIR / "python"
Expand All @@ -66,6 +64,9 @@
MAP_NAME_COMMAND[AUTO_TRADING_AGENT_NAME] = (
f"uv run --env-file {ENV_PATH_STR} -m valuecell.agents.auto_trading_agent"
)
MAP_NAME_COMMAND[NEWS_AGENT_NAME] = (
f"uv run --env-file {ENV_PATH_STR} -m valuecell.agents.news_agent"
)
BACKEND_COMMAND = (
f"cd {PYTHON_DIR_STR} && uv run --env-file {ENV_PATH_STR} -m valuecell.server.main"
)
Expand Down
5 changes: 5 additions & 0 deletions python/valuecell/agents/news_agent/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""News Agent for fetching and analyzing news content."""

from .core import NewsAgent

__all__ = ["NewsAgent"]
8 changes: 8 additions & 0 deletions python/valuecell/agents/news_agent/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import asyncio

from valuecell.agents.news_agent import NewsAgent
from valuecell.core import create_wrapped_agent

if __name__ == "__main__":
agent = create_wrapped_agent(NewsAgent)
asyncio.run(agent.serve())
133 changes: 133 additions & 0 deletions python/valuecell/agents/news_agent/core.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
"""News Agent Core Implementation."""

from typing import Any, AsyncGenerator, Dict, Optional

from agno.agent import Agent
from loguru import logger

from valuecell.adapters.models import create_model_for_agent
from valuecell.config.manager import get_config_manager
from valuecell.core.agent.responses import streaming
from valuecell.core.types import BaseAgent, StreamResponse

from .prompts import NEWS_AGENT_INSTRUCTIONS
from .tools import get_breaking_news, get_financial_news, web_search


class NewsAgent(BaseAgent):
"""News Agent for fetching and analyzing news."""

def __init__(self, **kwargs):
"""Initialize the News Agent."""
super().__init__(**kwargs)
# Load agent configuration
self.config_manager = get_config_manager()
self.agent_config = self.config_manager.get_agent_config("news_agent")

# Load tools based on configuration
available_tools = []

available_tools.extend([web_search, get_breaking_news, get_financial_news])

# Use create_model_for_agent to load agent-specific configuration
self.knowledge_news_agent = Agent(
model=create_model_for_agent("news_agent"),
tools=available_tools,
instructions=NEWS_AGENT_INSTRUCTIONS,
)

logger.info("NewsAgent initialized with news tools")

async def stream(
self,
query: str,
conversation_id: str,
task_id: str,
dependencies: Optional[Dict] = None,
) -> AsyncGenerator[StreamResponse, None]:
"""Stream news responses."""
logger.info(
f"Processing news query: {query[:100]}{'...' if len(query) > 100 else ''}"
)

try:
response_stream = self.knowledge_news_agent.arun(
query,
stream=True,
stream_intermediate_steps=True,
session_id=conversation_id,
)
async for event in response_stream:
if event.event == "RunContent":
yield streaming.message_chunk(event.content)
elif event.event == "ToolCallStarted":
yield streaming.tool_call_started(
event.tool.tool_call_id, event.tool.tool_name
)
elif event.event == "ToolCallCompleted":
yield streaming.tool_call_completed(
event.tool.result, event.tool.tool_call_id, event.tool.tool_name
)

yield streaming.done()
logger.info("News query processed successfully")

except Exception as e:
logger.error(f"Error processing news query: {str(e)}")
logger.exception("Full error details:")
yield {"type": "error", "content": f"Error processing news query: {str(e)}"}

async def run(self, query: str, **kwargs) -> str:
"""Run news agent and return response."""
logger.info(
f"Running news agent with query: {query[:100]}{'...' if len(query) > 100 else ''}"
)

try:
logger.debug("Starting news agent processing")

# Get the complete response from the knowledge news agent
response = await self.knowledge_news_agent.arun(query)

logger.info("News agent query completed successfully")
logger.debug(f"Response length: {len(str(response.content))} characters")

return response.content

except Exception as e:
logger.error(f"Error in NewsAgent run: {e}")
logger.exception("Full error details:")
return f"Error processing news query: {str(e)}"

def get_capabilities(self) -> Dict[str, Any]:
"""Get agent capabilities."""
logger.debug("Retrieving news agent capabilities")

capabilities = {
"name": "News Agent",
"description": "Professional news agent for fetching and analyzing news",
"tools": [
{
"name": "web_search",
"description": "Search for general news and information",
},
{
"name": "get_breaking_news",
"description": "Get latest breaking news",
},
{
"name": "get_financial_news",
"description": "Get financial and market news",
},
],
"supported_queries": [
"Latest news",
"Breaking news",
"Financial news",
"Market updates",
"Topic-specific news search",
],
}

logger.debug("Capabilities retrieved successfully")
return capabilities
Loading