import os import re from typing import Any from crewai.tools import BaseTool, EnvVar from pydantic import Field class SerpApiBaseTool(BaseTool): """Base class for SerpApi functionality with shared capabilities.""" package_dependencies: list[str] = Field(default_factory=lambda: ["serpapi"]) env_vars: list[EnvVar] = Field( default_factory=lambda: [ EnvVar( name="SERPAPI_API_KEY", description="API key for SerpApi searches", required=True, ), ] ) client: Any | None = None def __init__(self, **kwargs: Any) -> None: super().__init__(**kwargs) try: from serpapi import Client except ImportError: import click if click.confirm( "You are missing the 'serpapi' package. Would you like to install it?" ): import subprocess subprocess.run(["uv", "add", "serpapi"], check=True) # noqa: S607 from serpapi import Client # type: ignore[import-untyped] else: raise ImportError( "`serpapi` package not found, please install with `uv add serpapi`" ) from None api_key = os.getenv("SERPAPI_API_KEY") if not api_key: raise ValueError( "Missing API key, you can get the key from https://serpapi.com/manage-api-key" ) self.client = Client(api_key=api_key) def _omit_fields( self, data: dict[str, Any] | list[Any], omit_patterns: list[str] ) -> None: if isinstance(data, dict): for field in list(data.keys()): if any(re.compile(p).match(field) for p in omit_patterns): data.pop(field, None) else: if isinstance(data[field], (dict, list)): self._omit_fields(data[field], omit_patterns) elif isinstance(data, list): for item in data: self._omit_fields(item, omit_patterns)