test(models): cover Chat Completions reasoning fallback

Cover streaming and complete messages, legacy-field precedence, empty or missing reasoning, and encrypted-reasoning filtering. Document the transport contract.

Validation: transport, Responses architecture, encrypted-reasoning, and refusal suites passed (126 tests); git diff --check passed.
This commit is contained in:
Alessandro 2026-09-30 16:47:56 +02:00
parent 9aca3adbb8
commit 2715fed8f8
2 changed files with 21 additions and 0 deletions

View file

@ -45,6 +45,7 @@
- Serialize synthesized Responses function-call JSON with literal Unicode so streamed raw-response logs preserve tool arguments.
- Preserve provider-state metadata when Responses API calls succeed, and fall back to local replay when provider state is unsupported.
- Keep prompt-cache markers only for providers that accept them.
- Chat Completions parsing prefers `reasoning_content` and falls back to `reasoning` for both streaming deltas and complete messages, preserving response content and applying the same encrypted-reasoning filter. Verify with `test_chat_reasoning_field_fallback` in `tests/test_stream_tool_early_stop.py`.
- Automatic `cache_control` marker placement is provider-gated; the OpenAI/Codex Responses configuration bypasses it. Skipping a marker target never removes its message, tool call, or reasoning content. Responses `phase: commentary`, encrypted reasoning, native replay, and request flags remain owned by their Responses paths.
- For supported Chat providers, mark the last leading system/developer message and the last two nonempty assistant messages. Retain the previous assistant boundary as the conversation grows; leave user/tool tails containing rebuilt extras unmarked. Before the first assistant message, cache only the leading context. Do not add markers to empty assistant content or thinking/redacted-thinking blocks. Automatic placement uses at most three message breakpoints, leaving one for tool definitions; this is not a limit on conversation messages or native tool calls. Do not mutate caller messages or stored history.

View file

@ -1444,6 +1444,26 @@ def test_responses_fallback_on_untyped_input_item_rejection():
assert policy.mode is litellm_transport.TransportMode.CHAT_COMPLETIONS
@pytest.mark.parametrize("source", ["delta", "message"])
@pytest.mark.parametrize(
("fields", "expected"),
[
({"reasoning_content": "legacy"}, "legacy"),
({"reasoning": "fallback"}, "fallback"),
({"reasoning_content": "legacy", "reasoning": "fallback"}, "legacy"),
({"reasoning_content": "", "reasoning": "fallback"}, "fallback"),
({"reasoning": "summary__ENCRYPTED_REASONING__opaque"}, "summary"),
({}, ""),
],
)
def test_chat_reasoning_field_fallback(source, fields, expected):
parsed = litellm_transport.ChatCompletionsTransport.parse(
{"choices": [{source: {"content": "answer", **fields}}]}
)
assert parsed == {"reasoning_delta": expected, "response_delta": "answer"}
def test_responses_response_parser_extracts_text_reasoning_and_function_calls():
text_response = {
"output": [