This commit is contained in:
dengzi 2026-11-07 02:21:42 +00:00 • committed by GitHub
commit bd6ee71110
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 31 additions and 2 deletions

View file

@ -1812,7 +1812,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",
}
)
@ -1892,7 +1898,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:

View file

@ -882,6 +882,11 @@ class ChatCompletionFileObject(TypedDict):
file: ChatCompletionFileObjectFile
class ChatCompletionRefusalObject(TypedDict):
type: ReadOnly[Literal["refusal"]]
refusal: ReadOnly[str]
OpenAIMessageContentListBlock = (
ChatCompletionTextObject
| ChatCompletionImageObject
@ -889,6 +894,7 @@ OpenAIMessageContentListBlock = (
| ChatCompletionDocumentObject
| ChatCompletionVideoObject
| ChatCompletionFileObject
| ChatCompletionRefusalObject
)
OpenAIMessageContent = str | Iterable[OpenAIMessageContentListBlock]

View file

@ -3625,3 +3625,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
)