Skip to content

[BUG] A2AAgent returns empty AgentResult content when last event is TaskStatusUpdateEvent with no message #1648

@yuu551

Description

@yuu551

Checks

  • I have updated to the lastest minor and patch version of Strands
  • I have checked the documentation and this is not expected behavior
  • I have searched ./issues and there are no duplicates of my issue

Strands Version

1.25.0

Python Version

3.12.0

Operating System

macOS 15.7

Installation Method

other

Steps to Reproduce

  1. Create an A2A server:
# server.py
from strands import Agent
from strands.multiagent.a2a import A2AServer
from strands_tools.calculator import calculator

strands_agent = Agent(
    name="Calculator Agent",
    description="Calculator agent for arithmetic operations.",
    tools=[calculator],
    callback_handler=None,
)

a2a_server = A2AServer(agent=strands_agent, enable_a2a_compliant_streaming=True)
a2a_server.serve()
  1. Call the agent synchronously or with invoke_async:
# client.py
from strands.agent.a2a_agent import A2AAgent

a2a_agent = A2AAgent(endpoint="http://localhost:9000")
result = a2a_agent("101 * 11 を計算して")
print(result.message)
#Result
# {'role': 'assistant', 'content': []}

Expected Behavior

AgentResult.message["content"] should contain the agent's response text, e.g.:

{'role': 'assistant', 'content': [{'text': '101 × 11 = 1111'}]}

Actual Behavior

AgentResult.message["content"] is an empty list:

{'role': 'assistant', 'content': []}

The text is correctly received in the stream — TaskArtifactUpdateEvents contain the expected text parts. Only the final AgentResult conversion produces empty content.

The issue is in convert_response_to_agent_result in strands/multiagent/a2a/_converters.py.

The A2A stream ends with the following sequence:

  1. Multiple TaskArtifactUpdateEvents with text content (correct)
  2. A final TaskArtifactUpdateEvent with lastChunk=True and empty parts
  3. A final TaskStatusUpdateEvent with state=completed and message=None

stream_async selects the last complete event via _is_complete_event(). Since TaskStatusUpdateEvent with state=completed is considered complete, it becomes the last_complete_event — overwriting the previous TaskArtifactUpdateEvent with lastChunk=True.

When convert_response_to_agent_result receives (Task, TaskStatusUpdateEvent):

# Current code (lines 103-107)
elif isinstance(update_event, TaskStatusUpdateEvent):
    if update_event.status and hasattr(update_event.status, "message") and update_event.status.message:
        for part in update_event.status.message.parts:
            ...

update_event.status.message is None, so no content is extracted.

The fallback to task.artifacts (line 109) only runs when update_event is None:

elif update_event is None and task and hasattr(task, "artifacts") and task.artifacts is not None:
    for artifact in task.artifacts:
        ...

The Task object does contain the accumulated text in task.artifacts, but the converter never reaches this branch because update_event is a TaskStatusUpdateEvent, not None.

Possible Solution

Add a fallback to task.artifacts when TaskStatusUpdateEvent.status.message is None:

elif isinstance(update_event, TaskStatusUpdateEvent):
    if update_event.status and hasattr(update_event.status, "message") and update_event.status.message:
        for part in update_event.status.message.parts:
            if hasattr(part, "root") and hasattr(part.root, "text"):
                content.append({"text": part.root.text})
    # Fallback: extract from task.artifacts when status.message is None
    elif task and hasattr(task, "artifacts") and task.artifacts is not None:
        for artifact in task.artifacts:
            if hasattr(artifact, "parts"):
                for part in artifact.parts:
                    if hasattr(part, "root") and hasattr(part.root, "text"):
                        content.append({"text": part.root.text})

Workaround

Use stream_async and extract text directly from TaskArtifactUpdateEvent:

import asyncio
from strands.agent.a2a_agent import A2AAgent

async def main():
    a2a_agent = A2AAgent(endpoint="http://localhost:9000")
    async for event in a2a_agent.stream_async("101 * 11 を計算して"):
        if event.get("type") == "a2a_stream":
            a2a_event = event["event"]
            if isinstance(a2a_event, tuple):
                task, update = a2a_event
                if hasattr(update, "artifact") and update.artifact and update.artifact.parts:
                    for part in update.artifact.parts:
                        if hasattr(part, "root") and hasattr(part.root, "text"):
                            print(part.root.text, end="", flush=True)
        elif "result" in event:
            print()

asyncio.run(main())

Related Issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions