From f57cbb0ca010b11f0a2763f8e5b3ea1cc457e284 Mon Sep 17 00:00:00 2001 From: lorenzejay Date: Thu, 4 Jun 2026 15:45:09 -0700 Subject: [PATCH] fix(conversational_mixin): handle empty message index in route events Updated the message index handling in the class to return when there are no messages. Added tests to ensure that route events do not reference index zero when the transcript is empty, and verified the correct emission of conversation message events during flow handling. --- .../experimental/conversational_mixin.py | 2 +- lib/crewai/tests/test_flow_conversation.py | 33 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/lib/crewai/src/crewai/experimental/conversational_mixin.py b/lib/crewai/src/crewai/experimental/conversational_mixin.py index 829029a0a..3801d0570 100644 --- a/lib/crewai/src/crewai/experimental/conversational_mixin.py +++ b/lib/crewai/src/crewai/experimental/conversational_mixin.py @@ -479,7 +479,7 @@ class _ConversationalMixin: session_id=state.id, route=route, user_message=state.current_user_message, - message_index=max(len(state.messages) - 1, 0), + message_index=(len(state.messages) - 1) if state.messages else None, previous_intent=previous_intent, ), ) diff --git a/lib/crewai/tests/test_flow_conversation.py b/lib/crewai/tests/test_flow_conversation.py index cd01ca4cb..fab03ad29 100644 --- a/lib/crewai/tests/test_flow_conversation.py +++ b/lib/crewai/tests/test_flow_conversation.py @@ -1036,14 +1036,23 @@ class TestConversationalFlow: return "worked" flow = DeferredFlow() + observed_events: list[str] = [] started_events: list[FlowStartedEvent] = [] with crewai_event_bus.scoped_handlers(): @crewai_event_bus.on(FlowStartedEvent) def capture(_: Any, event: FlowStartedEvent) -> None: + observed_events.append(event.type) started_events.append(event) + @crewai_event_bus.on(ConversationMessageAddedEvent) + def capture_message( + _: Any, event: ConversationMessageAddedEvent + ) -> None: + if event.role == "user": + observed_events.append(event.type) + flow.handle_turn("turn 1") flow.handle_turn("turn 2") flow.handle_turn("turn 3") @@ -1053,6 +1062,30 @@ class TestConversationalFlow: "deferred conversational traces should emit one session-level " "flow_started event, not one per turn" ) + assert observed_events[0] == "flow_started" + assert observed_events[1] == "conversation_message_added" + + def test_route_event_uses_no_message_index_for_empty_transcript(self) -> None: + """Route events do not reference index zero when no message exists.""" + + @ConversationConfig() + class DeferredFlow(ConversationalFlow): + pass + + flow = DeferredFlow() + route_events: list[ConversationRouteSelectedEvent] = [] + + with crewai_event_bus.scoped_handlers(): + + @crewai_event_bus.on(ConversationRouteSelectedEvent) + def capture(_: Any, event: ConversationRouteSelectedEvent) -> None: + route_events.append(event) + + flow._emit_conversation_route_selected("converse") + crewai_event_bus.flush() + + assert len(route_events) == 1 + assert route_events[0].message_index is None def test_finalize_session_traces_emits_finished_and_finalizes_batch(self) -> None: """``finalize_session_traces()`` emits one ``FlowFinishedEvent`` + one ``finalize_batch``.