From 81d69efcc587f269ca1ee93f56529af80a14d7a3 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Mon, 14 Apr 2025 09:26:05 +0000 Subject: [PATCH] fix: Check for AGENTOPS_API_KEY before using agentops (#2601) Ensures CrewAI checks for the AGENTOPS_API_KEY environment variable after importing the optional agentops package but before using its functionality. If the key is missing, CrewAI proceeds as if agentops is unavailable, preventing NoApiKeyException. Adds a test case to verify this behavior. Co-Authored-By: Joe Moura --- .../events/third_party/agentops_listener.py | 3 +- tests/crew_test.py | 45 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/crewai/utilities/events/third_party/agentops_listener.py b/src/crewai/utilities/events/third_party/agentops_listener.py index 294a820ee..186be5d95 100644 --- a/src/crewai/utilities/events/third_party/agentops_listener.py +++ b/src/crewai/utilities/events/third_party/agentops_listener.py @@ -1,3 +1,4 @@ +import os from typing import Optional from crewai.utilities.events import ( @@ -25,7 +26,7 @@ class AgentOpsListener(BaseEventListener): super().__init__() def setup_listeners(self, crewai_event_bus): - if not AGENTOPS_INSTALLED: + if not AGENTOPS_INSTALLED or not os.getenv("AGENTOPS_API_KEY"): return @crewai_event_bus.on(CrewKickoffStartedEvent) diff --git a/tests/crew_test.py b/tests/crew_test.py index d7e4740cd..ceacfba8c 100644 --- a/tests/crew_test.py +++ b/tests/crew_test.py @@ -39,6 +39,10 @@ from crewai.utilities.events.event_listener import EventListener from crewai.utilities.rpm_controller import RPMController from crewai.utilities.task_output_storage_handler import TaskOutputStorageHandler +import sys +from unittest.mock import Mock, MagicMock + + # Skip streaming tests when running in CI/CD environments skip_streaming_in_ci = pytest.mark.skipif( os.getenv("CI") is not None, reason="Skipping streaming tests in CI/CD environments" @@ -4119,3 +4123,44 @@ def test_crew_kickoff_for_each_works_with_manager_agent_copy(): assert crew_copy.manager_agent.backstory == crew.manager_agent.backstory assert isinstance(crew_copy.manager_agent.agent_executor, CrewAgentExecutor) assert isinstance(crew_copy.manager_agent.cache_handler, CacheHandler) + +@patch.dict(os.environ, {}, clear=True) # Ensure AGENTOPS_API_KEY is not set +@patch("sys.modules") +def test_crew_kickoff_with_agentops_installed_no_key(mock_sys_modules): + """ + Test that crew kickoff does not raise an error if agentops is installed + but the AGENTOPS_API_KEY environment variable is not set. + This simulates the scenario described in issue #2601. + """ + mock_agentops = MagicMock() + mock_sys_modules["agentops"] = mock_agentops + + listener_module_name = "crewai.utilities.events.third_party.agentops_listener" + if listener_module_name in sys.modules: + del sys.modules[listener_module_name] + + import importlib + agentops_listener_module = importlib.import_module(listener_module_name) # noqa: F841 - Used for side effects (registration) + + mock_llm = Mock(spec=LLM) + mock_llm.invoke = Mock(return_value="Task completed.") + mock_llm.tokens_usage = [] # Mock token usage tracking if needed + + test_agent = Agent(role="tester", goal="test", backstory="testing", llm=mock_llm) + test_task = Task(description="test task", expected_output="tested", agent=test_agent) + + # Create the crew + crew = Crew(agents=[test_agent], tasks=[test_task]) + + try: + crew.kickoff() + except Exception as e: + if "agentops" in str(type(e)).lower() or "api key" in str(e).lower(): + pytest.fail(f"Crew kickoff raised an unexpected AgentOps exception: {e}") + + mock_agentops.init.assert_not_called() + + if "agentops" in sys.modules: + del sys.modules["agentops"] + if listener_module_name in sys.modules: + del sys.modules[listener_module_name]