From 6e01f1caea67170366b4f33042de513f22755364 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 22 Oct 2025 14:08:37 +0000 Subject: [PATCH] Implement configurable API providers from configs.yaml Co-authored-by: Berack96 <31776951+Berack96@users.noreply.github.com> --- configs.yaml | 7 +++-- src/app/api/tools/market_tool.py | 42 ++++++++++++++++++++---------- src/app/api/tools/news_tool.py | 44 ++++++++++++++++++++++---------- src/app/api/tools/social_tool.py | 38 ++++++++++++++++++++------- src/app/configs.py | 3 +++ 5 files changed, 94 insertions(+), 40 deletions(-) diff --git a/configs.yaml b/configs.yaml index f83ae9e..1837a30 100644 --- a/configs.yaml +++ b/configs.yaml @@ -32,10 +32,9 @@ models: api: retry_attempts: 3 retry_delay_seconds: 2 - # TODO Magari implementare un sistema per settare i providers - market_providers: [BinanceWrapper, YFinanceWrapper] - news_providers: [GoogleNewsWrapper, DuckDuckGoWrapper] - social_providers: [RedditWrapper] + market_providers: [BinanceWrapper, YFinanceWrapper, CoinBaseWrapper, CryptoCompareWrapper] + news_providers: [GoogleNewsWrapper, DuckDuckGoWrapper, NewsApiWrapper, CryptoPanicWrapper] + social_providers: [RedditWrapper, XWrapper, ChanWrapper] agents: strategy: Conservative diff --git a/src/app/api/tools/market_tool.py b/src/app/api/tools/market_tool.py index 0b92319..e740372 100644 --- a/src/app/api/tools/market_tool.py +++ b/src/app/api/tools/market_tool.py @@ -2,30 +2,46 @@ from agno.tools import Toolkit from app.api.wrapper_handler import WrapperHandler from app.api.core.markets import MarketWrapper, Price, ProductInfo from app.api.markets import BinanceWrapper, CoinBaseWrapper, CryptoCompareWrapper, YFinanceWrapper +from app.configs import AppConfig class MarketAPIsTool(MarketWrapper, Toolkit): """ Class that aggregates multiple market API wrappers and manages them using WrapperHandler. This class supports retrieving product information and historical prices. This class can also aggregate data from multiple sources to provide a more comprehensive view of the market. - The following wrappers are included in this order: - - BinanceWrapper - - YFinanceWrapper - - CoinBaseWrapper - - CryptoCompareWrapper + Providers can be configured in configs.yaml under api.market_providers. """ + # Mapping of wrapper names to wrapper classes + _WRAPPER_MAP = { + 'BinanceWrapper': BinanceWrapper, + 'YFinanceWrapper': YFinanceWrapper, + 'CoinBaseWrapper': CoinBaseWrapper, + 'CryptoCompareWrapper': CryptoCompareWrapper, + } + def __init__(self): """ - Initialize the MarketAPIsTool with multiple market API wrappers. - The following wrappers are included in this order: - - BinanceWrapper - - YFinanceWrapper - - CoinBaseWrapper - - CryptoCompareWrapper + Initialize the MarketAPIsTool with market API wrappers configured in configs.yaml. + The order of wrappers is determined by the api.market_providers list in the configuration. """ - wrappers: list[type[MarketWrapper]] = [BinanceWrapper, YFinanceWrapper, CoinBaseWrapper, CryptoCompareWrapper] - self.handler = WrapperHandler.build_wrappers(wrappers) + config = AppConfig() + + # Get wrapper classes based on configuration + wrappers: list[type[MarketWrapper]] = [] + for provider_name in config.api.market_providers: + if provider_name in self._WRAPPER_MAP: + wrappers.append(self._WRAPPER_MAP[provider_name]) + + # Fallback to all wrappers if none configured + if not wrappers: + wrappers = [BinanceWrapper, YFinanceWrapper, CoinBaseWrapper, CryptoCompareWrapper] + + self.handler = WrapperHandler.build_wrappers( + wrappers, + try_per_wrapper=config.api.retry_attempts, + retry_delay=config.api.retry_delay_seconds + ) Toolkit.__init__( # type: ignore self, diff --git a/src/app/api/tools/news_tool.py b/src/app/api/tools/news_tool.py index ab67f8b..e4733f7 100644 --- a/src/app/api/tools/news_tool.py +++ b/src/app/api/tools/news_tool.py @@ -2,33 +2,49 @@ from agno.tools import Toolkit from app.api.wrapper_handler import WrapperHandler from app.api.core.news import NewsWrapper, Article from app.api.news import NewsApiWrapper, GoogleNewsWrapper, CryptoPanicWrapper, DuckDuckGoWrapper +from app.configs import AppConfig class NewsAPIsTool(NewsWrapper, Toolkit): """ Aggregates multiple news API wrappers and manages them using WrapperHandler. - This class supports retrieving top headlines and latest news articles by querying multiple sources: - - GoogleNewsWrapper - - DuckDuckGoWrapper - - NewsApiWrapper - - CryptoPanicWrapper + This class supports retrieving top headlines and latest news articles by querying multiple sources. + Providers can be configured in configs.yaml under api.news_providers. By default, it returns results from the first successful wrapper. Optionally, it can be configured to collect articles from all wrappers. If no wrapper succeeds, an exception is raised. """ + # Mapping of wrapper names to wrapper classes + _WRAPPER_MAP = { + 'GoogleNewsWrapper': GoogleNewsWrapper, + 'DuckDuckGoWrapper': DuckDuckGoWrapper, + 'NewsApiWrapper': NewsApiWrapper, + 'CryptoPanicWrapper': CryptoPanicWrapper, + } + def __init__(self): """ - Initialize the NewsAPIsTool with multiple news API wrappers. - The tool uses WrapperHandler to manage and invoke the different news API wrappers. - The following wrappers are included in this order: - - GoogleNewsWrapper. - - DuckDuckGoWrapper. - - NewsApiWrapper. - - CryptoPanicWrapper. + Initialize the NewsAPIsTool with news API wrappers configured in configs.yaml. + The order of wrappers is determined by the api.news_providers list in the configuration. """ - wrappers: list[type[NewsWrapper]] = [GoogleNewsWrapper, DuckDuckGoWrapper, NewsApiWrapper, CryptoPanicWrapper] - self.handler = WrapperHandler.build_wrappers(wrappers) + config = AppConfig() + + # Get wrapper classes based on configuration + wrappers: list[type[NewsWrapper]] = [] + for provider_name in config.api.news_providers: + if provider_name in self._WRAPPER_MAP: + wrappers.append(self._WRAPPER_MAP[provider_name]) + + # Fallback to all wrappers if none configured + if not wrappers: + wrappers = [GoogleNewsWrapper, DuckDuckGoWrapper, NewsApiWrapper, CryptoPanicWrapper] + + self.handler = WrapperHandler.build_wrappers( + wrappers, + try_per_wrapper=config.api.retry_attempts, + retry_delay=config.api.retry_delay_seconds + ) Toolkit.__init__( # type: ignore self, diff --git a/src/app/api/tools/social_tool.py b/src/app/api/tools/social_tool.py index c905b5b..e63eb4c 100644 --- a/src/app/api/tools/social_tool.py +++ b/src/app/api/tools/social_tool.py @@ -2,29 +2,49 @@ from agno.tools import Toolkit from app.api.wrapper_handler import WrapperHandler from app.api.core.social import SocialPost, SocialWrapper from app.api.social import * +from app.configs import AppConfig class SocialAPIsTool(SocialWrapper, Toolkit): """ Aggregates multiple social media API wrappers and manages them using WrapperHandler. - This class supports retrieving top crypto-related posts by querying multiple sources: - - RedditWrapper + This class supports retrieving top crypto-related posts by querying multiple sources. + Providers can be configured in configs.yaml under api.social_providers. By default, it returns results from the first successful wrapper. Optionally, it can be configured to collect posts from all wrappers. If no wrapper succeeds, an exception is raised. """ + # Mapping of wrapper names to wrapper classes + _WRAPPER_MAP = { + 'RedditWrapper': RedditWrapper, + 'XWrapper': XWrapper, + 'ChanWrapper': ChanWrapper, + } + def __init__(self): """ - Initialize the SocialAPIsTool with multiple social media API wrappers. - The tool uses WrapperHandler to manage and invoke the different social media API wrappers. - The following wrappers are included in this order: - - RedditWrapper. + Initialize the SocialAPIsTool with social media API wrappers configured in configs.yaml. + The order of wrappers is determined by the api.social_providers list in the configuration. """ - - wrappers: list[type[SocialWrapper]] = [RedditWrapper, XWrapper, ChanWrapper] - self.handler = WrapperHandler.build_wrappers(wrappers) + config = AppConfig() + + # Get wrapper classes based on configuration + wrappers: list[type[SocialWrapper]] = [] + for provider_name in config.api.social_providers: + if provider_name in self._WRAPPER_MAP: + wrappers.append(self._WRAPPER_MAP[provider_name]) + + # Fallback to all wrappers if none configured + if not wrappers: + wrappers = [RedditWrapper, XWrapper, ChanWrapper] + + self.handler = WrapperHandler.build_wrappers( + wrappers, + try_per_wrapper=config.api.retry_attempts, + retry_delay=config.api.retry_delay_seconds + ) Toolkit.__init__( # type: ignore self, diff --git a/src/app/configs.py b/src/app/configs.py index 45b5b01..fab5ad4 100644 --- a/src/app/configs.py +++ b/src/app/configs.py @@ -57,6 +57,9 @@ class AppModel(BaseModel): class APIConfig(BaseModel): retry_attempts: int = 3 retry_delay_seconds: int = 2 + market_providers: list[str] = [] + news_providers: list[str] = [] + social_providers: list[str] = [] class Strategy(BaseModel): name: str = "Conservative"