Skip to content

Commit 97f1093

Browse files
authored
fix: client should not specify taskId if it doesn't exist (#264)
# Description I'm submitting this PR as a proposal based off of #218 (comment). If the taskId doesn't exist, I was thinking that an exception should be thrown to prevent the client from specifying the id. The reason I think this change is required because if the client specifies a taskId but one doesn't exist, it won't actually get push notifications based off that first request, because the logic to `set_info()` gets skipped because there is no `task` when _setup_message_execution is called. Found while working on mozilla-ai/any-agent#414
1 parent 0e9baaa commit 97f1093

File tree

2 files changed

+88
-0
lines changed

2 files changed

+88
-0
lines changed

src/a2a/server/request_handlers/default_request_handler.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,12 @@ async def _setup_message_execution(
200200
)
201201

202202
task = task_manager.update_with_message(params.message, task)
203+
elif params.message.taskId:
204+
raise ServerError(
205+
error=TaskNotFoundError(
206+
message=f'Task {params.message.taskId} was specified but does not exist'
207+
)
208+
)
203209

204210
# Build request context
205211
request_context = await self._request_context_builder.build(

tests/server/request_handlers/test_default_request_handler.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1779,3 +1779,85 @@ async def test_on_resubscribe_to_task_in_terminal_state(terminal_state):
17791779
in exc_info.value.error.message
17801780
)
17811781
mock_task_store.get.assert_awaited_once_with(task_id)
1782+
1783+
1784+
@pytest.mark.asyncio
1785+
async def test_on_message_send_task_id_provided_but_task_not_found():
1786+
"""Test on_message_send when taskId is provided but task doesn't exist."""
1787+
task_id = 'nonexistent_task'
1788+
mock_task_store = AsyncMock(spec=TaskStore)
1789+
1790+
request_handler = DefaultRequestHandler(
1791+
agent_executor=DummyAgentExecutor(), task_store=mock_task_store
1792+
)
1793+
1794+
params = MessageSendParams(
1795+
message=Message(
1796+
role=Role.user,
1797+
messageId='msg_nonexistent',
1798+
parts=[Part(root=TextPart(text='Hello'))],
1799+
taskId=task_id,
1800+
contextId='ctx1',
1801+
)
1802+
)
1803+
1804+
from a2a.utils.errors import ServerError
1805+
1806+
# Mock TaskManager.get_task to return None (task not found)
1807+
with patch(
1808+
'a2a.server.request_handlers.default_request_handler.TaskManager.get_task',
1809+
return_value=None,
1810+
):
1811+
with pytest.raises(ServerError) as exc_info:
1812+
await request_handler.on_message_send(
1813+
params, create_server_call_context()
1814+
)
1815+
1816+
assert isinstance(exc_info.value.error, TaskNotFoundError)
1817+
assert exc_info.value.error.message
1818+
assert (
1819+
f'Task {task_id} was specified but does not exist'
1820+
in exc_info.value.error.message
1821+
)
1822+
1823+
1824+
@pytest.mark.asyncio
1825+
async def test_on_message_send_stream_task_id_provided_but_task_not_found():
1826+
"""Test on_message_send_stream when taskId is provided but task doesn't exist."""
1827+
task_id = 'nonexistent_stream_task'
1828+
mock_task_store = AsyncMock(spec=TaskStore)
1829+
1830+
request_handler = DefaultRequestHandler(
1831+
agent_executor=DummyAgentExecutor(), task_store=mock_task_store
1832+
)
1833+
1834+
params = MessageSendParams(
1835+
message=Message(
1836+
role=Role.user,
1837+
messageId='msg_nonexistent_stream',
1838+
parts=[Part(root=TextPart(text='Hello'))],
1839+
taskId=task_id,
1840+
contextId='ctx1',
1841+
)
1842+
)
1843+
1844+
from a2a.utils.errors import ServerError
1845+
1846+
# Mock TaskManager.get_task to return None (task not found)
1847+
with patch(
1848+
'a2a.server.request_handlers.default_request_handler.TaskManager.get_task',
1849+
return_value=None,
1850+
):
1851+
with pytest.raises(ServerError) as exc_info:
1852+
# Need to consume the async generator to trigger the error
1853+
async for _ in request_handler.on_message_send_stream(
1854+
params, create_server_call_context()
1855+
):
1856+
pass
1857+
1858+
assert isinstance(exc_info.value.error, TaskNotFoundError)
1859+
assert exc_info.value.error.message
1860+
assert (
1861+
f'Task {task_id} was specified but does not exist'
1862+
in exc_info.value.error.message
1863+
)

0 commit comments

Comments
 (0)