From a04c0889ca98758bdccb5a5a40a1379263263a8e Mon Sep 17 00:00:00 2001 From: ridhima-splunk Date: Thu, 27 Aug 2026 12:31:03 -0700 Subject: [PATCH 1/4] Upgrade openai to 3.x.x --- pyproject.toml | 11 ++++++----- tests/test_openai_agents.py | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c9e1aa6d..67078ef9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,10 +27,10 @@ packages = [ [project.optional-dependencies] langchain = ["langchain-core", "langchain", "langsmith (>=0.8.0)"] -openai = ["openai (>=2.8.0,<3.0.0)", "packaging (>=24.2,<25.0)", "openai-agents (>=0.4.0,<1.0.0)", "cryptography (>=50.0.0)", "mcp (>=1.27.2,<2)"] +openai = ["openai (>=3.0.0,<4.0.0)", "packaging (>=24.2,<25.0)", "openai-agents (>=0.21.0,<1.0.0)", "cryptography (>=50.0.0)", "mcp (>=1.27.2,<2)"] crewai = ["crewai (>=0.152.0,<2.0.0); python_version < '3.14'", "litellm (>=1.83.14,<2.0.0); python_version < '3.14'", "uv (>=0.9.6); python_version < '3.14'", "aiohttp (>=3.14.1,<4); python_version < '3.14'", "cryptography (>=50.0.0)", "mcp (>=1.27.2,<2)", "pdfminer-six (>=20251107)"] middleware = ["starlette"] -all = ["langchain-core", "langchain", "langsmith (>=0.8.0)", "openai (>=2.8.0,<3.0.0)", "packaging (>=24.2,<25.0)", "openai-agents (>=0.4.0,<1.0.0)", "crewai (>=0.152.0,<2.0.0); python_version < '3.14'", "starlette", "litellm (>=1.83.14,<2.0.0); python_version < '3.14'", "uv (>=0.9.6); python_version < '3.14'", "aiohttp (>=3.14.1,<4); python_version < '3.14'", "cryptography (>=50.0.0)", "mcp (>=1.27.2,<2)", "pdfminer-six (>=20251107)"] +all = ["langchain-core", "langchain", "langsmith (>=0.8.0)", "openai (>=3.0.0,<4.0.0)", "packaging (>=24.2,<25.0)", "openai-agents (>=0.21.0,<1.0.0)", "crewai (>=0.152.0,<2.0.0); python_version < '3.14'", "starlette", "litellm (>=1.83.14,<2.0.0); python_version < '3.14'", "uv (>=0.9.6); python_version < '3.14'", "aiohttp (>=3.14.1,<4); python_version < '3.14'", "cryptography (>=50.0.0)", "mcp (>=1.27.2,<2)", "pdfminer-six (>=20251107)"] @@ -45,8 +45,8 @@ python-dateutil = "^2.8.0" langchain-core = { version = ">=1.3.3", optional = true } langchain = { version = ">=1.3.9,<2.0.0", optional = true } langsmith = { version = ">=0.8.0", optional = true } -openai = { version = ">=2.8.0,<3.0.0", optional = true } -openai-agents = { version = ">=0.4.0,<1.0.0", optional = true } +openai = { version = ">=3.0.0,<4.0.0", optional = true } +openai-agents = { version = ">=0.21.0,<1.0.0", optional = true } litellm = { version = ">=1.83.14,<2.0.0", optional = true, python = ">=3.11,<3.14" } galileo-core = "^4.4.0" httpx = ">=0.27.0,<0.29.0" @@ -93,7 +93,8 @@ time-machine = "^2.17.0" # freezegun causes problems with pydantic model valida pre-commit = "^4.0.1" mypy = "^1.16.0" invoke = "^2.2.0" -openai = ">=2.8.0,<3.0.0" +openai = ">=3.0.0,<4.0.0" +httpx2 = ">=0.28.0" fastapi = "^0.135.0" ruff = "^0.15.22" openapi-python-client = "^0.29.0" diff --git a/tests/test_openai_agents.py b/tests/test_openai_agents.py index 16ed813e..0dbcf56f 100644 --- a/tests/test_openai_agents.py +++ b/tests/test_openai_agents.py @@ -2,7 +2,7 @@ import uuid from unittest.mock import MagicMock, Mock, patch -import httpx +import httpx2 import pytest import respx import vcr @@ -334,7 +334,7 @@ async def capture_payload(payload): mock_response_data = _create_mock_response_with_tools(tool_calls) with respx.mock(base_url="https://api.openai.com") as respx_mock: - respx_mock.post("/v1/responses").mock(return_value=httpx.Response(200, json=mock_response_data)) + respx_mock.post("/v1/responses").mock(return_value=httpx2.Response(200, json=mock_response_data)) agent = Agent( name="Assistant", instructions="You are a helpful assistant.", From b17c0cde154ad1f6d4a38e3aa2b9ea42e2e80511 Mon Sep 17 00:00:00 2001 From: ridhima-splunk Date: Thu, 27 Aug 2026 13:47:21 -0700 Subject: [PATCH 2/4] updated tests --- pyproject.toml | 1 - tests/test_openai_agents.py | 28 ++++++++++++++++++---------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 67078ef9..d10dcbaa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -94,7 +94,6 @@ pre-commit = "^4.0.1" mypy = "^1.16.0" invoke = "^2.2.0" openai = ">=3.0.0,<4.0.0" -httpx2 = ">=0.28.0" fastapi = "^0.135.0" ruff = "^0.15.22" openapi-python-client = "^0.29.0" diff --git a/tests/test_openai_agents.py b/tests/test_openai_agents.py index 0dbcf56f..2a251ee0 100644 --- a/tests/test_openai_agents.py +++ b/tests/test_openai_agents.py @@ -4,7 +4,6 @@ import httpx2 import pytest -import respx import vcr from agents import ( Agent, @@ -12,10 +11,13 @@ GuardrailFunctionOutput, InputGuardrail, InputGuardrailTripwireTriggered, + OpenAIProvider, + RunConfig, Runner, set_trace_processors, ) from agents.tracing import ResponseSpanData +from openai import AsyncOpenAI from pydantic import BaseModel from pytest import MonkeyPatch, mark @@ -333,16 +335,22 @@ async def capture_payload(payload): mock_response_data = _create_mock_response_with_tools(tool_calls) - with respx.mock(base_url="https://api.openai.com") as respx_mock: - respx_mock.post("/v1/responses").mock(return_value=httpx2.Response(200, json=mock_response_data)) - agent = Agent( - name="Assistant", - instructions="You are a helpful assistant.", - tools=[CodeInterpreterTool(tool_config={"type": "code_interpreter", "container": {"type": "auto"}})], - ) + def mock_handler(request: httpx2.Request) -> httpx2.Response: + return httpx2.Response(200, json=mock_response_data) - result = await Runner.run(agent, "Test multiple tools.") - assert result + mock_openai = AsyncOpenAI( + api_key="sk-test", + http_client=httpx2.AsyncClient(transport=httpx2.MockTransport(mock_handler)), + ) + provider = OpenAIProvider(openai_client=mock_openai) + agent = Agent( + name="Assistant", + instructions="You are a helpful assistant.", + tools=[CodeInterpreterTool(tool_config={"type": "code_interpreter", "container": {"type": "auto"}})], + ) + + result = await Runner.run(agent, "Test multiple tools.", run_config=RunConfig(model_provider=provider)) + assert result traces = splunk_ao_logger.traces assert len(traces) == 1 From 4b9c1ca3337aac5a7e193c07caca71cec046ddd7 Mon Sep 17 00:00:00 2001 From: ridhima-splunk Date: Thu, 27 Aug 2026 14:15:55 -0700 Subject: [PATCH 3/4] removed litellm dependancy from crewAI --- pyproject.toml | 6 +-- src/splunk_ao/handlers/crewai/handler.py | 49 ++-------------------- tests/test_crewai_handler.py | 52 ------------------------ 3 files changed, 6 insertions(+), 101 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index d10dcbaa..6ad7de68 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,9 +28,9 @@ packages = [ [project.optional-dependencies] langchain = ["langchain-core", "langchain", "langsmith (>=0.8.0)"] openai = ["openai (>=3.0.0,<4.0.0)", "packaging (>=24.2,<25.0)", "openai-agents (>=0.21.0,<1.0.0)", "cryptography (>=50.0.0)", "mcp (>=1.27.2,<2)"] -crewai = ["crewai (>=0.152.0,<2.0.0); python_version < '3.14'", "litellm (>=1.83.14,<2.0.0); python_version < '3.14'", "uv (>=0.9.6); python_version < '3.14'", "aiohttp (>=3.14.1,<4); python_version < '3.14'", "cryptography (>=50.0.0)", "mcp (>=1.27.2,<2)", "pdfminer-six (>=20251107)"] +crewai = ["crewai (>=0.152.0,<2.0.0); python_version < '3.14'", "uv (>=0.9.6); python_version < '3.14'", "aiohttp (>=3.14.1,<4); python_version < '3.14'", "cryptography (>=50.0.0)", "mcp (>=1.27.2,<2)", "pdfminer-six (>=20251107)"] middleware = ["starlette"] -all = ["langchain-core", "langchain", "langsmith (>=0.8.0)", "openai (>=3.0.0,<4.0.0)", "packaging (>=24.2,<25.0)", "openai-agents (>=0.21.0,<1.0.0)", "crewai (>=0.152.0,<2.0.0); python_version < '3.14'", "starlette", "litellm (>=1.83.14,<2.0.0); python_version < '3.14'", "uv (>=0.9.6); python_version < '3.14'", "aiohttp (>=3.14.1,<4); python_version < '3.14'", "cryptography (>=50.0.0)", "mcp (>=1.27.2,<2)", "pdfminer-six (>=20251107)"] +all = ["langchain-core", "langchain", "langsmith (>=0.8.0)", "openai (>=3.0.0,<4.0.0)", "packaging (>=24.2,<25.0)", "openai-agents (>=0.21.0,<1.0.0)", "crewai (>=0.152.0,<2.0.0); python_version < '3.14'", "starlette", "uv (>=0.9.6); python_version < '3.14'", "aiohttp (>=3.14.1,<4); python_version < '3.14'", "cryptography (>=50.0.0)", "mcp (>=1.27.2,<2)", "pdfminer-six (>=20251107)"] @@ -47,12 +47,10 @@ langchain = { version = ">=1.3.9,<2.0.0", optional = true } langsmith = { version = ">=0.8.0", optional = true } openai = { version = ">=3.0.0,<4.0.0", optional = true } openai-agents = { version = ">=0.21.0,<1.0.0", optional = true } -litellm = { version = ">=1.83.14,<2.0.0", optional = true, python = ">=3.11,<3.14" } galileo-core = "^4.4.0" httpx = ">=0.27.0,<0.29.0" starlette = { version = ">=1.3.1", optional = true } backoff = "^2.2.1" -crewai = { version = ">=0.152.0,<2.0.0", optional = true, python = ">=3.11,<3.14" } tqdm = { version = ">=4.0.0" } typing-extensions = { version = ">=4.5.0" } opentelemetry-sdk = "^1.38.0" diff --git a/src/splunk_ao/handlers/crewai/handler.py b/src/splunk_ao/handlers/crewai/handler.py index 6adc870c..5d346ab9 100644 --- a/src/splunk_ao/handlers/crewai/handler.py +++ b/src/splunk_ao/handlers/crewai/handler.py @@ -1,7 +1,6 @@ import hashlib import json import logging -from datetime import datetime from typing import Any from uuid import UUID @@ -15,19 +14,16 @@ _logger = logging.getLogger(__name__) # Lazy import state — crewai wraps sys.stdout/sys.stderr at import time, which -# causes pytest-xdist worker hangs. All crewai/litellm imports are deferred to +# causes pytest-xdist worker hangs. All crewai imports are deferred to # _resolve_crewai_imports(), called once from CrewAIEventListener.__init__. CREWAI_AVAILABLE = False CREWAI_EVENTS_MODULE_AVAILABLE = False -LITE_LLM_AVAILABLE = False -litellm = None _crewai_imports_resolved = False def _resolve_crewai_imports() -> None: - """Import crewai and litellm on first use, populating module-level globals.""" - global CREWAI_AVAILABLE, CREWAI_EVENTS_MODULE_AVAILABLE - global LITE_LLM_AVAILABLE, litellm, _crewai_imports_resolved + """Import crewai on first use, populating module-level globals.""" + global CREWAI_AVAILABLE, CREWAI_EVENTS_MODULE_AVAILABLE, _crewai_imports_resolved if _crewai_imports_resolved: return @@ -43,15 +39,6 @@ def _resolve_crewai_imports() -> None: except ImportError: _logger.warning("CrewAI not available, using stubs") - try: - import litellm as _litellm - - litellm = _litellm - LITE_LLM_AVAILABLE = True - except ImportError: - _logger.warning("LiteLLM not available, using stubs") - litellm = None - class CrewAIEventListener: """ @@ -92,11 +79,6 @@ def __init__( except ImportError: _logger.warning("Could not import crewai event bus, skipping listener setup") - if LITE_LLM_AVAILABLE and litellm is not None: - if not litellm.success_callback: - litellm.success_callback = [] - litellm.success_callback.append(self.lite_llm_usage_callback) - def setup_listeners(self, crewai_event_bus: Any) -> None: """Setup event listeners for CrewAI events.""" if not CREWAI_AVAILABLE: @@ -345,12 +327,7 @@ def _generate_run_id(self, source: Any, event: Any) -> UUID: task_id = getattr(getattr(event, "task", None), "id", "") return self._hash_to_uuid(f"{event_agent.id}_{task_id}") - # 7. dict messages — lite_llm callback - if isinstance(event, dict) and "messages" in event: - messages = json.dumps(event["messages"]) - return self._hash_to_uuid(messages) - - # 8. Generic fallback + # 7. Generic fallback return self._hash_to_uuid( f"{getattr(event, 'crew_name', '')}_{getattr(event, 'agent', '')}_{getattr(event, 'task', '')}" ) @@ -770,21 +747,3 @@ def _handle_memory_retrieval_failed(self, source: Any, event: Any) -> None: self._handler.end_node(run_id=run_id, output=f"Memory retrieval failed: {metadata['error']}", metadata=metadata) - def lite_llm_usage_callback( - self, - kwargs: dict, # kwargs to completion - completion_response: Any, # response from completion - start_time: datetime, - end_time: datetime, - ) -> None: - node_id = self._generate_run_id(kwargs, kwargs) - - node = self._handler.get_node(node_id) - if not node: - _logger.debug(f"No node exists for run_id {node_id}") - return - usage = completion_response.model_extra["usage"] - node.span_params["usage"] = usage.model_dump() if hasattr(usage, "model_dump") else usage - node.span_params["num_input_tokens"] = getattr(usage, "prompt_tokens", 0) - node.span_params["num_output_tokens"] = getattr(usage, "completion_tokens", 0) - node.span_params["total_tokens"] = getattr(usage, "total_tokens", 0) diff --git a/tests/test_crewai_handler.py b/tests/test_crewai_handler.py index 61cd33e5..ebe58e20 100644 --- a/tests/test_crewai_handler.py +++ b/tests/test_crewai_handler.py @@ -99,7 +99,6 @@ def crewai_callback(mock_splunk_ao_logger): with ( patch("splunk_ao.handlers.crewai.handler._crewai_imports_resolved", True), patch("splunk_ao.handlers.crewai.handler.CREWAI_AVAILABLE", False), - patch("splunk_ao.handlers.crewai.handler.LITE_LLM_AVAILABLE", False), ): from splunk_ao.handlers.crewai.handler import CrewAIEventListener @@ -113,7 +112,6 @@ def test_initialization_with_crewai_available(mock_splunk_ao_logger) -> None: with ( patch("splunk_ao.handlers.crewai.handler._crewai_imports_resolved", True), patch("splunk_ao.handlers.crewai.handler.CREWAI_AVAILABLE", True), - patch("splunk_ao.handlers.crewai.handler.LITE_LLM_AVAILABLE", True), ): from splunk_ao.handlers.crewai.handler import CrewAIEventListener @@ -131,7 +129,6 @@ def test_initialization_with_crewai_unavailable(mock_splunk_ao_logger) -> None: with ( patch("splunk_ao.handlers.crewai.handler._crewai_imports_resolved", True), patch("splunk_ao.handlers.crewai.handler.CREWAI_AVAILABLE", False), - patch("splunk_ao.handlers.crewai.handler.LITE_LLM_AVAILABLE", False), ): from splunk_ao.handlers.crewai.handler import CrewAIEventListener @@ -693,55 +690,6 @@ def test_update_crew_input(crewai_callback: CrewAIEventListener) -> None: assert "Research market trends" in mock_root_node.span_params["input"] -def test_lite_llm_usage_callback(crewai_callback: CrewAIEventListener) -> None: - """Test LiteLLM usage callback.""" - node_id = uuid.uuid4() - - # Mock node - mock_node = Mock() - mock_node.span_params = {} - - # Mock completion response with usage - mock_usage = Mock() - mock_usage.model_dump.return_value = {"prompt_tokens": 100, "completion_tokens": 50, "total_tokens": 150} - mock_usage.prompt_tokens = 100 - mock_usage.completion_tokens = 50 - mock_usage.total_tokens = 150 - - mock_response = Mock() - mock_response.model_extra = {"usage": mock_usage} - - kwargs = {"messages": [{"role": "user", "content": "test"}]} - - with ( - patch.object(crewai_callback._handler, "get_node", return_value=mock_node), - patch.object(crewai_callback, "_generate_run_id", return_value=node_id), - ): - crewai_callback.lite_llm_usage_callback( - kwargs=kwargs, completion_response=mock_response, start_time=datetime.now(), end_time=datetime.now() - ) - - # Verify usage was recorded - assert mock_node.span_params["num_input_tokens"] == 100 - assert mock_node.span_params["num_output_tokens"] == 50 - assert mock_node.span_params["total_tokens"] == 150 - - -def test_lite_llm_usage_callback_no_node(crewai_callback) -> None: - """Test LiteLLM usage callback when node doesn't exist.""" - kwargs = {"messages": [{"role": "user", "content": "test"}]} - mock_response = Mock() - - with ( - patch.object(crewai_callback._handler, "get_node", return_value=None), - patch.object(crewai_callback, "_generate_run_id", return_value=uuid.uuid4()), - ): - # Should not raise an exception - crewai_callback.lite_llm_usage_callback( - kwargs=kwargs, completion_response=mock_response, start_time=datetime.now(), end_time=datetime.now() - ) - - # Memory event tests (for CrewAI >= 0.177.0) From d5bef298fa3e584e0473d56346d8efee26677624 Mon Sep 17 00:00:00 2001 From: ridhima-splunk Date: Fri, 28 Aug 2026 10:10:04 -0700 Subject: [PATCH 4/4] changed crewAI version --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 6ad7de68..c144c4bb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,9 +28,9 @@ packages = [ [project.optional-dependencies] langchain = ["langchain-core", "langchain", "langsmith (>=0.8.0)"] openai = ["openai (>=3.0.0,<4.0.0)", "packaging (>=24.2,<25.0)", "openai-agents (>=0.21.0,<1.0.0)", "cryptography (>=50.0.0)", "mcp (>=1.27.2,<2)"] -crewai = ["crewai (>=0.152.0,<2.0.0); python_version < '3.14'", "uv (>=0.9.6); python_version < '3.14'", "aiohttp (>=3.14.1,<4); python_version < '3.14'", "cryptography (>=50.0.0)", "mcp (>=1.27.2,<2)", "pdfminer-six (>=20251107)"] +crewai = ["crewai (>=0.177.0,<2.0.0); python_version < '3.14'", "uv (>=0.9.6); python_version < '3.14'", "aiohttp (>=3.14.1,<4); python_version < '3.14'", "cryptography (>=50.0.0)", "mcp (>=1.27.2,<2)", "pdfminer-six (>=20251107)"] middleware = ["starlette"] -all = ["langchain-core", "langchain", "langsmith (>=0.8.0)", "openai (>=3.0.0,<4.0.0)", "packaging (>=24.2,<25.0)", "openai-agents (>=0.21.0,<1.0.0)", "crewai (>=0.152.0,<2.0.0); python_version < '3.14'", "starlette", "uv (>=0.9.6); python_version < '3.14'", "aiohttp (>=3.14.1,<4); python_version < '3.14'", "cryptography (>=50.0.0)", "mcp (>=1.27.2,<2)", "pdfminer-six (>=20251107)"] +all = ["langchain-core", "langchain", "langsmith (>=0.8.0)", "openai (>=3.0.0,<4.0.0)", "packaging (>=24.2,<25.0)", "openai-agents (>=0.21.0,<1.0.0)", "crewai (>=0.177.0,<2.0.0); python_version < '3.14'", "starlette", "uv (>=0.9.6); python_version < '3.14'", "aiohttp (>=3.14.1,<4); python_version < '3.14'", "cryptography (>=50.0.0)", "mcp (>=1.27.2,<2)", "pdfminer-six (>=20251107)"]