mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-01-22 06:18:14 +00:00
Squashed 'packages/tools/' content from commit 78317b9c
git-subtree-dir: packages/tools git-subtree-split: 78317b9c127f18bd040c1d77e3c0840cdc9a5b38
This commit is contained in:
119
crewai_tools/tools/parallel_tools/parallel_search_tool.py
Normal file
119
crewai_tools/tools/parallel_tools/parallel_search_tool.py
Normal file
@@ -0,0 +1,119 @@
|
||||
import os
|
||||
from typing import Any, Dict, List, Optional, Type, Annotated
|
||||
|
||||
import requests
|
||||
from crewai.tools import BaseTool, EnvVar
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class ParallelSearchInput(BaseModel):
|
||||
"""Input schema for ParallelSearchTool using the Search API (v1beta).
|
||||
|
||||
At least one of objective or search_queries is required.
|
||||
"""
|
||||
|
||||
objective: Optional[str] = Field(
|
||||
None,
|
||||
description="Natural-language goal for the web research (<=5000 chars)",
|
||||
max_length=5000,
|
||||
)
|
||||
search_queries: Optional[List[Annotated[str, Field(max_length=200)]]] = Field(
|
||||
default=None,
|
||||
description="Optional list of keyword queries (<=5 items, each <=200 chars)",
|
||||
min_length=1,
|
||||
max_length=5,
|
||||
)
|
||||
processor: str = Field(
|
||||
default="base",
|
||||
description="Search processor: 'base' (fast/low cost) or 'pro' (higher quality/freshness)",
|
||||
pattern=r"^(base|pro)$",
|
||||
)
|
||||
max_results: int = Field(
|
||||
default=10,
|
||||
ge=1,
|
||||
le=40,
|
||||
description="Maximum number of search results to return (processor limits apply)",
|
||||
)
|
||||
max_chars_per_result: int = Field(
|
||||
default=6000,
|
||||
ge=100,
|
||||
description="Maximum characters per result excerpt (values >30000 not guaranteed)",
|
||||
)
|
||||
source_policy: Optional[Dict[str, Any]] = Field(
|
||||
default=None, description="Optional source policy configuration"
|
||||
)
|
||||
|
||||
|
||||
class ParallelSearchTool(BaseTool):
|
||||
name: str = "Parallel Web Search Tool"
|
||||
description: str = (
|
||||
"Search the web using Parallel's Search API (v1beta). Returns ranked results with "
|
||||
"compressed excerpts optimized for LLMs."
|
||||
)
|
||||
args_schema: Type[BaseModel] = ParallelSearchInput
|
||||
|
||||
env_vars: List[EnvVar] = [
|
||||
EnvVar(
|
||||
name="PARALLEL_API_KEY",
|
||||
description="API key for Parallel",
|
||||
required=True,
|
||||
),
|
||||
]
|
||||
package_dependencies: List[str] = ["requests"]
|
||||
|
||||
search_url: str = "https://api.parallel.ai/v1beta/search"
|
||||
|
||||
def _run(
|
||||
self,
|
||||
objective: Optional[str] = None,
|
||||
search_queries: Optional[List[str]] = None,
|
||||
processor: str = "base",
|
||||
max_results: int = 10,
|
||||
max_chars_per_result: int = 6000,
|
||||
source_policy: Optional[Dict[str, Any]] = None,
|
||||
**_: Any,
|
||||
) -> str:
|
||||
api_key = os.environ.get("PARALLEL_API_KEY")
|
||||
if not api_key:
|
||||
return "Error: PARALLEL_API_KEY environment variable is required"
|
||||
|
||||
if not objective and not search_queries:
|
||||
return "Error: Provide at least one of 'objective' or 'search_queries'"
|
||||
|
||||
headers = {
|
||||
"x-api-key": api_key,
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
try:
|
||||
payload: Dict[str, Any] = {
|
||||
"processor": processor,
|
||||
"max_results": max_results,
|
||||
"max_chars_per_result": max_chars_per_result,
|
||||
}
|
||||
if objective is not None:
|
||||
payload["objective"] = objective
|
||||
if search_queries is not None:
|
||||
payload["search_queries"] = search_queries
|
||||
if source_policy is not None:
|
||||
payload["source_policy"] = source_policy
|
||||
|
||||
request_timeout = 90 if processor == "pro" else 30
|
||||
resp = requests.post(self.search_url, json=payload, headers=headers, timeout=request_timeout)
|
||||
if resp.status_code >= 300:
|
||||
return f"Parallel Search API error: {resp.status_code} {resp.text[:200]}"
|
||||
data = resp.json()
|
||||
return self._format_output(data)
|
||||
except requests.Timeout:
|
||||
return "Parallel Search API timeout. Please try again later."
|
||||
except Exception as exc: # noqa: BLE001
|
||||
return f"Unexpected error calling Parallel Search API: {exc}"
|
||||
|
||||
def _format_output(self, result: Dict[str, Any]) -> str:
|
||||
# Return the full JSON payload (search_id + results) as a compact JSON string
|
||||
try:
|
||||
import json
|
||||
|
||||
return json.dumps(result or {}, ensure_ascii=False)
|
||||
except Exception:
|
||||
return str(result or {})
|
||||
Reference in New Issue
Block a user