diff --git a/tests/entrypoints/anthropic/test_anthropic_messages_conversion.py b/tests/entrypoints/anthropic/test_anthropic_messages_conversion.py index 21d5154c67..3edc09801e 100644 --- a/tests/entrypoints/anthropic/test_anthropic_messages_conversion.py +++ b/tests/entrypoints/anthropic/test_anthropic_messages_conversion.py @@ -996,3 +996,39 @@ class TestMessageStreamConverterToolUseContentBuffering: assert "text" in block_starts assert events[-1][0] == "message_stop" + + +class TestMessageStartIncludesTypeAndRole: + """Regression test for issue #45367: the streaming message_start event is + serialized with exclude_unset=True, which silently dropped the + default-valued ``type``/``role`` fields of the nested message object. + Strict Anthropic SDK clients (e.g. Claude Code) validate + ``message_start.message.type``/``role`` and reject the whole stream when + they are missing. + """ + + @pytest.mark.asyncio + async def test_message_start_contains_message_type_and_role(self): + async def sse_input(): + yield _make_stream_chunk( + delta=DeltaMessage(content="Hello"), + usage=UsageInfo( + prompt_tokens=20, + total_tokens=20, + completion_tokens=0, + ), + ) + yield _make_stream_chunk(finish_reason="stop") + yield "data: [DONE]" + + converter = _make_stream_converter() + output = [] + async for event in converter.message_stream_converter(sse_input()): + output.append(event) + + events = _parse_sse_events(output) + + assert events[0][0] == "message_start" + message = events[0][1]["message"] + assert message["type"] == "message" + assert message["role"] == "assistant" diff --git a/vllm/entrypoints/anthropic/serving.py b/vllm/entrypoints/anthropic/serving.py index 266a315421..3dce10695b 100644 --- a/vllm/entrypoints/anthropic/serving.py +++ b/vllm/entrypoints/anthropic/serving.py @@ -678,6 +678,13 @@ class AnthropicServingMessages(OpenAIServingChat): type="message_start", message=AnthropicMessagesResponse( id=origin_chunk.id, + # Set explicitly: this event is serialized + # with exclude_unset=True, which drops + # default-valued fields, while strict + # Anthropic SDK clients require + # message.type/role (issue #45367). + type="message", + role="assistant", content=[], model=origin_chunk.model, stop_reason=None,