diff --git a/backend/packages/harness/deerflow/community/brave/tools.py b/backend/packages/harness/deerflow/community/brave/tools.py index 31a2370470..947a7e076b 100644 --- a/backend/packages/harness/deerflow/community/brave/tools.py +++ b/backend/packages/harness/deerflow/community/brave/tools.py @@ -56,7 +56,7 @@ def _coerce_max_results( ) -> int: try: coerced = int(value) - except (TypeError, ValueError): + except (TypeError, ValueError, OverflowError): logger.warning( "Invalid Brave Search max_results=%r; using default %s", value, diff --git a/backend/packages/harness/deerflow/community/groundroute/tools.py b/backend/packages/harness/deerflow/community/groundroute/tools.py index d8be3fdd6e..d666e03eb3 100644 --- a/backend/packages/harness/deerflow/community/groundroute/tools.py +++ b/backend/packages/harness/deerflow/community/groundroute/tools.py @@ -55,7 +55,7 @@ def _get_api_key(tool_name: str) -> str | None: def _coerce_max_results(value: object, *, default: int = _DEFAULT_MAX_RESULTS) -> int: try: coerced = int(value) - except (TypeError, ValueError): + except (TypeError, ValueError, OverflowError): logger.warning("Invalid GroundRoute max_results=%r; using default %s", value, default) coerced = default return max(1, min(coerced, _MAX_RESULTS_CAP)) diff --git a/backend/packages/harness/deerflow/community/searxng/tools.py b/backend/packages/harness/deerflow/community/searxng/tools.py index 447f9726e3..9eb3e822b6 100644 --- a/backend/packages/harness/deerflow/community/searxng/tools.py +++ b/backend/packages/harness/deerflow/community/searxng/tools.py @@ -46,7 +46,7 @@ async def web_search_tool(query: str, time_range: SearchTimeRange | None = None) else: try: max_results = int(raw) - except (TypeError, ValueError): + except (TypeError, ValueError, OverflowError): logger.warning( "Invalid SearXNG max_results=%r; using default %s", raw, diff --git a/backend/packages/harness/deerflow/community/serper/tools.py b/backend/packages/harness/deerflow/community/serper/tools.py index 9f960981dd..8ca23ab957 100644 --- a/backend/packages/harness/deerflow/community/serper/tools.py +++ b/backend/packages/harness/deerflow/community/serper/tools.py @@ -40,7 +40,7 @@ def _coerce_max_results(value: object, default: int = 5, max_allowed: int = _SER """Coerce config/parameter input into a bounded positive result count.""" try: count = int(value) - except (TypeError, ValueError): + except (TypeError, ValueError, OverflowError): return default if count <= 0: return default diff --git a/backend/packages/harness/deerflow/community/serply/tools.py b/backend/packages/harness/deerflow/community/serply/tools.py index 7d476d9597..e0f65062a5 100644 --- a/backend/packages/harness/deerflow/community/serply/tools.py +++ b/backend/packages/harness/deerflow/community/serply/tools.py @@ -58,7 +58,7 @@ def _coerce_max_results( ) -> int: try: coerced = int(value) - except (TypeError, ValueError): + except (TypeError, ValueError, OverflowError): logger.warning("Invalid Serply max_results=%r; using default %s", value, default) coerced = default if coerced < 1: diff --git a/backend/packages/harness/deerflow/community/sofya/tools.py b/backend/packages/harness/deerflow/community/sofya/tools.py index 92ffcf06b8..b78ff64c7b 100644 --- a/backend/packages/harness/deerflow/community/sofya/tools.py +++ b/backend/packages/harness/deerflow/community/sofya/tools.py @@ -46,7 +46,7 @@ def _coerce_max_results(value: object, default: int = 5, max_allowed: int = _SOF """Coerce config/parameter input into a bounded positive result count.""" try: count = int(value) # type: ignore[call-overload] - except (TypeError, ValueError): + except (TypeError, ValueError, OverflowError): return default if count <= 0: return default @@ -57,7 +57,7 @@ def _coerce_content_limit(value: object, default: int = _DEFAULT_CONTENTS_MAX_CH """Coerce the per-result content limit. 0 means no limit; anything invalid falls back to the default.""" try: limit = int(value) # type: ignore[call-overload] - except (TypeError, ValueError): + except (TypeError, ValueError, OverflowError): return default return limit if limit >= 0 else default diff --git a/backend/tests/test_brave_tools.py b/backend/tests/test_brave_tools.py index 3d57a25b21..8d04f68c9e 100644 --- a/backend/tests/test_brave_tools.py +++ b/backend/tests/test_brave_tools.py @@ -731,3 +731,10 @@ def test_package_exports_image_search_tool(): from deerflow.community.brave.tools import image_search_tool as direct_image_search_tool assert image_search_tool is direct_image_search_tool + + +def test_coerce_max_results_inf_falls_back_to_default(): + """A YAML `.inf` max_results must fall back to the default, not crash.""" + import deerflow.community.brave.tools as brave_mod + + assert brave_mod._coerce_max_results(float("inf")) == brave_mod._DEFAULT_MAX_RESULTS diff --git a/backend/tests/test_groundroute_tools.py b/backend/tests/test_groundroute_tools.py index 71e01df261..95de840fae 100644 --- a/backend/tests/test_groundroute_tools.py +++ b/backend/tests/test_groundroute_tools.py @@ -328,3 +328,10 @@ class TestWebFetchTool: patcher.stop() assert result == "Error: No results found" + + +def test_coerce_max_results_inf_falls_back_to_default(): + """A YAML `.inf` max_results must fall back to the default, not crash.""" + import deerflow.community.groundroute.tools as groundroute_mod + + assert groundroute_mod._coerce_max_results(float("inf")) == groundroute_mod._DEFAULT_MAX_RESULTS diff --git a/backend/tests/test_searxng_client.py b/backend/tests/test_searxng_client.py index f3b8850270..e6b11ba32b 100644 --- a/backend/tests/test_searxng_client.py +++ b/backend/tests/test_searxng_client.py @@ -298,3 +298,24 @@ class TestSearxngTools: await tools.web_search_tool.ainvoke({"query": "latest release", "time_range": "week"}) mock_client.search.assert_called_once_with("latest release", max_results=5, time_range="week") + + @patch("deerflow.community.searxng.tools._get_searxng_client") + async def test_web_search_tool_inf_max_results_falls_back_to_default(self, mock_get_client): + """A YAML `.inf` max_results must fall back to the default, not error out.""" + mock_client = MagicMock() + mock_client.search = AsyncMock( + return_value=[ + {"title": "Result 1", "url": "https://example.com/1", "content": "Desc 1"}, + ] + ) + mock_get_client.return_value = mock_client + + with patch( + "deerflow.community.searxng.tools._get_tool_config", + return_value={"max_results": float("inf")}, + ): + result = await tools.web_search_tool.ainvoke("test query") + + data = json.loads(result) + assert "error" not in data + assert mock_client.search.call_args.kwargs["max_results"] == 5 diff --git a/backend/tests/test_serper_tools.py b/backend/tests/test_serper_tools.py index f1bbddc9d4..199d680364 100644 --- a/backend/tests/test_serper_tools.py +++ b/backend/tests/test_serper_tools.py @@ -1212,3 +1212,10 @@ def test_package_exports_image_search_tool(): from deerflow.community.serper.tools import image_search_tool as direct_image_search_tool assert image_search_tool is direct_image_search_tool + + +def test_coerce_max_results_inf_falls_back_to_default(): + """A YAML `.inf` max_results must fall back to the default, not crash.""" + import deerflow.community.serper.tools as serper_mod + + assert serper_mod._coerce_max_results(float("inf")) == 5 diff --git a/backend/tests/test_serply_tools.py b/backend/tests/test_serply_tools.py index 89fed878e7..557f92df31 100644 --- a/backend/tests/test_serply_tools.py +++ b/backend/tests/test_serply_tools.py @@ -316,3 +316,10 @@ class TestWebSearchTool: assert result["total_results"] == 1 assert mock_get.call_args.kwargs["headers"]["X-Api-Key"] == "env-key" + + +def test_coerce_max_results_inf_falls_back_to_default(): + """A YAML `.inf` max_results must fall back to the default, not crash.""" + import deerflow.community.serply.tools as serply_mod + + assert serply_mod._coerce_max_results(float("inf")) == serply_mod._DEFAULT_MAX_RESULTS diff --git a/backend/tests/test_sofya_tools.py b/backend/tests/test_sofya_tools.py index fa931da283..09d91157d4 100644 --- a/backend/tests/test_sofya_tools.py +++ b/backend/tests/test_sofya_tools.py @@ -591,3 +591,15 @@ class TestWebFetchTool: result = web_fetch_tool.invoke({"url": "https://example.com"}) assert result == "Error: SOFYA_API_KEY is not configured" + + +class TestCoerceInfFallsBackToDefault: + def test_coerce_max_results_inf_returns_default(self): + from deerflow.community.sofya.tools import _coerce_max_results + + assert _coerce_max_results(float("inf")) == 5 + + def test_coerce_content_limit_inf_returns_default(self): + from deerflow.community.sofya.tools import _coerce_content_limit + + assert _coerce_content_limit(float("inf")) == 2000