diff --git a/agentops/sdk/decorators/factory.py b/agentops/sdk/decorators/factory.py index 2ddca1437..50d25d322 100644 --- a/agentops/sdk/decorators/factory.py +++ b/agentops/sdk/decorators/factory.py @@ -82,7 +82,21 @@ def wrapper( wrapped_func: Callable[..., Any], instance: Optional[Any], args: tuple, kwargs: Dict[str, Any] ) -> Any: if not tracer.initialized: - return wrapped_func(*args, **kwargs) + logger.warning( + "AgentOps SDK not initialized. Attempting to initialize with defaults before applying decorator." + ) + try: + from agentops import init + + init() + if not tracer.initialized: + logger.error("SDK initialization failed. Decorator will not instrument function.") + return wrapped_func(*args, **kwargs) + except Exception as e: + logger.error( + f"SDK auto-initialization failed during decorator application: {e}. Decorator will not instrument function." + ) + return wrapped_func(*args, **kwargs) operation_name = name or wrapped_func.__name__ is_async = asyncio.iscoroutinefunction(wrapped_func) diff --git a/tests/unit/sdk/test_decorators.py b/tests/unit/sdk/test_decorators.py index 96824d0fe..f8b19dfc4 100644 --- a/tests/unit/sdk/test_decorators.py +++ b/tests/unit/sdk/test_decorators.py @@ -761,3 +761,68 @@ def no_cost_tool(self): span for span in spans if span.attributes.get(SpanAttributes.AGENTOPS_SPAN_KIND) == SpanKind.TOOL ) assert SpanAttributes.LLM_USAGE_TOOL_COST not in tool_span.attributes + + +class TestDecoratorAutoInitialization: + """Tests for decorator auto-initialization functionality.""" + + def test_decorator_auto_initialization_success(self, instrumentation: InstrumentationTester): + """Test that decorators auto-initialize when tracer is not initialized.""" + from unittest.mock import patch + from agentops.sdk.decorators.factory import create_entity_decorator + from agentops.sdk.core import tracer + + with patch.object(tracer, "_initialized", False): + with patch("agentops.init") as mock_init: + + def mock_init_side_effect(): + tracer._initialized = True + + mock_init.side_effect = mock_init_side_effect + + @create_entity_decorator("TASK") + def test_function(): + return "test_result" + + result = test_function() + + mock_init.assert_called_once() + assert result == "test_result" + + def test_decorator_auto_initialization_failure(self, instrumentation: InstrumentationTester): + """Test that decorators handle auto-initialization failure gracefully.""" + from unittest.mock import patch + from agentops.sdk.decorators.factory import create_entity_decorator + from agentops.sdk.core import tracer + + with patch.object(tracer, "_initialized", False): + with patch("agentops.init") as mock_init: + mock_init.side_effect = Exception("Init failed") + + @create_entity_decorator("TASK") + def test_function(): + return "test_result" + + result = test_function() + + mock_init.assert_called_once() + assert result == "test_result" + + def test_decorator_auto_initialization_partial_failure(self, instrumentation: InstrumentationTester): + """Test that decorators handle partial initialization failure gracefully.""" + from unittest.mock import patch + from agentops.sdk.decorators.factory import create_entity_decorator + from agentops.sdk.core import tracer + + with patch.object(tracer, "_initialized", False): + with patch("agentops.init") as mock_init: + mock_init.return_value = None + + @create_entity_decorator("TASK") + def test_function(): + return "test_result" + + result = test_function() + + mock_init.assert_called_once() + assert result == "test_result"