refactor(google_serper_api): migrate to new tool mode implementation (#5446)

* # refactor(google_serper_api): migrate to new tool mode implementation

BREAKING CHANGE: Replace legacy LCToolComponent implementation with new Component base class

- Migrate from LCToolComponent to Component base class
- Add tool_mode flag to MultilineInput
- Update output configuration to use DataFrame type
- Implement structured error handling with DataFrame responses
- Remove legacy tool mode implementation

* test(google-serper): add unit tests for GoogleSerperAPIComponent

- Add comprehensive test suite for GoogleSerperAPIComponent
- Mock HTTP requests to test search functionality
- Test component initialization and configuration
- Add error handling test cases
- Test text search and wrapper building methods
- Ensure proper DataFrame output structure

This change improves test coverage for the Google Serper API integration,
following existing test patterns in the project.

* [autofix.ci] apply automated fixes

* style(tests): remove unused fixture argument in google-serper test

- Remove unused mock_search_results fixture from test_text_search_serper
- Fix linting error ARG001 (unused function argument)

* revert(tools): restore Google Search API component to original implementation

Due to backward compatibility concerns, reverting the Google Search API component
to its initial implementation state to maintain stability and prevent breaking changes.

* refactor(components): mark GoogleSerperAPI component as deprecated & Legacy

* feat(components): add GoogleSerperAPICore component

* refactor(google-serper): fix filename typo from 'gloogle' to 'google'

* test(google-serper): add unit tests following component test guide

* feat(icons): improve Serper icon quality and add to icon list

* [autofix.ci] apply automated fixes

* Update test_google_serper_api_core.py

test update

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Edwin Jose <edwin.jose@datastax.com>
This commit is contained in:
VICTOR CORREA GOMES 2025-01-17 22:25:34 -03:00 • committed by GitHub
commit d650b21f17
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 213 additions and 44 deletions

View file

@ -11,6 +11,7 @@ from .glean_search_api import GleanSearchAPIComponent
from .google_search_api import GoogleSearchAPIComponent
from .google_search_api_core import GoogleSearchAPICore
from .google_serper_api import GoogleSerperAPIComponent
from .google_serper_api_core import GoogleSerperAPICore
from .mcp_stdio import MCPStdio
from .python_code_structured_tool import PythonCodeStructuredTool
from .python_repl import PythonREPLToolComponent
@ -42,6 +43,7 @@ __all__ = [
"GoogleSearchAPIComponent",
"GoogleSearchAPICore",
"GoogleSerperAPIComponent",
"GoogleSerperAPICore",
"MCPStdio",
"PythonCodeStructuredTool",
"PythonREPLToolComponent",

View file

@ -7,10 +7,11 @@ from langflow.schema import Data
class GoogleSerperAPIComponent(LCToolComponent):
display_name = "Google Serper API"
display_name = "Google Serper API [DEPRECATED]"
description = "Call the Serper.dev Google Search API."
name = "GoogleSerperAPI"
icon = "Google"
legacy = True
inputs = [
SecretStrInput(name="serper_api_key", display_name="Serper API Key", required=True),
MultilineInput(

View file

@ -0,0 +1,74 @@
from langchain_community.utilities.google_serper import GoogleSerperAPIWrapper
from langflow.custom import Component
from langflow.io import IntInput, MultilineInput, Output, SecretStrInput
from langflow.schema import DataFrame
from langflow.schema.message import Message
class GoogleSerperAPICore(Component):
display_name = "Google Serper API"
description = "Call the Serper.dev Google Search API."
icon = "Serper"
inputs = [
SecretStrInput(
name="serper_api_key",
display_name="Serper API Key",
required=True,
),
MultilineInput(
name="input_value",
display_name="Input",
tool_mode=True,
),
IntInput(
name="k",
display_name="Number of results",
value=4,
required=True,
),
]
outputs = [
Output(
display_name="Results",
name="results",
type_=DataFrame,
method="search_serper",
),
]
def search_serper(self) -> DataFrame:
try:
wrapper = self._build_wrapper()
results = wrapper.results(query=self.input_value)
list_results = results.get("organic", [])
# Convert results to DataFrame using list comprehension
df_data = [
{
"title": result.get("title", ""),
"link": result.get("link", ""),
"snippet": result.get("snippet", ""),
}
for result in list_results
]
return DataFrame(df_data)
except (ValueError, KeyError, ConnectionError) as e:
error_message = f"Error occurred while searching: {e!s}"
self.status = error_message
# Return DataFrame with error as a list of dictionaries
return DataFrame([{"error": error_message}])
def text_search_serper(self) -> Message:
search_results = self.search_serper()
text_result = search_results.to_string(index=False) if not search_results.empty else "No results found."
return Message(text=text_result)
def _build_wrapper(self):
return GoogleSerperAPIWrapper(serper_api_key=self.serper_api_key, k=self.k)
def build(self):
return self.search_serper