Skip to content

Commit 35137fe

Browse files
committed
fix: return mandatory fields from list_tasks
According to [the spec](https://a2a-protocol.org/latest/specification/#314-list-tasks) all response fields are mandatory. Update implementation and add tests to cover.
1 parent e140694 commit 35137fe

File tree

7 files changed

+23
-20
lines changed

7 files changed

+23
-20
lines changed

src/a2a/server/request_handlers/default_request_handler.py

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -137,25 +137,15 @@ async def on_list_tasks(
137137
) -> ListTasksResponse:
138138
"""Default handler for 'tasks/list'."""
139139
page = await self.task_store.list(params, context)
140-
processed_tasks = []
141140
for task in page.tasks:
142-
processed_task = task
143-
144141
if not params.include_artifacts:
145-
new_task = Task()
146-
new_task.CopyFrom(processed_task)
147-
new_task.ClearField('artifacts')
148-
processed_task = new_task
149-
150-
if params.history_length > 0:
151-
processed_task = apply_history_length(
152-
processed_task, params.history_length
153-
)
154-
processed_tasks.append(processed_task)
155-
return ListTasksResponse(
156-
next_page_token=page.next_page_token or '',
157-
tasks=processed_tasks,
158-
)
142+
task.ClearField('artifacts')
143+
144+
updated_task = apply_history_length(task, params.history_length)
145+
if updated_task is not task:
146+
task.CopyFrom(updated_task)
147+
148+
return page
159149

160150
async def on_cancel_task(
161151
self,

src/a2a/server/tasks/database_task_store.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,8 @@ async def list(
261261
return a2a_pb2.ListTasksResponse(
262262
tasks=tasks[:page_size],
263263
total_size=total_count,
264-
next_page_token=next_page_token or '',
264+
next_page_token=next_page_token,
265+
page_size=page_size,
265266
)
266267

267268
async def delete(

src/a2a/server/tasks/inmemory_task_store.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ async def list(
106106
break
107107
if not valid_token:
108108
raise ValueError(f'Invalid page token: {params.page_token}')
109-
end_idx = start_idx + (params.page_size or DEFAULT_LIST_TASKS_PAGE_SIZE)
109+
page_size = params.page_size or DEFAULT_LIST_TASKS_PAGE_SIZE
110+
end_idx = start_idx + page_size
110111
next_page_token = (
111112
encode_page_token(tasks[end_idx].id)
112113
if end_idx < total_size
@@ -115,9 +116,10 @@ async def list(
115116
tasks = tasks[start_idx:end_idx]
116117

117118
return a2a_pb2.ListTasksResponse(
118-
next_page_token=next_page_token or '',
119+
next_page_token=next_page_token,
119120
tasks=tasks,
120121
total_size=total_size,
122+
page_size=page_size,
121123
)
122124

123125
async def delete(

tests/integration/test_client_server_integration.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@
9696
LIST_TASKS_RESPONSE = ListTasksResponse(
9797
tasks=[TASK_FROM_BLOCKING, GET_TASK_RESPONSE],
9898
next_page_token='page-2',
99+
total_size=12,
100+
page_size=10,
99101
)
100102

101103

@@ -480,6 +482,8 @@ async def test_http_transport_list_tasks(
480482

481483
assert len(result.tasks) == 2
482484
assert result.next_page_token == 'page-2'
485+
assert result.total_size == 12
486+
assert result.page_size == 10
483487
handler.on_list_tasks.assert_awaited_once()
484488

485489
if hasattr(transport, 'close'):

tests/integration/test_end_to_end.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,8 @@ async def test_end_to_end_list_tasks(transport_setups):
304304

305305
list_response = await transport.list_tasks(request=list_request)
306306
assert 0 < len(list_response.tasks) <= page_size
307+
assert list_response.total_size == total_items
308+
assert list_response.page_size == page_size
307309

308310
for task in list_response.tasks:
309311
unique_task_ids.add(task.id)

tests/server/tasks/test_database_task_store.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
TaskState,
3131
TaskStatus,
3232
)
33+
from a2a.utils.constants import DEFAULT_LIST_TASKS_PAGE_SIZE
3334

3435

3536
# DSNs for different databases
@@ -305,6 +306,7 @@ async def test_list_tasks(
305306
assert retrieved_ids == expected_ids
306307
assert page.total_size == total_count
307308
assert page.next_page_token == (next_page_token or '')
309+
assert page.page_size == (params.page_size or DEFAULT_LIST_TASKS_PAGE_SIZE)
308310

309311
# Cleanup
310312
for task in tasks_to_create:

tests/server/tasks/test_inmemory_task_store.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
from a2a.server.tasks import InMemoryTaskStore
55
from a2a.types.a2a_pb2 import Task, TaskState, TaskStatus, ListTasksRequest
6+
from a2a.utils.constants import DEFAULT_LIST_TASKS_PAGE_SIZE
67

78

89
def create_minimal_task(
@@ -167,6 +168,7 @@ async def test_list_tasks(
167168
assert retrieved_ids == expected_ids
168169
assert page.total_size == total_count
169170
assert page.next_page_token == (next_page_token or '')
171+
assert page.page_size == (params.page_size or DEFAULT_LIST_TASKS_PAGE_SIZE)
170172

171173
# Cleanup
172174
for task in tasks_to_create:

0 commit comments

Comments
 (0)