diff --git a/lib/crewai/src/crewai/events/listeners/tracing/first_time_trace_handler.py b/lib/crewai/src/crewai/events/listeners/tracing/first_time_trace_handler.py index eeb46b2aa..3bdef83c0 100644 --- a/lib/crewai/src/crewai/events/listeners/tracing/first_time_trace_handler.py +++ b/lib/crewai/src/crewai/events/listeners/tracing/first_time_trace_handler.py @@ -99,7 +99,7 @@ class FirstTimeTraceHandler: self.batch_manager._initialize_backend_batch( user_context=user_context, execution_metadata=execution_metadata, - use_ephemeral=True, + use_ephemeral=self.batch_manager.is_current_batch_ephemeral, ) if not self.batch_manager.trace_batch_id: diff --git a/lib/crewai/src/crewai/events/listeners/tracing/trace_listener.py b/lib/crewai/src/crewai/events/listeners/tracing/trace_listener.py index b022eb582..27012c743 100644 --- a/lib/crewai/src/crewai/events/listeners/tracing/trace_listener.py +++ b/lib/crewai/src/crewai/events/listeners/tracing/trace_listener.py @@ -706,13 +706,14 @@ class TraceCollectionListener(BaseEventListener): user_context: User context information. execution_metadata: Metadata about the execution. """ + use_ephemeral = not self._check_authenticated() + if self.first_time_handler.is_first_time: self.batch_manager.initialize_batch( - user_context, execution_metadata, use_ephemeral=True + user_context, execution_metadata, use_ephemeral=use_ephemeral ) return - use_ephemeral = not self._check_authenticated() self.batch_manager.initialize_batch( user_context, execution_metadata, use_ephemeral=use_ephemeral ) diff --git a/lib/crewai/tests/tracing/test_tracing.py b/lib/crewai/tests/tracing/test_tracing.py index 890567631..3b515ca4e 100644 --- a/lib/crewai/tests/tracing/test_tracing.py +++ b/lib/crewai/tests/tracing/test_tracing.py @@ -1344,3 +1344,106 @@ class TestFirstTimeHandlerBackendInitGuard: mock_send.assert_not_called() mock_finalize.assert_not_called() mock_fail.assert_called_once() + + +class TestFirstTimeAuthRespected: + """Tests for Fix 3: first-time users respect authentication status.""" + + def test_first_time_authenticated_uses_non_ephemeral(self): + """Authenticated first-time user should use non-ephemeral (use_ephemeral=False).""" + with ( + patch( + "crewai.events.listeners.tracing.trace_batch_manager.get_auth_token", + return_value="mock_token", + ), + patch( + "crewai.events.listeners.tracing.trace_listener.get_auth_token", + return_value="mock_token", + ), + ): + from crewai.events.listeners.tracing.trace_listener import TraceCollectionListener + + listener = TraceCollectionListener.__new__(TraceCollectionListener) + listener.first_time_handler = FirstTimeTraceHandler() + listener.first_time_handler.is_first_time = True + listener.batch_manager = TraceBatchManager() + + with patch.object( + listener.batch_manager, "initialize_batch" + ) as mock_init_batch: + listener._initialize_batch( + user_context={"privacy_level": "standard"}, + execution_metadata={"execution_type": "crew"}, + ) + + mock_init_batch.assert_called_once_with( + {"privacy_level": "standard"}, + {"execution_type": "crew"}, + use_ephemeral=False, + ) + + def test_first_time_unauthenticated_uses_ephemeral(self): + """Unauthenticated first-time user should use ephemeral (use_ephemeral=True).""" + with ( + patch( + "crewai.events.listeners.tracing.trace_batch_manager.get_auth_token", + return_value="mock_token", + ), + patch( + "crewai.events.listeners.tracing.trace_listener.get_auth_token", + return_value=None, + ), + ): + from crewai.events.listeners.tracing.trace_listener import TraceCollectionListener + + listener = TraceCollectionListener.__new__(TraceCollectionListener) + listener.first_time_handler = FirstTimeTraceHandler() + listener.first_time_handler.is_first_time = True + listener.batch_manager = TraceBatchManager() + + with patch.object( + listener.batch_manager, "initialize_batch" + ) as mock_init_batch: + listener._initialize_batch( + user_context={"privacy_level": "standard"}, + execution_metadata={"execution_type": "crew"}, + ) + + mock_init_batch.assert_called_once_with( + {"privacy_level": "standard"}, + {"execution_type": "crew"}, + use_ephemeral=True, + ) + + def test_first_time_handler_deferred_init_uses_batch_ephemeral_flag(self): + """Deferred backend init should use is_current_batch_ephemeral, not hardcoded True.""" + with patch( + "crewai.events.listeners.tracing.trace_batch_manager.get_auth_token", + return_value="mock_token", + ): + bm = TraceBatchManager() + bm.current_batch = TraceBatch( + user_context={"privacy_level": "standard"}, + execution_metadata={"execution_type": "crew", "crew_name": "test"}, + ) + bm.trace_batch_id = bm.current_batch.batch_id + bm.is_current_batch_ephemeral = False # authenticated user + + handler = FirstTimeTraceHandler() + handler.is_first_time = True + handler.collected_events = True + handler.batch_manager = bm + + with ( + patch.object(bm, "_initialize_backend_batch") as mock_init, + patch.object(bm, "_send_events_to_backend"), + patch.object(bm, "finalize_batch"), + ): + # trace_batch_id stays set (simulating success) + mock_init.side_effect = lambda **kwargs: None + bm.event_buffer = [MagicMock()] + handler._initialize_backend_and_send_events() + + mock_init.assert_called_once() + call_kwargs = mock_init.call_args + assert call_kwargs.kwargs["use_ephemeral"] is False