-
Notifications
You must be signed in to change notification settings - Fork 1
fix: Mock html2text in content truncation test #28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
cf7787f
55f771f
b04374d
77588c4
827b532
e3f872c
a41667b
77d9015
91fbd3f
415a5df
4820c10
33e5184
818c3d0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -251,79 +251,146 @@ async def get_server_info_tool() -> dict: | |
| return response.model_dump() | ||
|
|
||
|
|
||
| async def _fetch_with_serper(query: str, api_key: str): | ||
| """Fetch search results using Serper API. | ||
|
|
||
| Args: | ||
| query: Search query | ||
| api_key: Serper API key | ||
|
|
||
| Returns: | ||
| Tuple of (results, search_source) | ||
| """ | ||
| import asyncio | ||
|
|
||
| from mcp_server import fetch_search_results | ||
|
|
||
| logger.info("Using Serper API for search") | ||
| results = await asyncio.get_event_loop().run_in_executor( | ||
| None, fetch_search_results, query, api_key | ||
| ) | ||
| return results, "Serper API" | ||
|
|
||
|
|
||
| async def _fetch_with_duckduckgo(query: str, has_api_key: bool): | ||
| """Fetch search results using DuckDuckGo. | ||
|
|
||
| Args: | ||
| query: Search query | ||
| has_api_key: Whether Serper API key was configured | ||
|
|
||
| Returns: | ||
| Tuple of (results, search_source) | ||
| """ | ||
| import asyncio | ||
|
|
||
| from mcp_server import fetch_duckduckgo_search_results | ||
|
|
||
| if not has_api_key: | ||
| logger.info("No Serper API key configured, using DuckDuckGo fallback") | ||
| else: | ||
| logger.warning("No results from Serper API, trying DuckDuckGo fallback") | ||
|
|
||
| results = await asyncio.get_event_loop().run_in_executor( | ||
| None, fetch_duckduckgo_search_results, query | ||
| ) | ||
| return results, "DuckDuckGo (free fallback)" | ||
|
|
||
|
Comment on lines
+275
to
+298
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Ensure the DuckDuckGo helper is fully typed. Please mirror the Serper changes here: add a precise return type (e.g., |
||
|
|
||
| def _format_no_results_error(query: str, search_source: str) -> dict: | ||
| """Format error response for no results. | ||
|
|
||
| Args: | ||
| query: Search query | ||
| search_source: Source that was used | ||
|
|
||
| Returns: | ||
| Error dictionary | ||
| """ | ||
| return { | ||
| "error": "No search results found from any source.", | ||
| "query": query, | ||
| "search_source": search_source, | ||
| } | ||
|
|
||
|
|
||
| def _format_search_error(error: str, query: str, search_source: str) -> dict: | ||
| """Format error response for search failure. | ||
|
|
||
| Args: | ||
| error: Error message | ||
| query: Search query | ||
| search_source: Source that was attempted | ||
|
|
||
| Returns: | ||
| Error dictionary | ||
| """ | ||
| return { | ||
| "error": f"Search failed: {error}", | ||
| "query": query, | ||
| "search_source": search_source, | ||
| } | ||
|
|
||
|
|
||
| async def _process_and_format_results(results, query: str, search_source: str): | ||
| """Process search results and format response. | ||
|
|
||
| Args: | ||
| results: Raw search results | ||
| query: Search query | ||
| search_source: Source of results | ||
|
|
||
| Returns: | ||
| Formatted results dictionary | ||
| """ | ||
| import asyncio | ||
|
|
||
| from mcp_server import process_search_results | ||
|
|
||
| processed_results = await asyncio.get_event_loop().run_in_executor( | ||
| None, process_search_results, results | ||
| ) | ||
|
|
||
| return { | ||
| "query": query, | ||
| "search_source": search_source, | ||
| "results": [result.model_dump() for result in processed_results], | ||
| } | ||
|
Comment on lines
+300
to
+358
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Type the formatting utilities. Our guidelines require explicit return types. 🤖 Prompt for AI Agents |
||
|
|
||
|
|
||
| def create_webcat_functions() -> Dict[str, Any]: | ||
| """Create a dictionary of WebCat functions for the tools to use.""" | ||
|
|
||
| # Import the existing functions from the main server | ||
| from mcp_server import ( | ||
| SERPER_API_KEY, | ||
| fetch_duckduckgo_search_results, | ||
| fetch_search_results, | ||
| process_search_results, | ||
| ) | ||
| from mcp_server import SERPER_API_KEY | ||
|
|
||
| async def search_function(query: str) -> Dict[str, Any]: | ||
| """Wrapper for the search functionality.""" | ||
| import asyncio | ||
|
|
||
| results = [] | ||
| search_source = "Unknown" | ||
|
|
||
| try: | ||
| # Try Serper API first if key is available | ||
| if SERPER_API_KEY: | ||
| logger.info("Using Serper API for search") | ||
| search_source = "Serper API" | ||
| # Run the synchronous function in a thread pool | ||
| results = await asyncio.get_event_loop().run_in_executor( | ||
| None, fetch_search_results, query, SERPER_API_KEY | ||
| ) | ||
| results, search_source = await _fetch_with_serper(query, SERPER_API_KEY) | ||
|
|
||
| # Fall back to DuckDuckGo if no API key or no results from Serper | ||
| if not results: | ||
| if not SERPER_API_KEY: | ||
| logger.info( | ||
| "No Serper API key configured, using DuckDuckGo fallback" | ||
| ) | ||
| else: | ||
| logger.warning( | ||
| "No results from Serper API, trying DuckDuckGo fallback" | ||
| ) | ||
|
|
||
| search_source = "DuckDuckGo (free fallback)" | ||
| # Run the synchronous function in a thread pool | ||
| results = await asyncio.get_event_loop().run_in_executor( | ||
| None, fetch_duckduckgo_search_results, query | ||
| results, search_source = await _fetch_with_duckduckgo( | ||
| query, bool(SERPER_API_KEY) | ||
| ) | ||
|
|
||
| # Check if we got any results | ||
| if not results: | ||
| logger.warning(f"No search results found for query: {query}") | ||
| return { | ||
| "error": "No search results found from any source.", | ||
| "query": query, | ||
| "search_source": search_source, | ||
| } | ||
|
|
||
| # Process the results in thread pool (since it involves web scraping) | ||
| processed_results = await asyncio.get_event_loop().run_in_executor( | ||
| None, process_search_results, results | ||
| ) | ||
| return _format_no_results_error(query, search_source) | ||
|
|
||
| # Return formatted results | ||
| return { | ||
| "query": query, | ||
| "search_source": search_source, | ||
| "results": [result.model_dump() for result in processed_results], | ||
| } | ||
| # Process and format results | ||
| return await _process_and_format_results(results, query, search_source) | ||
|
|
||
| except Exception as e: | ||
| logger.error(f"Error in search function: {str(e)}") | ||
| return { | ||
| "error": f"Search failed: {str(e)}", | ||
| "query": query, | ||
| "search_source": search_source, | ||
| } | ||
| return _format_search_error(str(e), query, search_source) | ||
|
|
||
| async def health_check_function() -> Dict[str, Any]: | ||
| """Wrapper for the health check functionality.""" | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Add return types and favour
asyncio.to_thread.New helpers must have explicit return annotations per our typing rules, and we can avoid the deprecated
asyncio.get_event_loop()by switching toasyncio.to_thread(...). Consider:Apply the same pattern to the DuckDuckGo helper so static typing and asyncio usage stay consistent.
📝 Committable suggestion
🤖 Prompt for AI Agents