core/lmproto: allow null content on stream deltas

OpenAI-compatible and DeepSeek SSE chunks often set content and
reasoning_content to null; accept None so decode does not fail mid-stream.
This commit is contained in:
2026-07-15 14:21:50 +08:00
parent 553d491cbc
commit 366752efb9
2 changed files with 16 additions and 2 deletions
@@ -236,8 +236,9 @@ class StreamToolCallDelta(Struct):
class DeltaMessage(Struct): class DeltaMessage(Struct):
role: RoleAssistant | Unset = UNSET role: RoleAssistant | Unset = UNSET
content: str | Unset = UNSET # Providers often send content=null / reasoning_content=null on partial chunks.
reasoning_content: str | Unset = UNSET content: str | None | Unset = UNSET
reasoning_content: str | None | Unset = UNSET
tool_calls: list[StreamToolCallDelta] | Unset = UNSET tool_calls: list[StreamToolCallDelta] | Unset = UNSET
+13
View File
@@ -34,6 +34,19 @@ def test_sse_data_payload_json() -> None:
assert chunk.choices[0].delta.content == "hi" assert chunk.choices[0].delta.content == "hi"
def test_delta_accepts_null_content_and_reasoning() -> None:
"""DeepSeek / OpenAI often send content=null on reasoning-only or role chunks."""
payload = (
b'{"id":"1","object":"chat.completion.chunk","created":0,"model":"m",'
b'"choices":[{"index":0,"delta":{"role":"assistant","content":null,'
b'"reasoning_content":null},"finish_reason":null}]}'
)
chunk = msgspec_decode_chunk(payload)
delta = chunk.choices[0].delta
assert delta.content is None
assert delta.reasoning_content is None
def msgspec_decode_chunk(payload: bytes) -> ChatCompletionChunk: def msgspec_decode_chunk(payload: bytes) -> ChatCompletionChunk:
import msgspec import msgspec