-
Notifications
You must be signed in to change notification settings - Fork 8.5k
Fix A2A artifact part reassembly inserting extra whitespace #7488
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
242c146
22f1656
41660f6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -181,7 +181,7 @@ def process_task_state( | |
| if a2a_task.history: | ||
| new_messages.extend(a2a_task.history) | ||
|
|
||
| response_text = " ".join(result_parts) if result_parts else "" | ||
| response_text = "".join(result_parts) if result_parts else "" | ||
| message_id = None | ||
| if a2a_task.status and a2a_task.status.message: | ||
| message_id = a2a_task.status.message.message_id | ||
|
|
@@ -327,7 +327,7 @@ async def send_message_and_get_task_id( | |
| result_parts = [ | ||
| part.root.text for part in event.parts if part.root.kind == "text" | ||
| ] | ||
| response_text = " ".join(result_parts) if result_parts else "" | ||
| response_text = "".join(result_parts) if result_parts else "" | ||
|
|
||
| crewai_event_bus.emit( | ||
| None, | ||
|
Comment on lines
327
to
333
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Concatenate max-turns fallback text directly. When 🤖 Prompt for AI Agents |
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| """Tests for A2A task_helpers.py — specifically artifact text reassembly.""" | ||
| from unittest.mock import MagicMock, patch | ||
|
|
||
| from a2a.types import Part, TaskState, TextPart | ||
|
|
||
| from crewai.a2a.task_helpers import process_task_state | ||
|
|
||
|
|
||
| def _make_text_part(text: str) -> Part: | ||
| return Part(root=TextPart(text=text)) | ||
|
|
||
|
|
||
| @patch("crewai.a2a.task_helpers.crewai_event_bus.emit") | ||
| def test_result_parts_are_concatenated_without_separator(mock_emit): | ||
| """Per the A2A spec, artifact parts sent with append=True must be | ||
| joined with NO separator. Previously this used ' '.join(...), which | ||
| corrupted text by inserting spaces between streamed chunks.""" | ||
| a2a_task = MagicMock() | ||
| a2a_task.status.state = TaskState.completed | ||
| a2a_task.status.message.parts = [ | ||
| _make_text_part("Hel"), | ||
| _make_text_part("lo, "), | ||
| _make_text_part("world"), | ||
| ] | ||
|
Comment on lines
+20
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Exercise the artifact extraction path.
🤖 Prompt for AI Agents |
||
| a2a_task.status.message.message_id = "msg-1" | ||
| a2a_task.history = None | ||
| a2a_task.context_id = "ctx-1" | ||
|
|
||
| result = process_task_state( | ||
| a2a_task=a2a_task, | ||
| new_messages=[], | ||
| agent_card=MagicMock(), | ||
| turn_number=1, | ||
| is_multiturn=False, | ||
| agent_role=None, | ||
| endpoint=None, | ||
| a2a_agent_name=None, | ||
| from_task=None, | ||
| from_agent=None, | ||
| is_final=True, | ||
| ) | ||
|
|
||
| print("RESULT KEYS:", result) # delete this line | ||
|
|
||
| assert result is not None | ||
| assert result["result"] == "Hello, world" | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Concatenate streamed result parts without separators. When a streamed response reaches the terminal fallback in
lib/crewai/src/crewai/a2a/updates/streaming/handler.py, it returns" ".join(result_parts). This inserts spaces between A2A append chunks, so["Hel", "lo, ", "world"]becomesHel lo, worldinstead ofHello, world. Use direct concatenation in this fallback.🤖 Prompt for AI Agents