mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-14 09:03:16 +00:00
fix(responses): keep overlong system prompts in input on the chat to responses bridge
This commit is contained in:
parent
7e4ad6eb33
commit
69c9132005
2 changed files with 49 additions and 1 deletions
|
|
@ -102,6 +102,7 @@ _CHAT_COMPLETION_FIELDS: Final = frozenset((*ModelResponse.model_fields, "usage"
|
|||
_RESPONSES_API_ONLY_FIELDS: Final = frozenset((*Response.model_fields, *ResponsesAPIResponse.model_fields)) - frozenset(
|
||||
ChatCompletion.model_fields
|
||||
)
|
||||
_RESPONSES_INSTRUCTIONS_MAX_LENGTH: Final = 1_048_576
|
||||
|
||||
|
||||
def _bridged_prompt_cache_breakpoint(marker: object, drop_params: bool, target_trims_breakpoints: bool) -> object:
|
||||
|
|
@ -1182,9 +1183,12 @@ class LiteLLMResponsesTransformationHandler(CompletionTransformationBridge):
|
|||
)
|
||||
# Keep the system text in input instead of instructions when the Responses API needs it there.
|
||||
# It rejects an empty input, and json_object requires the word "json" in input, ignoring instructions.
|
||||
# It also caps instructions at 1,048,576 characters, counted here in UTF-8 bytes to stay on the safe side.
|
||||
typed_optional_params: Final = cast("Mapping[str, object]", optional_params) # cast-ok: untyped dict
|
||||
system_goes_in_input: Final = converted_instructions is not None and (
|
||||
not converted_input_items or _payload_type(typed_optional_params.get("response_format")) == "json_object"
|
||||
not converted_input_items
|
||||
or _payload_type(typed_optional_params.get("response_format")) == "json_object"
|
||||
or len(converted_instructions.encode("utf-8")) > _RESPONSES_INSTRUCTIONS_MAX_LENGTH
|
||||
)
|
||||
target_input_items: Final = (
|
||||
_without_audio_input_parts(converted_input_items)
|
||||
|
|
|
|||
|
|
@ -1901,6 +1901,50 @@ def test_transform_request_json_object_keeps_system_prompt_where_the_json_word_c
|
|||
assert (result["input"], result.get("instructions")) == (expected_input, expected_instructions), result
|
||||
|
||||
|
||||
def _system_input_item(system_prompt: str) -> dict:
|
||||
return {
|
||||
"type": "message",
|
||||
"role": "system",
|
||||
"content": [{"type": "input_text", "text": system_prompt}],
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("system_prompt", "expected_input", "expected_instructions"),
|
||||
[
|
||||
("You are a helpful assistant.", [_PLAIN_USER_ITEM], "You are a helpful assistant."),
|
||||
("a" * 1_048_576, [_PLAIN_USER_ITEM], "a" * 1_048_576),
|
||||
("a" * 1_048_577, [_system_input_item("a" * 1_048_577), _PLAIN_USER_ITEM], None),
|
||||
("é" * 524_289, [_system_input_item("é" * 524_289), _PLAIN_USER_ITEM], None),
|
||||
],
|
||||
ids=[
|
||||
"short_system_stays_in_instructions",
|
||||
"system_at_cap_stays_in_instructions",
|
||||
"system_over_cap_moves_to_input",
|
||||
"multibyte_system_over_cap_in_bytes_moves_to_input",
|
||||
],
|
||||
)
|
||||
def test_transform_request_overlong_system_prompt_moves_to_input(system_prompt, expected_input, expected_instructions):
|
||||
"""Overlong system prompts go in input, since OpenAI caps instructions at 1,048,576 (#50243).
|
||||
|
||||
The cap is measured in UTF-8 bytes, so a prompt under the cap in characters still moves
|
||||
to input when its byte length is over it.
|
||||
"""
|
||||
result = LiteLLMResponsesTransformationHandler().transform_request(
|
||||
model="openai/gpt-6.1-terra",
|
||||
messages=[
|
||||
{"role": "system", "content": system_prompt},
|
||||
{"role": "user", "content": "List three colors."},
|
||||
],
|
||||
optional_params={},
|
||||
litellm_params={},
|
||||
headers={},
|
||||
litellm_logging_obj=Mock(),
|
||||
)
|
||||
|
||||
assert (result["input"], result.get("instructions")) == (expected_input, expected_instructions), result
|
||||
|
||||
|
||||
def test_transform_request_single_char_keys_not_matched():
|
||||
"""Test that single-character keys are not incorrectly matched to 'metadata' or 'previous_response_id'
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue