Skip to content

Commit b58b03e

Browse files
authored
fix: Don't generate empty metadata change events in VertexTaskStore (#974)
For #802
1 parent 3468180 commit b58b03e

2 files changed

Lines changed: 58 additions & 1 deletion

File tree

src/a2a/contrib/tasks/vertex_task_store.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,12 @@ def _get_metadata_change_event(
116116
task: CompatTask,
117117
event_sequence_number: int,
118118
) -> vertexai_types.TaskEvent | None:
119-
if task.metadata != previous_task.metadata:
119+
# We generate metadata change events if the metadata was changed.
120+
# We don't generate events if the metadata was changed from
121+
# one empty value to another, e.g. {} to None.
122+
if task.metadata != previous_task.metadata and (
123+
task.metadata or previous_task.metadata
124+
):
120125
return vertexai_types.TaskEvent(
121126
event_data=vertexai_types.TaskEventData(
122127
metadata_change=vertexai_types.TaskMetadataChange(

tests/contrib/tasks/test_vertex_task_store.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,58 @@ async def test_metadata_field_mapping(
534534
assert retrieved_none.metadata == {}
535535

536536

537+
@pytest.mark.asyncio
538+
async def test_metadata_empty_transitions(
539+
vertex_store: VertexTaskStore,
540+
) -> None:
541+
"""Test that updating metadata between {} and None does not generate events."""
542+
task_id = 'task-metadata-empty-test'
543+
544+
# Step 1: Create task with metadata={}
545+
task = Task(
546+
id=task_id,
547+
context_id='session-meta-empty',
548+
status=TaskStatus(state=TaskState.TASK_STATE_SUBMITTED),
549+
metadata={},
550+
)
551+
await vertex_store.save(task, ServerCallContext())
552+
553+
full_name = f'{vertex_store._agent_engine_resource_id}/a2aTasks/{task_id}'
554+
555+
# Get initial event sequence number
556+
stored_task_before = (
557+
await vertex_store._client.aio.agent_engines.a2a_tasks.get(
558+
name=full_name
559+
)
560+
)
561+
initial_seq = stored_task_before.next_event_sequence_number
562+
563+
# Step 2: Update metadata to None
564+
updated_task = Task()
565+
updated_task.CopyFrom(task)
566+
updated_task.metadata.Clear()
567+
await vertex_store.save(updated_task, ServerCallContext())
568+
569+
# Step 3: Update back to {}
570+
task_back = Task()
571+
task_back.CopyFrom(updated_task)
572+
task_back.metadata = {}
573+
await vertex_store.save(task_back, ServerCallContext())
574+
575+
# Verify that retrieved task still has {} (due to mapping)
576+
retrieved = await vertex_store.get(task_id, ServerCallContext())
577+
assert retrieved is not None
578+
assert retrieved.metadata == {}
579+
580+
# Verify that next_event_sequence_number did NOT increase (no events generated)
581+
stored_task_after = (
582+
await vertex_store._client.aio.agent_engines.a2a_tasks.get(
583+
name=full_name
584+
)
585+
)
586+
assert stored_task_after.next_event_sequence_number == initial_seq
587+
588+
537589
@pytest.mark.asyncio
538590
async def test_update_task_status_details(
539591
vertex_store: VertexTaskStore,

0 commit comments

Comments
 (0)