mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-14 09:03:16 +00:00
fix(token_counter): count assistant refusal content parts
token_counter raised UnsupportedContentTypeError on the refusal part that the OpenAI SDK documents for assistant messages, so POST /utils/token_counter answered 500 for any history containing one. A refusal now counts as text like the text part it replaces, and the content block union carries it.
This commit is contained in:
parent
20cb3ea439
commit
ba4f91b5d1
3 changed files with 31 additions and 2 deletions
|
|
@ -1691,7 +1691,13 @@ def _count_anthropic_content(
|
|||
|
||||
|
||||
_TEXT_FIELD_BY_BLOCK_TYPE: Final = MappingProxyType(
|
||||
{"text": "text", "thinking": "thinking", "redacted_thinking": "thinking", "compaction": "content"}
|
||||
{
|
||||
"text": "text",
|
||||
"thinking": "thinking",
|
||||
"redacted_thinking": "thinking",
|
||||
"compaction": "content",
|
||||
"refusal": "refusal",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -1771,7 +1777,7 @@ def _count_content_list(
|
|||
f"Invalid content item type: {content_type}. "
|
||||
f"Expected str or dict with 'type' field "
|
||||
f"(text, image_url, image, document, file, tool_use, tool_result, thinking, redacted_thinking, "
|
||||
f"compaction, tool_reference, search_result)."
|
||||
f"compaction, tool_reference, search_result, refusal)."
|
||||
)
|
||||
return num_tokens
|
||||
except Exception as e:
|
||||
|
|
|
|||
|
|
@ -881,6 +881,11 @@ class ChatCompletionFileObject(TypedDict):
|
|||
file: ChatCompletionFileObjectFile
|
||||
|
||||
|
||||
class ChatCompletionRefusalObject(TypedDict):
|
||||
type: ReadOnly[Literal["refusal"]]
|
||||
refusal: ReadOnly[str]
|
||||
|
||||
|
||||
OpenAIMessageContentListBlock = (
|
||||
ChatCompletionTextObject
|
||||
| ChatCompletionImageObject
|
||||
|
|
@ -888,6 +893,7 @@ OpenAIMessageContentListBlock = (
|
|||
| ChatCompletionDocumentObject
|
||||
| ChatCompletionVideoObject
|
||||
| ChatCompletionFileObject
|
||||
| ChatCompletionRefusalObject
|
||||
)
|
||||
|
||||
OpenAIMessageContent = str | Iterable[OpenAIMessageContentListBlock]
|
||||
|
|
|
|||
|
|
@ -3626,3 +3626,20 @@ def test_openai_model_check_holds_while_openai_models_are_registered_concurrentl
|
|||
registering.result()
|
||||
finally:
|
||||
litellm.open_ai_chat_completion_models.difference_update(registered)
|
||||
|
||||
|
||||
def test_refusal_content_part_counts_as_the_text_it_replaces() -> None:
|
||||
"""An assistant refusal part is a documented OpenAI content block, so it must count instead of raising"""
|
||||
with_text = [
|
||||
{"role": "user", "content": "A request"},
|
||||
{"role": "assistant", "content": [{"type": "text", "text": "I cannot help with that request."}]},
|
||||
{"role": "user", "content": "Please suggest a safe alternative."},
|
||||
]
|
||||
with_refusal = [
|
||||
{"role": "user", "content": "A request"},
|
||||
{"role": "assistant", "content": [{"type": "refusal", "refusal": "I cannot help with that request."}]},
|
||||
{"role": "user", "content": "Please suggest a safe alternative."},
|
||||
]
|
||||
assert token_counter_old(model="gpt-4o", messages=with_refusal) == token_counter_old(
|
||||
model="gpt-4o", messages=with_text
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue