diff --git a/astrbot/core/astr_main_agent.py b/astrbot/core/astr_main_agent.py index 59183b8a613..1610308187e 100644 --- a/astrbot/core/astr_main_agent.py +++ b/astrbot/core/astr_main_agent.py @@ -107,6 +107,7 @@ FirecrawlWebSearchTool, SerpApiFinanceSearchTool, SerpApiImageSearchTool, + SerpApiNewsSearchTool, SerpApiScholarSearchTool, SerpApiWebSearchTool, TavilyExtractWebPageTool, @@ -170,6 +171,7 @@ "web_search_anysearch", "web_search_deepseek", "web_search_serpapi", + "news_search_serpapi", "image_search_serpapi", "finance_search_serpapi", "scholar_search_serpapi", @@ -1312,6 +1314,7 @@ async def _apply_web_search_tools( req.func_tool.add_tool(tool_mgr.get_builtin_tool(DeepSeekFetchWebPageTool)) elif provider == "serpapi": req.func_tool.add_tool(tool_mgr.get_builtin_tool(SerpApiWebSearchTool)) + req.func_tool.add_tool(tool_mgr.get_builtin_tool(SerpApiNewsSearchTool)) req.func_tool.add_tool(tool_mgr.get_builtin_tool(SerpApiImageSearchTool)) req.func_tool.add_tool(tool_mgr.get_builtin_tool(SerpApiFinanceSearchTool)) req.func_tool.add_tool(tool_mgr.get_builtin_tool(SerpApiScholarSearchTool)) diff --git a/astrbot/core/config/default.py b/astrbot/core/config/default.py index 150804573a8..ee27298071a 100644 --- a/astrbot/core/config/default.py +++ b/astrbot/core/config/default.py @@ -3695,7 +3695,7 @@ def get_local_permission_defaults(system: str | None = None) -> dict: "AnySearch", ], "subtitles": [ - "Google 网页、图片、学术和财经搜索", + "Google 网页、新闻、图片、学术和财经搜索", "DeepSeek 官方搜索接口", "", "", @@ -3799,7 +3799,7 @@ def get_local_permission_defaults(system: str | None = None) -> dict: "description": "SerpApi API Key", "type": "list", "items": {"type": "string"}, - "hint": "支持 Google 网页、图片、学术和财经搜索。可添加多个 Key 轮询。获取 Key:[https://serpapi.com/manage-api-key](https://serpapi.com/manage-api-key)", + "hint": "支持 Google 网页、新闻、图片、学术和财经搜索。可添加多个 Key 轮询。获取 Key:[https://serpapi.com/manage-api-key](https://serpapi.com/manage-api-key)", "secret": True, "condition": { "provider_settings.websearch_provider": "serpapi", diff --git a/astrbot/core/tools/web_search_tools.py b/astrbot/core/tools/web_search_tools.py index 35826648da2..fa7eea312f9 100644 --- a/astrbot/core/tools/web_search_tools.py +++ b/astrbot/core/tools/web_search_tools.py @@ -26,6 +26,7 @@ "exa_get_contents", "web_search_anysearch", "web_search_serpapi", + "news_search_serpapi", "image_search_serpapi", "finance_search_serpapi", "scholar_search_serpapi", @@ -604,6 +605,108 @@ async def call(self, context, **kwargs) -> ToolExecResult: return _search_result_payload(results[:max_results]) +@builtin_tool(config=_SERPAPI_WEB_SEARCH_TOOL_CONFIG) +@pydantic_dataclass +class SerpApiNewsSearchTool(FunctionTool[AstrAgentContext]): + name: str = "news_search_serpapi" + description: str = ( + "Search current news using the SerpApi Google News API. Returns article " + "titles, source URLs, publishers, authors, snippets, and publication times." + ) + parameters: dict = Field( + default_factory=lambda: { + "type": "object", + "properties": { + "query": { + "type": "string", + "description": "Required. News search query. Google News operators such as site: and when: are supported.", + }, + "max_results": { + "type": "integer", + "description": "Maximum articles to return, 1-10. Default is 5; fewer may be available.", + }, + "country": { + "type": "string", + "description": "Optional. Google News country code, such as us, uk, or cn.", + }, + "search_lang": { + "type": "string", + "description": "Optional. Google News language code, such as en or zh-cn.", + }, + }, + "required": ["query"], + } + ) + + async def call(self, context, **kwargs) -> ToolExecResult: + """Search Google News and preserve article metadata for citations. + + Args: + context: Agent context containing the active profile settings. + **kwargs: News query, result limit, country, and language. + + Returns: + News results as JSON, or a configuration or validation error. + + Raises: + RuntimeError: If the search request fails. + """ + _, provider_settings, _ = _get_runtime(context) + if not provider_settings.get("websearch_serpapi_key", []): + return "Error: SerpApi API key is not configured in AstrBot." + + query = kwargs["query"].strip() + if not query: + return "Error: query must not be empty." + max_results = max(1, min(int(kwargs.get("max_results", 5)), 10)) + payload = {"q": query} + for name, parameter in (("country", "gl"), ("search_lang", "hl")): + if kwargs.get(name): + payload[parameter] = kwargs[name] + data = await _serpapi_request(provider_settings, payload, engine="google_news") + + ref_uuid = str(uuid.uuid4())[:4] + results = [] + seen_urls = set() + for group in data.get("news_results", []): + articles = [] + if group.get("link"): + articles.append(group) + if isinstance(group.get("highlight"), dict): + articles.append(group["highlight"]) + articles.extend( + story for story in group.get("stories", []) if isinstance(story, dict) + ) + for article in articles: + source_url = article.get("link") + if not source_url or source_url in seen_urls: + continue + seen_urls.add(source_url) + source = article.get("source") or {} + results.append( + { + "title": article.get("title") or "", + "url": source_url, + "snippet": article.get("snippet") or "", + "source": source.get("name") or source.get("title") or "", + "authors": source.get("authors") or [], + "published_at": article.get("iso_date") + or article.get("date") + or "", + "thumbnail_url": article.get("thumbnail") + or article.get("thumbnail_small") + or "", + "index": f"{ref_uuid}.{len(results) + 1}", + } + ) + _cache_favicon(source_url, source.get("icon")) + if len(results) >= max_results: + break + if len(results) >= max_results: + break + return json.dumps({"results": results}, ensure_ascii=False) + + @builtin_tool(config=_SERPAPI_WEB_SEARCH_TOOL_CONFIG) @pydantic_dataclass class SerpApiImageSearchTool(FunctionTool[AstrAgentContext]): @@ -2128,6 +2231,7 @@ async def call(self, context, **kwargs) -> ToolExecResult: "ExaWebSearchTool", "SerpApiFinanceSearchTool", "SerpApiImageSearchTool", + "SerpApiNewsSearchTool", "SerpApiScholarSearchTool", "SerpApiWebSearchTool", "TavilyExtractWebPageTool", diff --git a/astrbot/dashboard/services/chat_service.py b/astrbot/dashboard/services/chat_service.py index fe3e24264cd..7c4a8a3f958 100644 --- a/astrbot/dashboard/services/chat_service.py +++ b/astrbot/dashboard/services/chat_service.py @@ -278,6 +278,7 @@ def extract_web_search_refs(accumulated_text: str, accumulated_parts: list) -> d "web_search_brave", "web_search_deepseek", "web_search_serpapi", + "news_search_serpapi", "image_search_serpapi", "finance_search_serpapi", "scholar_search_serpapi", diff --git a/astrbot/dashboard/services/live_chat_service.py b/astrbot/dashboard/services/live_chat_service.py index 2b17c5e7c76..c34986923b8 100644 --- a/astrbot/dashboard/services/live_chat_service.py +++ b/astrbot/dashboard/services/live_chat_service.py @@ -289,6 +289,7 @@ def extract_web_search_refs(accumulated_text: str, accumulated_parts: list) -> d "web_search_brave", "web_search_deepseek", "web_search_serpapi", + "news_search_serpapi", "image_search_serpapi", "finance_search_serpapi", "scholar_search_serpapi", diff --git a/changelogs/unreleased.md b/changelogs/unreleased.md index 2e6d55d8881..d7cb966a8ad 100644 --- a/changelogs/unreleased.md +++ b/changelogs/unreleased.md @@ -2,6 +2,8 @@ - Simplify Context Management Strategy settings: Handling for History Limits or Context Window Pressure → Compression Strategy; Model Provider ID for Context Compression → Compression Model. Move maximum turns, discarded turns, compression instruction, recent-context ratio and fallback context window size under the collapsed More Settings section. Preserve existing configuration keys, defaults and runtime behavior. +- Add SerpApi Google News search with publisher, author, publication time, and WebUI citation support. + - Add compact data-cleanup checkboxes to the existing bot deletion dialog. Custom rules, preferences, configuration routes and scheduled tasks are selected by default; AI conversations, message history, local traces and usage statistics are retained unless selected. Preserve shared resources and match adapter IDs exactly. - Resolve Lark group-message sender names through the existing user-info lookup, sharing the same per-user cache with private chats (30 minutes for successful names and one minute for failures). Application senders skip user-directory lookups. diff --git a/dashboard/src/i18n/locales/en-US/features/config-metadata.json b/dashboard/src/i18n/locales/en-US/features/config-metadata.json index c3ed8c06be6..9fd9a516ccd 100644 --- a/dashboard/src/i18n/locales/en-US/features/config-metadata.json +++ b/dashboard/src/i18n/locales/en-US/features/config-metadata.json @@ -188,7 +188,7 @@ "AnySearch" ], "subtitles": [ - "Google web, image, scholar, and finance search", + "Google web, news, image, scholar, and finance search", "Official DeepSeek search API", "", "", @@ -232,7 +232,7 @@ }, "websearch_serpapi_key": { "description": "SerpApi API Key", - "hint": "Supports Google web, image, scholar, and finance search. Multiple keys can be added for rotation. Get a key: [https://serpapi.com/manage-api-key](https://serpapi.com/manage-api-key)" + "hint": "Supports Google web, news, image, scholar, and finance search. Multiple keys can be added for rotation. Get a key: [https://serpapi.com/manage-api-key](https://serpapi.com/manage-api-key)" }, "websearch_deepseek_key": { "description": "DeepSeek API Key", diff --git a/dashboard/src/i18n/locales/ja-JP/features/config-metadata.json b/dashboard/src/i18n/locales/ja-JP/features/config-metadata.json index e798966582d..f13ca731991 100644 --- a/dashboard/src/i18n/locales/ja-JP/features/config-metadata.json +++ b/dashboard/src/i18n/locales/ja-JP/features/config-metadata.json @@ -276,7 +276,7 @@ "AnySearch" ], "subtitles": [ - "Google のウェブ・画像・学術・金融検索", + "Google のウェブ・ニュース・画像・学術・金融検索", "DeepSeek 公式検索 API", "", "", @@ -320,7 +320,7 @@ }, "websearch_serpapi_key": { "description": "SerpApi API Key", - "hint": "Google のウェブ・画像・学術・金融検索に対応。複数の Key を追加してローテーションできます。Key の取得:[https://serpapi.com/manage-api-key](https://serpapi.com/manage-api-key)" + "hint": "Google のウェブ・ニュース・画像・学術・金融検索に対応。複数の Key を追加してローテーションできます。Key の取得:[https://serpapi.com/manage-api-key](https://serpapi.com/manage-api-key)" }, "websearch_deepseek_key": { "description": "DeepSeek API Key", diff --git a/dashboard/src/i18n/locales/ru-RU/features/config-metadata.json b/dashboard/src/i18n/locales/ru-RU/features/config-metadata.json index 5b7ce75ed72..46bd0d7ce36 100644 --- a/dashboard/src/i18n/locales/ru-RU/features/config-metadata.json +++ b/dashboard/src/i18n/locales/ru-RU/features/config-metadata.json @@ -276,7 +276,7 @@ "AnySearch" ], "subtitles": [ - "Веб-поиск, изображения, научные публикации и финансы Google", + "Веб-поиск, новости, изображения, научные публикации и финансы Google", "Официальный поисковый API DeepSeek", "", "", @@ -320,7 +320,7 @@ }, "websearch_serpapi_key": { "description": "SerpApi API Key", - "hint": "Поддерживает веб-поиск, поиск изображений, научных публикаций и финансовых данных Google. Можно добавить несколько ключей для ротации. Получить ключ: [https://serpapi.com/manage-api-key](https://serpapi.com/manage-api-key)" + "hint": "Поддерживает веб-поиск, поиск новостей, изображений, научных публикаций и финансовых данных Google. Можно добавить несколько ключей для ротации. Получить ключ: [https://serpapi.com/manage-api-key](https://serpapi.com/manage-api-key)" }, "websearch_deepseek_key": { "description": "API-ключ DeepSeek", diff --git a/dashboard/src/i18n/locales/zh-CN/features/config-metadata.json b/dashboard/src/i18n/locales/zh-CN/features/config-metadata.json index b50068469ed..e588d8c0c9d 100644 --- a/dashboard/src/i18n/locales/zh-CN/features/config-metadata.json +++ b/dashboard/src/i18n/locales/zh-CN/features/config-metadata.json @@ -204,7 +204,7 @@ "AnySearch" ], "subtitles": [ - "Google 网页、图片、学术和财经搜索", + "Google 网页、新闻、图片、学术和财经搜索", "DeepSeek 官方搜索接口", "", "", @@ -248,7 +248,7 @@ }, "websearch_serpapi_key": { "description": "SerpApi API Key", - "hint": "支持 Google 网页、图片、学术和财经搜索。可添加多个 Key 轮询。获取 Key:[https://serpapi.com/manage-api-key](https://serpapi.com/manage-api-key)" + "hint": "支持 Google 网页、新闻、图片、学术和财经搜索。可添加多个 Key 轮询。获取 Key:[https://serpapi.com/manage-api-key](https://serpapi.com/manage-api-key)" }, "websearch_deepseek_key": { "description": "DeepSeek API Key", diff --git a/docs/en/dev/astrbot-config.md b/docs/en/dev/astrbot-config.md index 5c790c9e2ae..8395eb06ffb 100644 --- a/docs/en/dev/astrbot-config.md +++ b/docs/en/dev/astrbot-config.md @@ -296,7 +296,7 @@ Whether to enable AstrBot's built-in web search capability. Default is `false`. Web search provider type. Default is `tavily`. Currently supports `serpapi`, `deepseek`, `tavily`, `bocha`, `baidu_ai_search`, `brave`, `firecrawl`, `exa`, and `anysearch`. -- `serpapi`: Uses SerpApi Google Search, Google Images Light, Google Finance, and Google Scholar. +- `serpapi`: Uses SerpApi Google Search, Google News, Google Images Light, Google Finance, and Google Scholar. - `deepseek`: Uses the DeepSeek Search API. - `tavily`: Uses the Tavily search engine. - `bocha`: Uses the BoCha search engine. @@ -328,7 +328,7 @@ API Key list for the DeepSeek search engine. Required when using `deepseek` as t #### `provider_settings.websearch_serpapi_key` -API Key list shared by SerpApi Google Search, Google Images Light, Google Finance, and Google Scholar. Required when using `serpapi` as the web search provider. Obtain a key at [SerpApi](https://serpapi.com/manage-api-key). Multiple keys rotate, with failover on authentication and quota errors. +API Key list shared by SerpApi Google Search, Google News, Google Images Light, Google Finance, and Google Scholar. Required when using `serpapi` as the web search provider. Obtain a key at [SerpApi](https://serpapi.com/manage-api-key). Multiple keys rotate, with failover on authentication and quota errors. #### `provider_settings.web_search_link` diff --git a/docs/en/use/websearch.md b/docs/en/use/websearch.md index 6642246d048..262f464cd9c 100644 --- a/docs/en/use/websearch.md +++ b/docs/en/use/websearch.md @@ -31,7 +31,7 @@ AstrBot supports nine providers. Configure one to start; you do not need an acco | Provider | Get a key | Capabilities available in AstrBot | | --- | --- | --- | -| [SerpApi](./websearch/serpapi.md) | [SerpApi API key](https://serpapi.com/manage-api-key) | Google web search, Images Light, Finance, and Scholar | +| [SerpApi](./websearch/serpapi.md) | [SerpApi API key](https://serpapi.com/manage-api-key) | Google web search, News, Images Light, Finance, and Scholar | | [DeepSeek Search API](./websearch/deepseek.md) | [DeepSeek Platform](https://platform.deepseek.com/api_keys) / [Search Docs](https://api-docs.deepseek.com/guides/search) | Web search and page content extraction from a URL | | Tavily | [Tavily dashboard](https://app.tavily.com/home) | Web search and page content extraction from a URL | | Bocha | [BoCha](https://bochaai.com/) | Web search | diff --git a/docs/zh/dev/astrbot-config.md b/docs/zh/dev/astrbot-config.md index ded6964b7ec..588284193e7 100644 --- a/docs/zh/dev/astrbot-config.md +++ b/docs/zh/dev/astrbot-config.md @@ -296,7 +296,7 @@ ID 白名单。填写后,将只处理所填写的 ID 发来的消息事件。 网页搜索提供商类型。默认为 `tavily`。目前支持 `serpapi`、`deepseek`、`tavily`、`bocha`、`baidu_ai_search`、`brave`、`firecrawl`、`exa`、`anysearch`。 -- `serpapi`:使用 SerpApi Google Search、Google Images Light、Google Finance 和 Google Scholar。 +- `serpapi`:使用 SerpApi Google Search、Google News、Google Images Light、Google Finance 和 Google Scholar。 - `deepseek`:使用 DeepSeek Search API。 - `tavily`:使用 Tavily 搜索引擎。 - `bocha`:使用 BoCha 搜索引擎。 @@ -328,7 +328,7 @@ DeepSeek 搜索引擎的 API Key 列表。使用 `deepseek` 作为网页搜索 #### `provider_settings.websearch_serpapi_key` -SerpApi Google Search、Google Images Light、Google Finance 和 Google Scholar 共用的 API Key 列表。使用 `serpapi` 作为网页搜索提供商时需要填写。前往 [SerpApi](https://serpapi.com/manage-api-key) 获取 Key。多个 Key 轮询使用,鉴权或额度错误时会尝试下一个 Key。 +SerpApi Google Search、Google News、Google Images Light、Google Finance 和 Google Scholar 共用的 API Key 列表。使用 `serpapi` 作为网页搜索提供商时需要填写。前往 [SerpApi](https://serpapi.com/manage-api-key) 获取 Key。多个 Key 轮询使用,鉴权或额度错误时会尝试下一个 Key。 #### `provider_settings.web_search_link` diff --git a/docs/zh/use/websearch.md b/docs/zh/use/websearch.md index 5114e85faf3..4489df8ce29 100644 --- a/docs/zh/use/websearch.md +++ b/docs/zh/use/websearch.md @@ -31,7 +31,7 @@ | 提供商 | Key 申请入口 | AstrBot 提供的能力 | | --- | --- | --- | -| [SerpApi](./websearch/serpapi.md) | [SerpApi API Key](https://serpapi.com/manage-api-key) | Google 网页搜索、Images Light 图片搜索、Finance 金融查询、Scholar 学术搜索 | +| [SerpApi](./websearch/serpapi.md) | [SerpApi API Key](https://serpapi.com/manage-api-key) | Google 网页搜索、News 新闻、Images Light 图片搜索、Finance 金融查询、Scholar 学术搜索 | | [DeepSeek Search API](./websearch/deepseek.md) | [DeepSeek 开放平台](https://platform.deepseek.com/api_keys) / [搜索文档](https://api-docs.deepseek.com/zh-cn/guides/search) | 网页搜索、按 URL 提取网页正文 | | Tavily | [Tavily 控制台](https://app.tavily.com/home) | 网页搜索、按 URL 提取网页正文 | | Bocha | [博查](https://bochaai.com/) | 网页搜索 | diff --git a/tests/unit/test_astr_main_agent.py b/tests/unit/test_astr_main_agent.py index 3089bbc7b34..a02d3054c54 100644 --- a/tests/unit/test_astr_main_agent.py +++ b/tests/unit/test_astr_main_agent.py @@ -799,6 +799,7 @@ async def test_serpapi_injects_all_search_tools(self, mock_event, mock_context): assert req.func_tool.names() == [ "web_search_serpapi", + "news_search_serpapi", "image_search_serpapi", "finance_search_serpapi", "scholar_search_serpapi", @@ -898,6 +899,7 @@ async def test_apply_web_search_tools_adds_search_and_extract_tools( "web_search_tavily", "web_search_deepseek", "web_search_serpapi", + "news_search_serpapi", "image_search_serpapi", "finance_search_serpapi", "scholar_search_serpapi", @@ -1583,6 +1585,7 @@ async def test_ensure_tools_from_persona(self, mock_event, mock_context): "serpapi", [ "web_search_serpapi", + "news_search_serpapi", "image_search_serpapi", "finance_search_serpapi", "scholar_search_serpapi", diff --git a/tests/unit/test_serpapi_search.py b/tests/unit/test_serpapi_search.py index 60cfefea760..3ebe26752fb 100644 --- a/tests/unit/test_serpapi_search.py +++ b/tests/unit/test_serpapi_search.py @@ -542,10 +542,128 @@ async def test_serpapi_tool_limits_first_page_results(serpapi_http, limit, expec } +@pytest.mark.asyncio +async def test_serpapi_news_maps_articles_and_metadata( + serpapi_http, serpapi_context, monkeypatch +): + cache = {} + monkeypatch.setitem(tools.sp.temporary_cache, "_ws_favicon", cache) + serpapi_http.session.get.return_value = _response( + data={ + "news_results": [ + { + "title": "AstrBot adds a news search tool", + "link": "https://example.com/astrbot-news", + "snippet": "The project added Google News support.", + "source": { + "name": "Example News", + "icon": "https://example.com/favicon.ico", + "authors": ["A. Reporter"], + }, + "iso_date": "2026-10-24T08:00:00Z", + "thumbnail": "https://example.com/news.jpg", + }, + {"title": "Group without a direct article", "stories": []}, + ] + } + ) + + result = json.loads( + await tools.SerpApiNewsSearchTool().call( + serpapi_context, + query="AstrBot", + country="us", + search_lang="en", + ) + )["results"] + + assert serpapi_http.session.get.call_args.kwargs["params"] == { + "engine": "google_news", + "api_key": "test-key", + "q": "AstrBot", + "gl": "us", + "hl": "en", + } + assert result == [ + { + "title": "AstrBot adds a news search tool", + "url": "https://example.com/astrbot-news", + "snippet": "The project added Google News support.", + "source": "Example News", + "authors": ["A. Reporter"], + "published_at": "2026-10-24T08:00:00Z", + "thumbnail_url": "https://example.com/news.jpg", + "index": result[0]["index"], + } + ] + assert result[0]["index"].endswith(".1") + assert cache == { + "https://example.com/astrbot-news": "https://example.com/favicon.ico" + } + + +@pytest.mark.asyncio +async def test_serpapi_news_flattens_groups_deduplicates_and_limits( + serpapi_http, serpapi_context +): + serpapi_http.session.get.return_value = _response( + data={ + "news_results": [ + { + "highlight": { + "title": "Highlighted article", + "link": "https://example.com/highlight", + }, + "stories": [ + { + "title": "Duplicate article", + "link": "https://example.com/highlight", + }, + { + "title": "Related article", + "link": "https://example.com/related", + "date": "Oct 24, 2026", + }, + ], + } + ] + } + ) + + result = json.loads( + await tools.SerpApiNewsSearchTool().call( + serpapi_context, query="AstrBot", max_results=2 + ) + )["results"] + + assert [item["url"] for item in result] == [ + "https://example.com/highlight", + "https://example.com/related", + ] + assert result[1]["published_at"] == "Oct 24, 2026" + + +@pytest.mark.asyncio +async def test_serpapi_news_validates_query_before_request( + serpapi_http, serpapi_context +): + result = await tools.SerpApiNewsSearchTool().call(serpapi_context, query=" ") + + assert result == "Error: query must not be empty." + serpapi_http.factory.assert_not_called() + + @pytest.mark.asyncio @pytest.mark.parametrize("status", [401, 403, 429]) @pytest.mark.parametrize( - "engine", ["google", "google_images_light", "google_finance", "google_scholar"] + "engine", + [ + "google", + "google_news", + "google_images_light", + "google_finance", + "google_scholar", + ], ) async def test_serpapi_rotates_and_retries_key_errors(serpapi_http, status, engine): serpapi_http.session.get.side_effect = [ @@ -652,6 +770,7 @@ async def test_serpapi_transport_errors_do_not_expose_credentials( "tool_class", [ tools.SerpApiWebSearchTool, + tools.SerpApiNewsSearchTool, tools.SerpApiImageSearchTool, tools.SerpApiFinanceSearchTool, tools.SerpApiScholarSearchTool, @@ -682,6 +801,7 @@ async def test_serpapi_requires_credentials_before_request(serpapi_http, tool_cl "tool_class", [ tools.SerpApiWebSearchTool, + tools.SerpApiNewsSearchTool, tools.SerpApiImageSearchTool, tools.SerpApiFinanceSearchTool, tools.SerpApiScholarSearchTool, diff --git a/tests/unit/test_web_search_refs.py b/tests/unit/test_web_search_refs.py index d805e229888..3132f244ff1 100644 --- a/tests/unit/test_web_search_refs.py +++ b/tests/unit/test_web_search_refs.py @@ -19,6 +19,7 @@ [ "web_search_deepseek", "web_search_serpapi", + "news_search_serpapi", "image_search_serpapi", "finance_search_serpapi", "scholar_search_serpapi",