Compare commits

..

12 Commits

Author SHA1 Message Date
lorenzejay
4789484523 Merge branch 'main' of github.com:crewAIInc/crewAI into lorenze/agent-query-for-knowledge 2025-05-07 11:04:16 -07:00
lorenzejay
b67f2a2c9b test: add unit test for knowledge search query and VCR cassette
This commit introduces a new test, `test_get_knowledge_search_query`, to verify that the `_get_knowledge_search_query` method in the Agent class correctly interacts with the LLM using the appropriate prompts. Additionally, a VCR cassette is added to record the interactions with the OpenAI API for this test, ensuring consistent and reliable test results.
2025-05-07 09:59:51 -07:00
lorenzejay
a30246503d Merge branch 'main' of github.com:crewAIInc/crewAI into lorenze/agent-query-for-knowledge 2025-05-07 07:53:30 -07:00
lorenzejay
55ed9b366f refactor: improve error handling in knowledge query processing
This commit refactors the knowledge query handling in the Agent class by changing the order of checks for LLM compatibility. It now logs a warning and emits a failure event if the LLM is not an instance of BaseLLM before attempting to call the LLM. Additionally, the task_prompt attribute has been removed from the KnowledgeQueryFailedEvent, simplifying the event structure.
2025-05-06 20:42:23 -07:00
lorenzejay
b9af25f434 docs for transparancy 2025-05-06 20:31:50 -07:00
lorenzejay
1c2238066f refactor: rename knowledge query events and enhance retrieval handling
This commit renames the KnowledgeQueryGeneratedEvent to KnowledgeQueryStartedEvent to better reflect its purpose. It also updates the event handling in the EventListener and ConsoleFormatter classes to accommodate the new event structure. Additionally, the retrieval knowledge is now included in the KnowledgeRetrievalCompletedEvent, improving the overall knowledge retrieval process.
2025-05-06 20:26:19 -07:00
lorenzejay
bce6865b43 fix broken tests 2025-05-06 19:39:52 -07:00
lorenzejay
bd61c52371 Merge branch 'main' of github.com:crewAIInc/crewAI into lorenze/agent-query-for-knowledge 2025-05-06 15:32:26 -07:00
lorenzejay
eb9ae78158 fix: add missing newline at end of en.json file 2025-05-05 21:40:19 -07:00
lorenzejay
5fa8cdbb48 Merge branch 'main' of github.com:crewAIInc/crewAI into lorenze/agent-query-for-knowledge 2025-05-05 21:38:31 -07:00
lorenzejay
a9decb54c8 refactor: update knowledge query handling in Agent
This commit refines the knowledge query processing in the Agent class by renaming variables for clarity and optimizing the query rewriting logic. The system prompt has been updated in the translation file to enhance clarity and context for the query rewriting process. These changes aim to improve the overall readability and maintainability of the code.
2025-05-05 21:37:48 -07:00
lorenzejay
e54a470493 feat: implement knowledge retrieval events in Agent
This commit introduces a series of knowledge retrieval events in the Agent class, enhancing its ability to handle knowledge queries. New events include KnowledgeRetrievalStartedEvent, KnowledgeRetrievalCompletedEvent, KnowledgeQueryGeneratedEvent, KnowledgeQueryFailedEvent, and KnowledgeSearchQueryCompletedEvent. The Agent now emits these events during knowledge retrieval processes, allowing for better tracking and handling of knowledge queries. Additionally, the console formatter has been updated to handle these new events, providing visual feedback during knowledge retrieval operations.
2025-04-29 22:09:46 -07:00
12 changed files with 45 additions and 270 deletions

38
.github/security.md vendored
View File

@@ -1,27 +1,19 @@
## CrewAI Security Vulnerability Reporting Policy
CrewAI takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organization.
If you believe you have found a security vulnerability in any CrewAI product or service, please report it to us as described below.
CrewAI prioritizes the security of our software products, services, and GitHub repositories. To promptly address vulnerabilities, follow these steps for reporting security issues:
## Reporting a Vulnerability
Please do not report security vulnerabilities through public GitHub issues.
To report a vulnerability, please email us at security@crewai.com.
Please include the requested information listed below so that we can triage your report more quickly
### Reporting Process
Do **not** report vulnerabilities via public GitHub issues.
- Type of issue (e.g. SQL injection, cross-site scripting, etc.)
- Full paths of source file(s) related to the manifestation of the issue
- The location of the affected source code (tag/branch/commit or direct URL)
- Any special configuration required to reproduce the issue
- Step-by-step instructions to reproduce the issue (please include screenshots if needed)
- Proof-of-concept or exploit code (if possible)
- Impact of the issue, including how an attacker might exploit the issue
Email all vulnerability reports directly to:
**security@crewai.com**
Once we have received your report, we will respond to you at the email address you provide. If the issue is confirmed, we will release a patch as soon as possible depending on the complexity of the issue.
### Required Information
To help us quickly validate and remediate the issue, your report must include:
- **Vulnerability Type:** Clearly state the vulnerability type (e.g., SQL injection, XSS, privilege escalation).
- **Affected Source Code:** Provide full file paths and direct URLs (branch, tag, or commit).
- **Reproduction Steps:** Include detailed, step-by-step instructions. Screenshots are recommended.
- **Special Configuration:** Document any special settings or configurations required to reproduce.
- **Proof-of-Concept (PoC):** Provide exploit or PoC code (if available).
- **Impact Assessment:** Clearly explain the severity and potential exploitation scenarios.
### Our Response
- We will acknowledge receipt of your report promptly via your provided email.
- Confirmed vulnerabilities will receive priority remediation based on severity.
- Patches will be released as swiftly as possible following verification.
### Reward Notice
Currently, we do not offer a bug bounty program. Rewards, if issued, are discretionary.
At this time, we are not offering a bug bounty program. Any rewards will be at our discretion.

View File

@@ -169,55 +169,19 @@ In this section, you'll find detailed examples that help you select, configure,
```
</Accordion>
<Accordion title="Google (Gemini API)">
Set your API key in your `.env` file. If you need a key, or need to find an
existing key, check [AI Studio](https://aistudio.google.com/apikey).
<Accordion title="Google">
Set the following environment variables in your `.env` file:
```toml .env
```toml Code
# Option 1: Gemini accessed with an API key.
# https://ai.google.dev/gemini-api/docs/api-key
GEMINI_API_KEY=<your-api-key>
# Option 2: Vertex AI IAM credentials for Gemini, Anthropic, and Model Garden.
# https://cloud.google.com/vertex-ai/generative-ai/docs/overview
```
Example usage in your CrewAI project:
```python Code
from crewai import LLM
llm = LLM(
model="gemini/gemini-2.0-flash",
temperature=0.7,
)
```
### Gemini models
Google offers a range of powerful models optimized for different use cases.
| Model | Context Window | Best For |
|--------------------------------|----------------|-------------------------------------------------------------------|
| gemini-2.5-flash-preview-04-17 | 1M tokens | Adaptive thinking, cost efficiency |
| gemini-2.5-pro-preview-05-06 | 1M tokens | Enhanced thinking and reasoning, multimodal understanding, advanced coding, and more |
| gemini-2.0-flash | 1M tokens | Next generation features, speed, thinking, and realtime streaming |
| gemini-2.0-flash-lite | 1M tokens | Cost efficiency and low latency |
| gemini-1.5-flash | 1M tokens | Balanced multimodal model, good for most tasks |
| gemini-1.5-flash-8B | 1M tokens | Fastest, most cost-efficient, good for high-frequency tasks |
| gemini-1.5-pro | 2M tokens | Best performing, wide variety of reasoning tasks including logical reasoning, coding, and creative collaboration |
The full list of models is available in the [Gemini model docs](https://ai.google.dev/gemini-api/docs/models).
### Gemma
The Gemini API also allows you to use your API key to access [Gemma models](https://ai.google.dev/gemma/docs) hosted on Google infrastructure.
| Model | Context Window |
|----------------|----------------|
| gemma-3-1b-it | 32k tokens |
| gemma-3-4b-it | 32k tokens |
| gemma-3-12b-it | 32k tokens |
| gemma-3-27b-it | 128k tokens |
</Accordion>
<Accordion title="Google (Vertex AI)">
Get credentials from your Google Cloud Console and save it to a JSON file, then load it with the following code:
Get credentials from your Google Cloud Console and save it to a JSON file with the following code:
```python Code
import json
@@ -241,18 +205,14 @@ In this section, you'll find detailed examples that help you select, configure,
vertex_credentials=vertex_credentials_json
)
```
Google offers a range of powerful models optimized for different use cases:
| Model | Context Window | Best For |
|--------------------------------|----------------|-------------------------------------------------------------------|
| gemini-2.5-flash-preview-04-17 | 1M tokens | Adaptive thinking, cost efficiency |
| gemini-2.5-pro-preview-05-06 | 1M tokens | Enhanced thinking and reasoning, multimodal understanding, advanced coding, and more |
| gemini-2.0-flash | 1M tokens | Next generation features, speed, thinking, and realtime streaming |
| gemini-2.0-flash-lite | 1M tokens | Cost efficiency and low latency |
| gemini-1.5-flash | 1M tokens | Balanced multimodal model, good for most tasks |
| gemini-1.5-flash-8B | 1M tokens | Fastest, most cost-efficient, good for high-frequency tasks |
| gemini-1.5-pro | 2M tokens | Best performing, wide variety of reasoning tasks including logical reasoning, coding, and creative collaboration |
| Model | Context Window | Best For |
|-----------------------|----------------|------------------------------------------------------------------|
| gemini-2.0-flash-exp | 1M tokens | Higher quality at faster speed, multimodal model, good for most tasks |
| gemini-1.5-flash | 1M tokens | Balanced multimodal model, good for most tasks |
| gemini-1.5-flash-8B | 1M tokens | Fastest, most cost-efficient, good for high-frequency tasks |
| gemini-1.5-pro | 2M tokens | Best performing, wide variety of reasoning tasks including logical reasoning, coding, and creative collaboration |
</Accordion>
<Accordion title="Azure">

View File

@@ -68,13 +68,7 @@ We'll create a CrewAI application where two agents collaborate to research and w
```python
from crewai import Agent, Crew, Process, Task
from crewai_tools import SerperDevTool
from openinference.instrumentation.crewai import CrewAIInstrumentor
from phoenix.otel import register
# setup monitoring for your crew
tracer_provider = register(
endpoint="http://localhost:6006/v1/traces")
CrewAIInstrumentor().instrument(skip_dep_check=True, tracer_provider=tracer_provider)
search_tool = SerperDevTool()
# Define your agents with roles and goals

View File

@@ -1,6 +1,6 @@
[project]
name = "crewai"
version = "0.119.0"
version = "0.118.0"
description = "Cutting-edge framework for orchestrating role-playing, autonomous AI agents. By fostering collaborative intelligence, CrewAI empowers agents to work together seamlessly, tackling complex tasks."
readme = "README.md"
requires-python = ">=3.10,<3.13"
@@ -45,7 +45,7 @@ Documentation = "https://docs.crewai.com"
Repository = "https://github.com/crewAIInc/crewAI"
[project.optional-dependencies]
tools = ["crewai-tools~=0.44.0"]
tools = ["crewai-tools~=0.42.2"]
embeddings = [
"tiktoken~=0.7.0"
]

View File

@@ -17,7 +17,7 @@ warnings.filterwarnings(
category=UserWarning,
module="pydantic.main",
)
__version__ = "0.119.0"
__version__ = "0.118.0"
__all__ = [
"Agent",
"Crew",

View File

@@ -13,7 +13,7 @@ ENV_VARS = {
],
"gemini": [
{
"prompt": "Enter your GEMINI API key from https://ai.dev/apikey (press Enter to skip)",
"prompt": "Enter your GEMINI API key (press Enter to skip)",
"key_name": "GEMINI_API_KEY",
}
],

View File

@@ -5,7 +5,7 @@ description = "{{name}} using crewAI"
authors = [{ name = "Your Name", email = "you@example.com" }]
requires-python = ">=3.10,<3.13"
dependencies = [
"crewai[tools]>=0.119.0,<1.0.0"
"crewai[tools]>=0.118.0,<1.0.0"
]
[project.scripts]

View File

@@ -5,7 +5,7 @@ description = "{{name}} using crewAI"
authors = [{ name = "Your Name", email = "you@example.com" }]
requires-python = ">=3.10,<3.13"
dependencies = [
"crewai[tools]>=0.119.0,<1.0.0",
"crewai[tools]>=0.118.0,<1.0.0",
]
[project.scripts]

View File

@@ -5,7 +5,7 @@ description = "Power up your crews with {{folder_name}}"
readme = "README.md"
requires-python = ">=3.10,<3.13"
dependencies = [
"crewai[tools]>=0.119.0"
"crewai[tools]>=0.118.0"
]
[tool.crewai]

View File

@@ -246,9 +246,6 @@ class AccumulatedToolArgs(BaseModel):
class LLM(BaseLLM):
ANTHROPIC_PREFIXES = ("anthropic/", "claude-", "claude/")
GEMINI_IDENTIFIERS = ("gemini", "gemma-")
def __init__(
self,
model: str,
@@ -322,55 +319,8 @@ class LLM(BaseLLM):
Returns:
bool: True if the model is from Anthropic, False otherwise.
"""
if not isinstance(model, str):
return False
return any(prefix in model.lower() for prefix in self.ANTHROPIC_PREFIXES)
def _is_gemini_model(self, model: str) -> bool:
"""Determine if the model is from Google Gemini provider.
Args:
model: The model identifier string.
Returns:
bool: True if the model is from Gemini, False otherwise.
"""
if not isinstance(model, str):
return False
return any(identifier in model.lower() for identifier in self.GEMINI_IDENTIFIERS)
def _normalize_gemini_model(self, model: str) -> str:
"""Normalize Gemini model name to the format expected by LiteLLM.
Handles formats like "models/gemini-pro" or "gemini-pro" and converts
them to "gemini/gemini-pro" format.
Args:
model: The model identifier string.
Returns:
str: Normalized model name.
Raises:
ValueError: If model is not a string or is empty.
"""
if not isinstance(model, str):
raise ValueError(f"Model must be a string, got {type(model)}")
if not model.strip():
raise ValueError("Model name cannot be empty")
if model.startswith("gemini/"):
return model
if model.startswith("models/"):
model_name = model.split("/", 1)[1]
return f"gemini/{model_name}"
if self._is_gemini_model(model) and "/" not in model:
return f"gemini/{model}"
return model
ANTHROPIC_PREFIXES = ("anthropic/", "claude-", "claude/")
return any(prefix in model.lower() for prefix in ANTHROPIC_PREFIXES)
def _prepare_completion_params(
self,
@@ -393,23 +343,9 @@ class LLM(BaseLLM):
messages = [{"role": "user", "content": messages}]
formatted_messages = self._format_messages_for_provider(messages)
model = self.model
if self._is_gemini_model(model):
try:
model = self._normalize_gemini_model(model)
logging.info(f"Normalized Gemini model name from '{self.model}' to '{model}'")
# --- 2.1) Map GOOGLE_API_KEY to GEMINI_API_KEY if needed
if not os.environ.get("GEMINI_API_KEY") and os.environ.get("GOOGLE_API_KEY"):
os.environ["GEMINI_API_KEY"] = os.environ["GOOGLE_API_KEY"]
logging.info("Mapped GOOGLE_API_KEY to GEMINI_API_KEY for Gemini model")
except ValueError as e:
logging.error(f"Error normalizing Gemini model: {str(e)}")
model = self.model
# --- 3) Prepare the parameters for the completion call
# --- 2) Prepare the parameters for the completion call
params = {
"model": model,
"model": self.model,
"messages": formatted_messages,
"timeout": self.timeout,
"temperature": self.temperature,

View File

@@ -220,37 +220,6 @@ def test_get_custom_llm_provider_gemini():
assert llm._get_custom_llm_provider() == "gemini"
def test_is_gemini_model():
"""Test the _is_gemini_model method with various model names."""
llm = LLM(model="gpt-4") # Model doesn't matter for this test
assert llm._is_gemini_model("gemini-pro") == True
assert llm._is_gemini_model("gemini/gemini-1.5-pro") == True
assert llm._is_gemini_model("models/gemini-pro") == True
assert llm._is_gemini_model("gemma-7b") == True
# Should not identify as Gemini models
assert llm._is_gemini_model("gpt-4") == False
assert llm._is_gemini_model("claude-3") == False
assert llm._is_gemini_model("mistral-7b") == False
def test_normalize_gemini_model():
"""Test the _normalize_gemini_model method with various model formats."""
llm = LLM(model="gpt-4") # Model doesn't matter for this test
assert llm._normalize_gemini_model("gemini/gemini-1.5-pro") == "gemini/gemini-1.5-pro"
assert llm._normalize_gemini_model("models/gemini-pro") == "gemini/gemini-pro"
assert llm._normalize_gemini_model("models/gemini-1.5-flash") == "gemini/gemini-1.5-flash"
assert llm._normalize_gemini_model("gemini-pro") == "gemini/gemini-pro"
assert llm._normalize_gemini_model("gemini-1.5-flash") == "gemini/gemini-1.5-flash"
assert llm._normalize_gemini_model("gpt-4") == "gpt-4"
assert llm._normalize_gemini_model("claude-3") == "claude-3"
def test_get_custom_llm_provider_openai():
llm = LLM(model="gpt-4")
assert llm._get_custom_llm_provider() == None
@@ -305,82 +274,6 @@ def test_gemini_models(model):
assert "Paris" in result
@pytest.mark.vcr(filter_headers=["authorization"], filter_query_parameters=["key"])
@pytest.mark.parametrize(
"model",
[
"models/gemini-pro", # Format from issue #2803
"gemini-pro", # Format without provider prefix
],
)
def test_gemini_model_normalization(model):
"""Test that different Gemini model formats are normalized correctly."""
llm = LLM(model=model)
with patch("litellm.completion") as mock_completion:
# Create mocks for response structure
mock_message = MagicMock()
mock_message.content = "Paris"
mock_choice = MagicMock()
mock_choice.message = mock_message
mock_response = MagicMock()
mock_response.choices = [mock_choice]
# Set up the mocked completion to return the mock response
mock_completion.return_value = mock_response
llm.call("What is the capital of France?")
# Check that the model was normalized correctly in the call to litellm
args, kwargs = mock_completion.call_args
assert kwargs["model"].startswith("gemini/")
assert "gemini-pro" in kwargs["model"]
@pytest.mark.vcr(filter_headers=["authorization"], filter_query_parameters=["key"])
def test_gemini_api_key_mapping():
"""Test that GOOGLE_API_KEY is mapped to GEMINI_API_KEY for Gemini models."""
original_google_api_key = os.environ.get("GOOGLE_API_KEY")
original_gemini_api_key = os.environ.get("GEMINI_API_KEY")
try:
# Set up test environment
test_api_key = "test_google_api_key"
os.environ["GOOGLE_API_KEY"] = test_api_key
if "GEMINI_API_KEY" in os.environ:
del os.environ["GEMINI_API_KEY"]
llm = LLM(model="gemini-pro")
with patch("litellm.completion") as mock_completion:
# Create mocks for response structure
mock_message = MagicMock()
mock_message.content = "Paris"
mock_choice = MagicMock()
mock_choice.message = mock_message
mock_response = MagicMock()
mock_response.choices = [mock_choice]
# Set up the mocked completion to return the mock response
mock_completion.return_value = mock_response
llm.call("What is the capital of France?")
# Check that GEMINI_API_KEY was set from GOOGLE_API_KEY
assert os.environ.get("GEMINI_API_KEY") == test_api_key
finally:
if original_google_api_key is not None:
os.environ["GOOGLE_API_KEY"] = original_google_api_key
else:
os.environ.pop("GOOGLE_API_KEY", None)
if original_gemini_api_key is not None:
os.environ["GEMINI_API_KEY"] = original_gemini_api_key
else:
os.environ.pop("GEMINI_API_KEY", None)
@pytest.mark.vcr(filter_headers=["authorization"], filter_query_parameters=["key"])
@pytest.mark.parametrize(
"model",

10
uv.lock generated
View File

@@ -738,7 +738,7 @@ wheels = [
[[package]]
name = "crewai"
version = "0.119.0"
version = "0.118.0"
source = { editable = "." }
dependencies = [
{ name = "appdirs" },
@@ -828,7 +828,7 @@ requires-dist = [
{ name = "blinker", specifier = ">=1.9.0" },
{ name = "chromadb", specifier = ">=0.5.23" },
{ name = "click", specifier = ">=8.1.7" },
{ name = "crewai-tools", marker = "extra == 'tools'", specifier = "~=0.44.0" },
{ name = "crewai-tools", marker = "extra == 'tools'", specifier = "~=0.42.2" },
{ name = "docling", marker = "extra == 'docling'", specifier = ">=2.12.0" },
{ name = "fastembed", marker = "extra == 'fastembed'", specifier = ">=0.4.1" },
{ name = "instructor", specifier = ">=1.3.3" },
@@ -879,7 +879,7 @@ dev = [
[[package]]
name = "crewai-tools"
version = "0.44.0"
version = "0.42.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "chromadb" },
@@ -894,9 +894,9 @@ dependencies = [
{ name = "pytube" },
{ name = "requests" },
]
sdist = { url = "https://files.pythonhosted.org/packages/b8/1f/2977dc72628c1225bf5788ae22a65e5a53df384d19b197646d2c4760684e/crewai_tools-0.44.0.tar.gz", hash = "sha256:44e0c26079396503a326efdd9ff34bf369d410cbf95c362cc523db65b18f3c3a", size = 892004 }
sdist = { url = "https://files.pythonhosted.org/packages/17/34/9e63e2db53d8f5c30353f271a3240687a48e55204bbd176a057c0b7658c8/crewai_tools-0.42.2.tar.gz", hash = "sha256:69365ffb168cccfea970e09b308905aa5007cfec60024d731ffac1362a0153c0", size = 754967 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ba/80/b91aa837d06edbb472445ea3c92d7619518894fd3049d480e5fffbf0c21b/crewai_tools-0.44.0-py3-none-any.whl", hash = "sha256:119e2365fe66ee16e18a5e8e222994b19f76bafcc8c1bb87f61609c1e39b2463", size = 583462 },
{ url = "https://files.pythonhosted.org/packages/4e/43/0f70b95350084e5cb1e1d74e9acb9e18a89ba675b1d579c787c2662baba7/crewai_tools-0.42.2-py3-none-any.whl", hash = "sha256:13727fb68f0efefd21edeb281be3d66ff2f5a3b5029d4e6adef388b11fd5846a", size = 583933 },
]
[[package]]