Skip to content
This repository was archived by the owner on Nov 10, 2025. It is now read-only.

Commit 78317b9

Browse files
authored
feat: attempt to make embedchain optional (#450)
* fix: attempt to make embedchain optional * fix: drop pydantic_settings dependency * fix: ensure the package is importable without any extra dependency After making embedchain option many packages were unstalled which caused errors in some tools due to failing import directives
1 parent 1397b1f commit 78317b9

File tree

23 files changed

+3692
-3548
lines changed

23 files changed

+3692
-3548
lines changed

crewai_tools/adapters/embedchain_adapter.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
11
from typing import Any
22

3-
from embedchain import App
4-
53
from crewai_tools.tools.rag.rag_tool import Adapter
64

5+
try:
6+
from embedchain import App
7+
EMBEDCHAIN_AVAILABLE = True
8+
except ImportError:
9+
EMBEDCHAIN_AVAILABLE = False
10+
711

812
class EmbedchainAdapter(Adapter):
9-
embedchain_app: App
13+
embedchain_app: Any # Will be App when embedchain is available
1014
summarize: bool = False
1115

16+
def __init__(self, **data):
17+
if not EMBEDCHAIN_AVAILABLE:
18+
raise ImportError("embedchain is not installed. Please install it with `pip install crewai-tools[embedchain]`")
19+
super().__init__(**data)
20+
1221
def query(self, question: str) -> str:
1322
result, sources = self.embedchain_app.query(
1423
question, citations=True, dry_run=(not self.summarize)

crewai_tools/adapters/pdf_embedchain_adapter.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,24 @@
11
from typing import Any, Optional
22

3-
from embedchain import App
4-
53
from crewai_tools.tools.rag.rag_tool import Adapter
64

5+
try:
6+
from embedchain import App
7+
EMBEDCHAIN_AVAILABLE = True
8+
except ImportError:
9+
EMBEDCHAIN_AVAILABLE = False
10+
711

812
class PDFEmbedchainAdapter(Adapter):
9-
embedchain_app: App
13+
embedchain_app: Any # Will be App when embedchain is available
1014
summarize: bool = False
1115
src: Optional[str] = None
1216

17+
def __init__(self, **data):
18+
if not EMBEDCHAIN_AVAILABLE:
19+
raise ImportError("embedchain is not installed. Please install it with `pip install crewai-tools[embedchain]`")
20+
super().__init__(**data)
21+
1322
def query(self, question: str) -> str:
1423
where = (
1524
{"app_id": self.embedchain_app.config.id, "source": self.src}

crewai_tools/tools/brightdata_tool/brightdata_dataset.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,19 @@
55
import aiohttp
66
from crewai.tools import BaseTool
77
from pydantic import BaseModel, Field
8-
from pydantic_settings import BaseSettings
98

10-
class BrightDataConfig(BaseSettings):
9+
class BrightDataConfig(BaseModel):
1110
API_URL: str = "https://api.brightdata.com"
1211
DEFAULT_TIMEOUT: int = 600
1312
DEFAULT_POLLING_INTERVAL: int = 1
14-
15-
class Config:
16-
env_prefix = "BRIGHTDATA_"
13+
14+
@classmethod
15+
def from_env(cls):
16+
return cls(
17+
API_URL=os.environ.get("BRIGHTDATA_API_URL", "https://api.brightdata.com"),
18+
DEFAULT_TIMEOUT=int(os.environ.get("BRIGHTDATA_DEFAULT_TIMEOUT", "600")),
19+
DEFAULT_POLLING_INTERVAL=int(os.environ.get("BRIGHTDATA_DEFAULT_POLLING_INTERVAL", "1"))
20+
)
1721
class BrightDataDatasetToolException(Exception):
1822
"""Exception raised for custom error in the application."""
1923

@@ -48,10 +52,10 @@ class BrightDataDatasetToolSchema(BaseModel):
4852
default=None, description="Additional params if any"
4953
)
5054

51-
config = BrightDataConfig()
55+
config = BrightDataConfig.from_env()
5256

53-
BRIGHTDATA_API_URL = config.API_URL
54-
timeout = config.DEFAULT_TIMEOUT
57+
BRIGHTDATA_API_URL = config.API_URL
58+
timeout = config.DEFAULT_TIMEOUT
5559

5660
datasets = [
5761
{
@@ -532,7 +536,7 @@ def _run(self, url: str = None, dataset_type: str = None, format: str = None, zi
532536
url = url or self.url
533537
zipcode = zipcode or self.zipcode
534538
additional_params = additional_params or self.additional_params
535-
539+
536540
if not dataset_type:
537541
raise ValueError("dataset_type is required either in constructor or method call")
538542
if not url:

crewai_tools/tools/brightdata_tool/brightdata_serp.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@
55
import requests
66
from crewai.tools import BaseTool
77
from pydantic import BaseModel, Field
8-
from pydantic_settings import BaseSettings
98

10-
class BrightDataConfig(BaseSettings):
11-
API_URL: str = "https://api.brightdata.com/request"
12-
class Config:
13-
env_prefix = "BRIGHTDATA_"
9+
class BrightDataConfig(BaseModel):
10+
API_URL: str = "https://api.brightdata.com/request"
11+
12+
@classmethod
13+
def from_env(cls):
14+
return cls(
15+
API_URL=os.environ.get("BRIGHTDATA_API_URL", "https://api.brightdata.com/request")
16+
)
1417

1518
class BrightDataSearchToolSchema(BaseModel):
1619
"""
@@ -73,7 +76,7 @@ class BrightDataSearchTool(BaseTool):
7376
name: str = "Bright Data SERP Search"
7477
description: str = "Tool to perform web search using Bright Data SERP API."
7578
args_schema: Type[BaseModel] = BrightDataSearchToolSchema
76-
_config = BrightDataConfig()
79+
_config = BrightDataConfig.from_env()
7780
base_url: str = ""
7881
api_key: str = ""
7982
zone: str = ""
@@ -95,7 +98,7 @@ def __init__(self, query: str = None, search_engine: str = "google", country: st
9598
self.search_type = search_type
9699
self.device_type = device_type
97100
self.parse_results = parse_results
98-
101+
99102
self.api_key = os.getenv("BRIGHT_DATA_API_KEY")
100103
self.zone = os.getenv("BRIGHT_DATA_ZONE")
101104
if not self.api_key:
@@ -136,7 +139,7 @@ def _run(self, query: str = None, search_engine: str = None, country: str = None
136139
device_type = device_type or self.device_type
137140
parse_results = parse_results if parse_results is not None else self.parse_results
138141
results_count = kwargs.get("results_count", "10")
139-
142+
140143
# Validate required parameters
141144
if not query:
142145
raise ValueError("query is required either in constructor or method call")

crewai_tools/tools/brightdata_tool/brightdata_unlocker.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@
44
import requests
55
from crewai.tools import BaseTool
66
from pydantic import BaseModel, Field
7-
from pydantic_settings import BaseSettings
87

9-
class BrightDataConfig(BaseSettings):
10-
API_URL: str = "https://api.brightdata.com/request"
11-
class Config:
12-
env_prefix = "BRIGHTDATA_"
8+
class BrightDataConfig(BaseModel):
9+
API_URL: str = "https://api.brightdata.com/request"
10+
11+
@classmethod
12+
def from_env(cls):
13+
return cls(
14+
API_URL=os.environ.get("BRIGHTDATA_API_URL", "https://api.brightdata.com/request")
15+
)
1316

1417
class BrightDataUnlockerToolSchema(BaseModel):
1518
"""
@@ -57,7 +60,7 @@ class BrightDataWebUnlockerTool(BaseTool):
5760
name: str = "Bright Data Web Unlocker Scraping"
5861
description: str = "Tool to perform web scraping using Bright Data Web Unlocker"
5962
args_schema: Type[BaseModel] = BrightDataUnlockerToolSchema
60-
_config = BrightDataConfig()
63+
_config = BrightDataConfig.from_env()
6164
base_url: str = ""
6265
api_key: str = ""
6366
zone: str = ""
@@ -71,7 +74,7 @@ def __init__(self, url: str = None, format: str = "raw", data_format: str = "mar
7174
self.url = url
7275
self.format = format
7376
self.data_format = data_format
74-
77+
7578
self.api_key = os.getenv("BRIGHT_DATA_API_KEY")
7679
self.zone = os.getenv("BRIGHT_DATA_ZONE")
7780
if not self.api_key:
@@ -83,10 +86,10 @@ def _run(self, url: str = None, format: str = None, data_format: str = None, **k
8386
url = url or self.url
8487
format = format or self.format
8588
data_format = data_format or self.data_format
86-
89+
8790
if not url:
8891
raise ValueError("url is required either in constructor or method call")
89-
92+
9093
payload = {
9194
"url": url,
9295
"zone": self.zone,

crewai_tools/tools/code_docs_search_tool/code_docs_search_tool.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
from typing import Any, Optional, Type
22

3-
from embedchain.models.data_type import DataType
3+
try:
4+
from embedchain.models.data_type import DataType
5+
EMBEDCHAIN_AVAILABLE = True
6+
except ImportError:
7+
EMBEDCHAIN_AVAILABLE = False
8+
49
from pydantic import BaseModel, Field
510

611
from ..rag.rag_tool import RagTool
@@ -37,6 +42,8 @@ def __init__(self, docs_url: Optional[str] = None, **kwargs):
3742
self._generate_description()
3843

3944
def add(self, docs_url: str) -> None:
45+
if not EMBEDCHAIN_AVAILABLE:
46+
raise ImportError("embedchain is not installed. Please install it with `pip install crewai-tools[embedchain]`")
4047
super().add(docs_url, data_type=DataType.DOCS_SITE)
4148

4249
def _run(

crewai_tools/tools/csv_search_tool/csv_search_tool.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
from typing import Optional, Type
22

3-
from embedchain.models.data_type import DataType
3+
try:
4+
from embedchain.models.data_type import DataType
5+
EMBEDCHAIN_AVAILABLE = True
6+
except ImportError:
7+
EMBEDCHAIN_AVAILABLE = False
8+
49
from pydantic import BaseModel, Field
510

611
from ..rag.rag_tool import RagTool
@@ -37,6 +42,8 @@ def __init__(self, csv: Optional[str] = None, **kwargs):
3742
self._generate_description()
3843

3944
def add(self, csv: str) -> None:
45+
if not EMBEDCHAIN_AVAILABLE:
46+
raise ImportError("embedchain is not installed. Please install it with `pip install crewai-tools[embedchain]`")
4047
super().add(csv, data_type=DataType.CSV)
4148

4249
def _run(

crewai_tools/tools/directory_search_tool/directory_search_tool.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
from typing import Optional, Type
22

3-
from embedchain.loaders.directory_loader import DirectoryLoader
3+
try:
4+
from embedchain.loaders.directory_loader import DirectoryLoader
5+
EMBEDCHAIN_AVAILABLE = True
6+
except ImportError:
7+
EMBEDCHAIN_AVAILABLE = False
8+
49
from pydantic import BaseModel, Field
510

611
from ..rag.rag_tool import RagTool
@@ -29,6 +34,8 @@ class DirectorySearchTool(RagTool):
2934
args_schema: Type[BaseModel] = DirectorySearchToolSchema
3035

3136
def __init__(self, directory: Optional[str] = None, **kwargs):
37+
if not EMBEDCHAIN_AVAILABLE:
38+
raise ImportError("embedchain is not installed. Please install it with `pip install crewai-tools[embedchain]`")
3239
super().__init__(**kwargs)
3340
if directory is not None:
3441
self.add(directory)

crewai_tools/tools/docx_search_tool/docx_search_tool.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
from typing import Any, Optional, Type
22

3-
from embedchain.models.data_type import DataType
3+
try:
4+
from embedchain.models.data_type import DataType
5+
EMBEDCHAIN_AVAILABLE = True
6+
except ImportError:
7+
EMBEDCHAIN_AVAILABLE = False
8+
49
from pydantic import BaseModel, Field
510

611
from ..rag.rag_tool import RagTool
@@ -43,6 +48,8 @@ def __init__(self, docx: Optional[str] = None, **kwargs):
4348
self._generate_description()
4449

4550
def add(self, docx: str) -> None:
51+
if not EMBEDCHAIN_AVAILABLE:
52+
raise ImportError("embedchain is not installed. Please install it with `pip install crewai-tools[embedchain]`")
4653
super().add(docx, data_type=DataType.DOCX)
4754

4855
def _run(

crewai_tools/tools/github_search_tool/github_search_tool.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1-
from typing import List, Optional, Type
1+
from typing import List, Optional, Type, Any
2+
3+
try:
4+
from embedchain.loaders.github import GithubLoader
5+
EMBEDCHAIN_AVAILABLE = True
6+
except ImportError:
7+
EMBEDCHAIN_AVAILABLE = False
28

3-
from embedchain.loaders.github import GithubLoader
49
from pydantic import BaseModel, Field, PrivateAttr
510

611
from ..rag.rag_tool import RagTool
@@ -37,14 +42,16 @@ class GithubSearchTool(RagTool):
3742
default_factory=lambda: ["code", "repo", "pr", "issue"],
3843
description="Content types you want to be included search, options: [code, repo, pr, issue]",
3944
)
40-
_loader: GithubLoader | None = PrivateAttr(default=None)
45+
_loader: Any | None = PrivateAttr(default=None)
4146

4247
def __init__(
4348
self,
4449
github_repo: Optional[str] = None,
4550
content_types: Optional[List[str]] = None,
4651
**kwargs,
4752
):
53+
if not EMBEDCHAIN_AVAILABLE:
54+
raise ImportError("embedchain is not installed. Please install it with `pip install crewai-tools[embedchain]`")
4855
super().__init__(**kwargs)
4956
self._loader = GithubLoader(config={"token": self.gh_token})
5057

0 commit comments

Comments
 (0)