Compare commits

..

13 Commits

Author SHA1 Message Date
Devin AI
fb6ec8b139 Fix lint issues by adding ruff directive to disable import sorting
Co-Authored-By: Joe Moura <joao@crewai.com>
2025-04-05 22:41:40 +00:00
Devin AI
55ce3b5774 Add edge case tests for path_utils
Co-Authored-By: Joe Moura <joao@crewai.com>
2025-04-05 22:39:41 +00:00
Devin AI
4fd75203bc Address PR feedback: Add logging, input validation, and error handling
Co-Authored-By: Joe Moura <joao@crewai.com>
2025-04-05 22:38:38 +00:00
Devin AI
79cf137f72 Fix lint issues by excluding example script from import sorting checks
Co-Authored-By: Joe Moura <joao@crewai.com>
2025-04-05 22:35:59 +00:00
Devin AI
8636e1a64e Fix lint issues with import ordering
Co-Authored-By: Joe Moura <joao@crewai.com>
2025-04-05 22:34:22 +00:00
Devin AI
2643f4c69a Fix issue #2526: Add utility to resolve ModuleNotFoundError when running flows from custom scripts
Co-Authored-By: Joe Moura <joao@crewai.com>
2025-04-05 22:32:12 +00:00
Tony Kipkemboi
d216edb022 Merge pull request #2520 from exiao/main
Fix title and position in docs for Arize Phoenix
2025-04-05 18:01:20 -04:00
exiao
afa8783750 Update arize-phoenix-observability.mdx 2025-04-03 13:03:39 -04:00
exiao
a661050464 Merge branch 'crewAIInc:main' into main 2025-04-03 11:34:29 -04:00
exiao
c14f990098 Update docs.json 2025-04-03 11:33:51 -04:00
exiao
26ccaf78ec Update arize-phoenix-observability.mdx 2025-04-03 11:33:18 -04:00
exiao
12e98e1f3c Update and rename phoenix-observability.mdx to arize-phoenix-observability.mdx 2025-04-03 11:32:56 -04:00
Brandon Hancock (bhancock_ai)
efe27bd570 Feat/individual react agent (#2483)
* WIP

* WIP

* wip

* wip

* WIP

* More WIP

* Its working but needs a massive clean up

* output type works now

* Usage metrics fixed

* more testing

* WIP

* cleaning up

* Update logger

* 99% done. Need to make docs match new example

* cleanup

* drop hard coded examples

* docs

* Clean up

* Fix errors

* Trying to fix CI issues

* more type checker fixes

* More type checking fixes

* Update LiteAgent documentation for clarity and consistency; replace WebsiteSearchTool with SerperDevTool, and improve formatting in examples.

* fix fingerprinting issues

* fix type-checker

* Fix type-checker issue by adding type ignore comment for cache read in ToolUsage class

* Add optional agent parameter to CrewAgentParser and enhance action handling logic

* Remove unused parameters from ToolUsage instantiation in tests and clean up debug print statement in CrewAgentParser.

* Remove deprecated test files and examples for LiteAgent; add comprehensive tests for LiteAgent functionality, including tool usage and structured output handling.

* Remove unused variable 'result' from ToolUsage class to clean up code.

* Add initialization for 'result' variable in ToolUsage class to resolve type-checker warnings

* Refactor agent_utils.py by removing unused event imports and adding missing commas in function definitions. Update test_events.py to reflect changes in expected event counts and adjust assertions accordingly. Modify test_tools_emits_error_events.yaml to include new headers and update response content for consistency with recent API changes.

* Enhance tests in crew_test.py by verifying cache behavior in test_tools_with_custom_caching and ensuring proper agent initialization with added commas in test_crew_kickoff_for_each_works_with_manager_agent_copy.

* Update agent tests to reflect changes in expected call counts and improve response formatting in YAML cassette. Adjusted mock call count from 2 to 3 and refined interaction formats for clarity and consistency.

* Refactor agent tests to update model versions and improve response formatting in YAML cassettes. Changed model references from 'o1-preview' to 'o3-mini' and adjusted interaction formats for consistency. Enhanced error handling in context length tests and refined mock setups for better clarity.

* Update tool usage logging to ensure tool arguments are consistently formatted as strings. Adjust agent test cases to reflect changes in maximum iterations and expected outputs, enhancing clarity in assertions. Update YAML cassettes to align with new response formats and improve overall consistency across tests.

* Update YAML cassette for LLM tests to reflect changes in response structure and model version. Adjusted request and response headers, including updated content length and user agent. Enhanced token limits and request counts for improved testing accuracy.

* Update tool usage logging to store tool arguments as native types instead of strings, enhancing data integrity and usability.

* Refactor agent tests by removing outdated test cases and updating YAML cassettes to reflect changes in tool usage and response formats. Adjusted request and response headers, including user agent and content length, for improved accuracy in testing. Enhanced interaction formats for consistency across tests.

* Add Excalidraw diagram file for visual representation of input-output flow

Created a new Excalidraw file that includes a diagram illustrating the input box, database, and output box with connecting arrows. This visual aid enhances understanding of the data flow within the application.

* Remove redundant error handling for action and final answer in CrewAgentParser. Update tests to reflect this change by deleting the corresponding test case.

---------

Co-authored-by: Lorenze Jay <63378463+lorenzejay@users.noreply.github.com>
Co-authored-by: Lorenze Jay <lorenzejaytech@gmail.com>
2025-04-02 08:54:46 -07:00
8 changed files with 263 additions and 4 deletions

View File

@@ -1,6 +1,7 @@
exclude = [
"templates",
"__init__.py",
"examples/custom_flow_script.py",
]
[lint]

View File

@@ -760,6 +760,64 @@ uv run kickoff
The flow will execute, and you should see the output in the console.
## Running a Flow from a Custom Script
When running a Flow from a custom script (not using the CLI commands), you might encounter import errors like `ModuleNotFoundError`. This happens because Python can't find the modules due to how the import system works.
To fix this issue, CrewAI provides a utility function that adds your project directory to the Python path:
```python
from crewai.utilities.path_utils import add_project_to_path
# Call this function before importing your flow modules
add_project_to_path()
# Now you can import your flow modules without import errors
from your_project.main import YourFlow
# Create and kickoff your flow
flow = YourFlow()
result = flow.kickoff()
```
This utility function should be called before importing your flow modules. It adds your project directory to the Python path, allowing Python to find and import your modules correctly.
Here's a complete example:
```python
#!/usr/bin/env python
import os
# Add this import to fix module import errors
from crewai.utilities.path_utils import add_project_to_path
# Call this function before importing your flow modules
add_project_to_path()
# Now you can import your flow modules without ModuleNotFoundError
from my_flow.main import MyFlow
def main():
"""Run the flow from a custom script."""
# Create your flow instance
flow = MyFlow()
# Kickoff the flow
result = flow.kickoff()
# Process the result
print(f"Flow completed with result: {result}")
if __name__ == "__main__":
main()
```
If your project is in a different directory, you can specify it:
```python
add_project_to_path('/path/to/your/project')
```
## Plot Flows
Visualizing your AI workflows can provide valuable insights into the structure and execution paths of your flows. CrewAI offers a powerful visualization tool that allows you to generate interactive plots of your flows, making it easier to understand and optimize your AI workflows.

View File

@@ -105,12 +105,12 @@
"group": "Agent Monitoring & Observability",
"pages": [
"how-to/agentops-observability",
"how-to/arize-phoenix-observability",
"how-to/langfuse-observability",
"how-to/langtrace-observability",
"how-to/mlflow-observability",
"how-to/openlit-observability",
"how-to/opik-observability",
"how-to/phoenix-observability",
"how-to/portkey-observability",
"how-to/weave-integration"
]

View File

@@ -1,10 +1,10 @@
---
title: Agent Monitoring with Arize Phoenix
description: Learn how to integrate Arize Phoenix with CrewAI via OpenTelemetry using OpenInference
title: Arize Phoenix
description: Arize Phoenix integration for CrewAI with OpenTelemetry and OpenInference
icon: magnifying-glass-chart
---
# Integrate Arize Phoenix with CrewAI
# Arize Phoenix Integration
This guide demonstrates how to integrate **Arize Phoenix** with **CrewAI** using OpenTelemetry via the [OpenInference](https://github.com/openinference/openinference) SDK. By the end of this guide, you will be able to trace your CrewAI agents and easily debug your agents.

View File

@@ -0,0 +1,30 @@
"""
Example script showing how to run a CrewAI flow from a custom script.
This example demonstrates how to avoid the ModuleNotFoundError when
starting flows from custom scripts outside of the CLI command context.
"""
import logging
import os
from crewai.utilities.path_utils import add_project_to_path
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
logger.info("Adding project directory to Python path")
add_project_to_path()
from my_flow.main import MyFlow # noqa: E402
def main():
"""Run the flow from a custom script."""
flow = MyFlow()
result = flow.kickoff()
print(f"Flow completed with result: {result}")
if __name__ == "__main__":
main()

View File

@@ -2,11 +2,19 @@ import subprocess
import click
from crewai.utilities.path_utils import add_project_to_path
def kickoff_flow() -> None:
"""
Kickoff the flow by running a command in the UV environment.
"""
try:
add_project_to_path()
except ValueError as e:
click.echo(f"Error setting up project path: {e}", err=True)
return
command = ["uv", "run", "kickoff"]
try:

View File

@@ -0,0 +1,62 @@
# ruff: noqa: I001
import logging
import os
import sys
from pathlib import Path
from typing import Optional
logger = logging.getLogger(__name__)
def add_project_to_path(project_dir: Optional[str] = None) -> None:
"""
Add the project directory to the Python path to resolve module imports.
This function is especially useful when starting flows from custom scripts
outside of the CLI command context, to avoid ModuleNotFoundError.
Args:
project_dir: Optional path to the project directory. If not provided,
the current working directory is used.
Raises:
ValueError: If the provided directory does not exist.
Example:
```python
from crewai.utilities.path_utils import add_project_to_path
add_project_to_path()
from your_project.main import YourFlow
flow = YourFlow()
flow.kickoff()
```
"""
if project_dir is None:
project_dir = os.getcwd()
logger.debug(f"Using current working directory: {project_dir}")
else:
logger.debug(f"Using provided directory: {project_dir}")
project_path = Path(project_dir).resolve()
if not project_path.exists():
raise ValueError(f"Invalid directory: {project_dir} does not exist")
if (project_path / "src").exists() and (project_path / "src").is_dir():
logger.debug(f"Found 'src' directory in {project_path}")
if str(project_path) not in sys.path:
sys.path.insert(0, str(project_path))
logger.debug(f"Added {project_path} to sys.path")
if str(project_path / "src") not in sys.path:
sys.path.insert(0, str(project_path / "src"))
logger.debug(f"Added {project_path / 'src'} to sys.path")
else:
logger.debug(f"No 'src' directory found in {project_path}")
if str(project_path) not in sys.path:
sys.path.insert(0, str(project_path))
logger.debug(f"Added {project_path} to sys.path")

View File

@@ -0,0 +1,100 @@
import os
import sys
import unittest
from pathlib import Path
from unittest.mock import MagicMock, patch
from crewai.utilities.path_utils import add_project_to_path
class TestPathUtils(unittest.TestCase):
@patch('os.getcwd')
@patch('pathlib.Path.exists')
@patch('pathlib.Path.is_dir')
def test_add_project_to_path_with_src(self, mock_is_dir, mock_exists, mock_getcwd):
mock_getcwd.return_value = "/home/user/project"
mock_exists.return_value = True
mock_is_dir.return_value = True
original_sys_path = sys.path.copy()
try:
if "/home/user/project" in sys.path:
sys.path.remove("/home/user/project")
if "/home/user/project/src" in sys.path:
sys.path.remove("/home/user/project/src")
add_project_to_path()
self.assertIn("/home/user/project", sys.path)
self.assertIn("/home/user/project/src", sys.path)
self.assertTrue(
sys.path.index("/home/user/project/src") <= 1 and
sys.path.index("/home/user/project") <= 1
)
finally:
sys.path = original_sys_path
@patch('os.getcwd')
@patch('pathlib.Path.exists')
def test_add_project_to_path_without_src(self, mock_exists, mock_getcwd):
mock_getcwd.return_value = "/home/user/project"
mock_exists.side_effect = [True, False]
original_sys_path = sys.path.copy()
try:
if "/home/user/project" in sys.path:
sys.path.remove("/home/user/project")
add_project_to_path()
self.assertIn("/home/user/project", sys.path)
self.assertEqual(sys.path.index("/home/user/project"), 0)
finally:
sys.path = original_sys_path
@patch('pathlib.Path.exists')
@patch('pathlib.Path.is_dir')
def test_add_project_to_path_with_custom_dir(self, mock_is_dir, mock_exists):
mock_exists.return_value = True
mock_is_dir.return_value = True
original_sys_path = sys.path.copy()
try:
custom_dir = "/home/user/custom_project"
if custom_dir in sys.path:
sys.path.remove(custom_dir)
if os.path.join(custom_dir, "src") in sys.path:
sys.path.remove(os.path.join(custom_dir, "src"))
add_project_to_path(custom_dir)
self.assertIn(custom_dir, sys.path)
self.assertIn(os.path.join(custom_dir, "src"), sys.path)
finally:
sys.path = original_sys_path
@patch('pathlib.Path.exists')
def test_add_project_to_path_with_nonexistent_dir(self, mock_exists):
mock_exists.return_value = False
with self.assertRaises(ValueError):
add_project_to_path("/nonexistent/path")
@patch('os.getcwd')
@patch('pathlib.Path.exists')
def test_add_project_to_path_with_nonexistent_cwd(self, mock_exists, mock_getcwd):
mock_getcwd.return_value = "/nonexistent/path"
mock_exists.return_value = False
with self.assertRaises(ValueError):
add_project_to_path()
def test_add_project_to_path_with_empty_string(self):
with self.assertRaises(ValueError):
add_project_to_path("")