fix: omit null optional fields from task result payloads (#2809)
Co-authored-by: Sheldon <neooosky@gmail.com>
This commit is contained in:
parent
494eb11d36
commit
2309e5ef97
2 changed files with 31 additions and 2 deletions
|
|
@ -129,9 +129,15 @@ class TaskResultHandler:
|
|||
# The stored result contains the actual payload data
|
||||
# Per spec: tasks/result MUST include _meta with related-task metadata
|
||||
related_task = RelatedTaskMetadata(taskId=task_id)
|
||||
related_task_meta: dict[str, Any] = {RELATED_TASK_METADATA_KEY: related_task.model_dump(by_alias=True)}
|
||||
related_task_meta: dict[str, Any] = {
|
||||
RELATED_TASK_METADATA_KEY: related_task.model_dump(
|
||||
by_alias=True,
|
||||
mode="json",
|
||||
exclude_none=True,
|
||||
)
|
||||
}
|
||||
if result is not None:
|
||||
result_data = result.model_dump(by_alias=True)
|
||||
result_data = result.model_dump(by_alias=True, mode="json", exclude_none=True)
|
||||
existing_meta: dict[str, Any] = result_data.get("_meta") or {}
|
||||
result_data["_meta"] = {**existing_meta, **related_task_meta}
|
||||
return GetTaskPayloadResult.model_validate(result_data)
|
||||
|
|
|
|||
|
|
@ -67,6 +67,29 @@ async def test_handle_returns_result_for_completed_task(
|
|||
assert "io.modelcontextprotocol/related-task" in response.meta
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_handle_omits_none_fields_from_completed_task_payload(
|
||||
store: InMemoryTaskStore, queue: InMemoryTaskMessageQueue, handler: TaskResultHandler
|
||||
) -> None:
|
||||
"""Test task result payloads omit optional None fields instead of serializing null."""
|
||||
task = await store.create_task(TaskMetadata(ttl=60000), task_id="test-task")
|
||||
result = CallToolResult(content=[TextContent(type="text", text="Done!")])
|
||||
await store.store_result(task.taskId, result)
|
||||
await store.update_task(task.taskId, status="completed")
|
||||
|
||||
mock_session = Mock()
|
||||
mock_session.send_message = AsyncMock()
|
||||
|
||||
request = GetTaskPayloadRequest(params=GetTaskPayloadRequestParams(taskId=task.taskId))
|
||||
response = await handler.handle(request, mock_session, "req-1")
|
||||
|
||||
payload = response.model_dump(by_alias=True, mode="json")
|
||||
assert payload["content"] == [{"type": "text", "text": "Done!"}]
|
||||
assert "annotations" not in payload["content"][0]
|
||||
assert "_meta" not in payload["content"][0]
|
||||
assert "io.modelcontextprotocol/related-task" in payload["_meta"]
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_handle_raises_for_nonexistent_task(
|
||||
store: InMemoryTaskStore, queue: InMemoryTaskMessageQueue, handler: TaskResultHandler
|
||||
|
|
|
|||
Loading…
Reference in a new issue