mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-06 02:48:13 +00:00
Merge f7d6bb579d into ed4caebb65
This commit is contained in:
commit
c3dab017be
3 changed files with 28 additions and 7 deletions
|
|
@ -55,6 +55,7 @@ FUNCTION_CALL_ATTRIBUTE: Final = "function_call"
|
|||
_SYNC_ITER_EXHAUSTED: Final = object()
|
||||
|
||||
_GCHUNK_FIELDS: Final[frozenset] = frozenset(GChunk.__annotations__)
|
||||
_GCHUNK_REQUIRED_FIELDS: Final[frozenset] = frozenset(GChunk.__required_keys__)
|
||||
_USAGE_COST_HEADER_PROVIDERS: Final[frozenset[str]] = frozenset({LlmProviders.OPENROUTER.value})
|
||||
|
||||
|
||||
|
|
@ -2467,7 +2468,7 @@ def generic_chunk_has_all_required_fields(chunk: dict) -> bool:
|
|||
:param chunk: The dictionary to check.
|
||||
:return: True if all required fields are present, False otherwise.
|
||||
"""
|
||||
return all(key in _GCHUNK_FIELDS for key in chunk)
|
||||
return _GCHUNK_REQUIRED_FIELDS <= chunk.keys() <= _GCHUNK_FIELDS
|
||||
|
||||
|
||||
def convert_generic_chunk_to_model_response_stream(
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ from litellm.litellm_core_utils.streaming_handler import (
|
|||
CustomStreamWrapper,
|
||||
_ProviderChunkEarlyReturn,
|
||||
_ProviderChunkParsed,
|
||||
convert_generic_chunk_to_model_response_stream,
|
||||
generic_chunk_has_all_required_fields,
|
||||
)
|
||||
from litellm.types.utils import (
|
||||
CompletionTokensDetailsWrapper,
|
||||
|
|
@ -4985,6 +4987,24 @@ async def test_async_stream_without_usage_counts_tokens_off_the_event_loop():
|
|||
assert_loop_stayed_free(took, lags)
|
||||
|
||||
|
||||
def test_generic_chunk_predicate_rejects_partial_chunk():
|
||||
partial_chunk = {"is_finished": False}
|
||||
assert generic_chunk_has_all_required_fields(partial_chunk) is False
|
||||
|
||||
full_chunk = {
|
||||
"text": "hello",
|
||||
"is_finished": True,
|
||||
"finish_reason": "stop",
|
||||
"usage": None,
|
||||
"index": 0,
|
||||
}
|
||||
assert generic_chunk_has_all_required_fields(full_chunk) is True
|
||||
|
||||
stream = convert_generic_chunk_to_model_response_stream(full_chunk)
|
||||
assert stream.choices[0].delta.content == "hello"
|
||||
assert stream.finish_reason == "stop"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("sync_mode", [True, False])
|
||||
@pytest.mark.asyncio
|
||||
async def test_openai_stream_relays_the_served_service_tier_on_every_chunk_including_usage(
|
||||
|
|
|
|||
|
|
@ -127,10 +127,11 @@ def test_gchunk_fields_is_frozenset():
|
|||
|
||||
|
||||
def test_generic_chunk_has_all_required_fields_uses_module_constant(monkeypatch):
|
||||
"""generic_chunk_has_all_required_fields must use _GCHUNK_FIELDS, not __annotations__.
|
||||
"""generic_chunk_has_all_required_fields must use the module constants.
|
||||
|
||||
The check semantics: every key in `chunk` must be a known GChunk field.
|
||||
This identifies GChunk-shaped dicts (all keys are valid GChunk fields).
|
||||
The check semantics: every required GChunk field must be present in `chunk`
|
||||
and every key must be a known GChunk field. Unknown keys and missing
|
||||
required fields both reject the chunk.
|
||||
"""
|
||||
valid_chunk = _make_generic_chunk("hello")
|
||||
assert generic_chunk_has_all_required_fields(valid_chunk) is True
|
||||
|
|
@ -141,10 +142,9 @@ def test_generic_chunk_has_all_required_fields_uses_module_constant(monkeypatch)
|
|||
extra_key_chunk["unknown_extra_key"] = "value"
|
||||
assert generic_chunk_has_all_required_fields(extra_key_chunk) is False
|
||||
|
||||
# A dict with only known GChunk fields but fewer keys still passes because
|
||||
# all its keys are valid (subset of GChunk fields).
|
||||
# A dict missing required fields is rejected, even if every key it has is valid.
|
||||
partial_chunk = {"text": "hi", "is_finished": False}
|
||||
assert generic_chunk_has_all_required_fields(partial_chunk) is True
|
||||
assert generic_chunk_has_all_required_fields(partial_chunk) is False
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue