From 41ec7f6ce0852d7c9dac1988963036db6d1e56b3 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 3 Feb 2026 12:45:48 +0000 Subject: [PATCH] fix: populate task_id and task_name in streaming chunks from event MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #4347 - Crew streaming chunks were missing task metadata (task_id/task_name empty). The issue was in _create_stream_chunk() which only used current_task_info for task_name and task_id, ignoring the values from the LLMStreamChunkEvent. This is inconsistent with how agent_role and agent_id were handled (preferring event values). The fix updates _create_stream_chunk() to use event.task_name and event.task_id when available, falling back to current_task_info values otherwise. Added test to verify streaming chunks contain task metadata from events. Co-Authored-By: João --- lib/crewai/src/crewai/utilities/streaming.py | 4 +- lib/crewai/tests/test_streaming.py | 58 ++++++++++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/lib/crewai/src/crewai/utilities/streaming.py b/lib/crewai/src/crewai/utilities/streaming.py index 8f43e8ef0..0cb1583ce 100644 --- a/lib/crewai/src/crewai/utilities/streaming.py +++ b/lib/crewai/src/crewai/utilities/streaming.py @@ -86,8 +86,8 @@ def _create_stream_chunk( content=event.chunk, chunk_type=chunk_type, task_index=current_task_info["index"], - task_name=current_task_info["name"], - task_id=current_task_info["id"], + task_name=event.task_name or current_task_info["name"], + task_id=event.task_id or current_task_info["id"], agent_role=event.agent_role or current_task_info["agent_role"], agent_id=event.agent_id or current_task_info["agent_id"], tool_call=tool_call_chunk, diff --git a/lib/crewai/tests/test_streaming.py b/lib/crewai/tests/test_streaming.py index 5860755ff..06741bf90 100644 --- a/lib/crewai/tests/test_streaming.py +++ b/lib/crewai/tests/test_streaming.py @@ -698,6 +698,64 @@ class TestStreamingEdgeCases: assert len(chunks) >= 1 assert streaming.is_completed + def test_streaming_chunks_contain_task_metadata_from_event( + self, researcher: Agent, simple_task: Task + ) -> None: + """Test that streaming chunks contain task_id and task_name from the event. + + This test verifies the fix for issue #4347 where streaming chunks were + missing task metadata (task_id/task_name were empty). + """ + crew = Crew( + agents=[researcher], + tasks=[simple_task], + verbose=False, + stream=True, + ) + + mock_output = MagicMock() + mock_output.raw = "Test output" + + original_kickoff = Crew.kickoff + call_count = [0] + test_task_id = "test-task-uuid-123" + test_task_name = "Test Task Name" + test_agent_id = "test-agent-uuid-456" + test_agent_role = "Test Agent Role" + + def mock_kickoff_fn(self: Any, inputs: Any = None, **kwargs: Any) -> Any: + call_count[0] += 1 + if call_count[0] == 1: + return original_kickoff(self, inputs, **kwargs) + else: + crewai_event_bus.emit( + crew, + LLMStreamChunkEvent( + type="llm_stream_chunk", + chunk="Hello from task", + task_id=test_task_id, + task_name=test_task_name, + agent_id=test_agent_id, + agent_role=test_agent_role, + ), + ) + return mock_output + + with patch.object(Crew, "kickoff", mock_kickoff_fn): + streaming = crew.kickoff() + assert isinstance(streaming, CrewStreamingOutput) + chunks = list(streaming) + + assert len(chunks) >= 1 + chunk_with_metadata = next( + (c for c in chunks if c.content == "Hello from task"), None + ) + assert chunk_with_metadata is not None + assert chunk_with_metadata.task_id == test_task_id + assert chunk_with_metadata.task_name == test_task_name + assert chunk_with_metadata.agent_id == test_agent_id + assert chunk_with_metadata.agent_role == test_agent_role + class TestStreamingImports: """Tests for correct imports of streaming types."""