mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-14 09:03:16 +00:00
Merge c166490bd3 into ff2709f5c3
This commit is contained in:
commit
25bf2ccda5
2 changed files with 41 additions and 5 deletions
|
|
@ -1535,8 +1535,8 @@ def _streamed_vllm_choice_fields(choices: Iterable[object]) -> Mapping[str, obje
|
|||
return MappingProxyType({field: streamed_values[field] for field in VLLM_CHOICE_FIELDS if field in present_fields})
|
||||
|
||||
|
||||
def _delta_reasoning_items(delta: object) -> Sequence[object]:
|
||||
items: Final = _field_of(delta, "reasoning_items")
|
||||
def _delta_reasoning_items(delta: object, field: str = "reasoning_items") -> Sequence[object]:
|
||||
items: Final = _field_of(delta, field)
|
||||
return cast(Sequence[object], items) if isinstance(items, list) else () # cast-ok: items forwarded verbatim
|
||||
|
||||
|
||||
|
|
@ -1547,8 +1547,8 @@ def _chunk_first_delta(chunk: object) -> object:
|
|||
return _field_of(cast(Sequence[object], choices)[0], "delta") # cast-ok: untyped chunk
|
||||
|
||||
|
||||
def _chunk_reasoning_items(chunk: object) -> Sequence[object]:
|
||||
return _delta_reasoning_items(_chunk_first_delta(chunk))
|
||||
def _chunk_reasoning_items(chunk: object, field: str = "reasoning_items") -> Sequence[object]:
|
||||
return _delta_reasoning_items(_chunk_first_delta(chunk), field)
|
||||
|
||||
|
||||
def _chunk_refusal(chunk: object) -> str:
|
||||
|
|
@ -1561,6 +1561,7 @@ _NON_TEXT_DELTA_FIELDS: Final = (
|
|||
"function_call",
|
||||
"reasoning_content",
|
||||
"reasoning_items",
|
||||
"reasoning_details",
|
||||
"thinking_blocks",
|
||||
"annotations",
|
||||
"audio",
|
||||
|
|
@ -1789,9 +1790,16 @@ def _assembled_message_fields(processor: ChunkProcessor, chunks: Sequence) -> It
|
|||
)
|
||||
citation_fields: Final = {"citations": _joined_streamed_citations(streamed_citations)} if streamed_citations else {}
|
||||
provider_annotation_fields: Final = {"annotations": list(provider_annotations)} if provider_annotations else {}
|
||||
# Keep every streamed reasoning_details entry in arrival order, as the
|
||||
# non-streaming response does. Do not merge by index: some providers
|
||||
# send whole entries that all have index 0.
|
||||
reasoning_details: Final = tuple(
|
||||
chain.from_iterable(_chunk_reasoning_items(chunk, "reasoning_details") for chunk in typed_chunks)
|
||||
)
|
||||
reasoning_detail_fields: Final = {"reasoning_details": list(reasoning_details)} if reasoning_details else {}
|
||||
combined_provider_fields: Final = {
|
||||
key: value
|
||||
for fields in (provider_annotation_fields, citation_fields, *provider_field_dicts)
|
||||
for fields in (provider_annotation_fields, citation_fields, *provider_field_dicts, reasoning_detail_fields)
|
||||
for key, value in fields.items()
|
||||
if key != "citation"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1233,6 +1233,34 @@ def test_stream_chunk_builder_tolerates_trailing_chunk_without_choices():
|
|||
assert response.choices[0].message.content == "Hello world"
|
||||
|
||||
|
||||
def test_stream_chunk_builder_keeps_reasoning_details_from_every_chunk():
|
||||
"""A streamed `reasoning_details` list must rebuild into the same
|
||||
`provider_specific_fields["reasoning_details"]` that a non-streaming
|
||||
response carries: every entry, in arrival order, not merged by `index`
|
||||
(Vercel AI Gateway sends whole entries that all have `index: 0`)."""
|
||||
text_entry: Final = {"type": "reasoning.text", "text": "step one", "index": 0}
|
||||
encrypted_entry: Final = {"type": "reasoning.encrypted", "data": "ENC-TWO", "index": 0}
|
||||
chunks: Final = [
|
||||
ModelResponseStream(
|
||||
model="m",
|
||||
choices=[
|
||||
StreamingChoices(index=0, delta=Delta(role="assistant", content="Hi", reasoning_details=[text_entry]))
|
||||
],
|
||||
),
|
||||
ModelResponseStream(
|
||||
model="m", choices=[StreamingChoices(index=0, delta=Delta(reasoning_details=[encrypted_entry]))]
|
||||
),
|
||||
ModelResponseStream(model="m", choices=[StreamingChoices(index=0, delta=Delta(content=" there"))]),
|
||||
]
|
||||
|
||||
response = stream_chunk_builder(chunks=chunks)
|
||||
|
||||
assert response is not None
|
||||
message = response.choices[0].message
|
||||
assert message.content == "Hi there"
|
||||
assert message.provider_specific_fields == {"reasoning_details": [text_entry, encrypted_entry]}
|
||||
|
||||
|
||||
def test_anthropic_speed_and_geo_survive_stream_assembly():
|
||||
"""Anthropic prices fast mode and non-global regions with a multiplier read off
|
||||
``usage.speed`` / ``usage.inference_geo``. Dropping them while reassembling a stream
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue