fix: keep streamed text when a filter or provider sends non-string content (#28840)

A stream filter function, or a provider that puts something other than a string in a delta, makes the streaming handler concatenate a string with a non-string. That raises TypeError, and the broad handler wrapped around the whole per-chunk block swallows it at debug level and moves on. The chunk's text never reaches the message the user sees, and nothing above debug level says why.

The content and reasoning fields are now coerced to text once, where they are read off the delta, ahead of every consumer. The coercion is guarded on truthiness, so falsy values such as an empty list still skip the block exactly as before, and the accumulated content receives byte for byte what it received previously.

Checked against 14 delta shapes covering strings, empty values, numbers, booleans, None, lists, dicts and a content array: the truthiness gate and the accumulated content are identical before and after.
This commit is contained in:
Classic298
2026-08-23 21:35:53 +02:00
committed by GitHub
parent 603e85c569
commit ac091273b7
+6 -1
View File
@@ -5064,13 +5064,18 @@ async def streaming_chat_response_handler(response, ctx):
}
)
# content and reasoning deltas are raw JSON: a stream filter can make them any type
value = delta.get('content')
if value and not isinstance(value, str):
value = f'{value}'
reasoning_content = (
delta.get('reasoning_content')
or delta.get('reasoning')
or delta.get('thinking')
)
if reasoning_content and not isinstance(reasoning_content, str):
reasoning_content = f'{reasoning_content}'
reasoning_details = get_reasoning_details(delta)
reasoning_detail_items = (
[item for item in reasoning_details if isinstance(item, dict)]
@@ -5201,7 +5206,7 @@ async def streaming_chat_response_handler(response, ctx):
)
# closure-cell str += recopies per chunk; append + join once at read is O(n)
content_parts.append(value if isinstance(value, str) else f'{value}')
content_parts.append(value)
# Check if we're inside a tag-based block
# (reasoning, code_interpreter, or solution).