Skip to content

Commit 1773033

Browse files
authored
feat: support api_key fallback to EXA_API_KEY env-var (crewAIInc#341)
1 parent 9a21d05 commit 1773033

File tree

2 files changed

+41
-3
lines changed

2 files changed

+41
-3
lines changed

crewai_tools/tools/exa_tools/exa_search_tool.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from typing import Any, Optional, Type, List
22
from pydantic import BaseModel, Field
3-
from crewai.tools import BaseTool
3+
from crewai.tools import BaseTool, EnvVar
4+
import os
45

56
try:
67
from exa_py import Exa
@@ -36,10 +37,15 @@ class EXASearchTool(BaseTool):
3637
summary: Optional[bool] = False
3738
type: Optional[str] = "auto"
3839
package_dependencies: List[str] = ["exa_py"]
40+
api_key: Optional[str] = Field(
41+
default_factory=lambda: os.getenv("EXA_API_KEY"), description="API key for Exa services", required=False
42+
)
43+
env_vars: List[EnvVar] = [
44+
EnvVar(name="EXA_API_KEY", description="API key for Exa services", required=False),
45+
]
3946

4047
def __init__(
4148
self,
42-
api_key: str,
4349
content: Optional[bool] = False,
4450
summary: Optional[bool] = False,
4551
type: Optional[str] = "auto",
@@ -62,7 +68,7 @@ def __init__(
6268
raise ImportError(
6369
"You are missing the 'exa_py' package. Would you like to install it?"
6470
)
65-
self.client = Exa(api_key=api_key)
71+
self.client = Exa(api_key=self.api_key)
6672
self.content = content
6773
self.summary = summary
6874
self.type = type

tests/tools/exa_search_tool_test.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import os
2+
from unittest.mock import patch
3+
from crewai_tools import EXASearchTool
4+
5+
import pytest
6+
7+
@pytest.fixture
8+
def exa_search_tool():
9+
return EXASearchTool(api_key="test_api_key")
10+
11+
12+
@pytest.fixture(autouse=True)
13+
def mock_exa_api_key():
14+
with patch.dict(os.environ, {"EXA_API_KEY": "test_key_from_env"}):
15+
yield
16+
17+
def test_exa_search_tool_initialization():
18+
with patch("crewai_tools.tools.exa_tools.exa_search_tool.Exa") as mock_exa_class:
19+
api_key = "test_api_key"
20+
tool = EXASearchTool(api_key=api_key)
21+
22+
assert tool.api_key == api_key
23+
assert tool.content is False
24+
assert tool.summary is False
25+
assert tool.type == "auto"
26+
mock_exa_class.assert_called_once_with(api_key=api_key)
27+
28+
29+
def test_exa_search_tool_initialization_with_env(mock_exa_api_key):
30+
with patch("crewai_tools.tools.exa_tools.exa_search_tool.Exa") as mock_exa_class:
31+
EXASearchTool()
32+
mock_exa_class.assert_called_once_with(api_key="test_key_from_env")

0 commit comments

Comments
 (0)