mirror of
https://github.com/BerriAI/litellm.git
synced 2025-04-26 11:14:04 +00:00
Return signature
on anthropic streaming + migrate to signature
field instead of signature_delta
[MINOR bump] (#9021)
* Fix missing signature_delta in thinking blocks when streaming from Claude 3.7 (#8797) Co-authored-by: Krish Dholakia <krrishdholakia@gmail.com> * test: update test to enforce signature found * feat(refactor-signature-param-to-be-'signature'-instead-of-'signature_delta'): keeps it in sync with anthropic * fix: fix linting error --------- Co-authored-by: Martin Krasser <krasserm@googlemail.com>
This commit is contained in:
parent
17efbf0ee9
commit
ec4f665e29
6 changed files with 19 additions and 10 deletions
|
@ -2983,7 +2983,7 @@ class BedrockConverseMessagesProcessor:
|
||||||
reasoning_content_blocks: List[BedrockContentBlock] = []
|
reasoning_content_blocks: List[BedrockContentBlock] = []
|
||||||
for thinking_block in thinking_blocks:
|
for thinking_block in thinking_blocks:
|
||||||
reasoning_text = thinking_block.get("thinking")
|
reasoning_text = thinking_block.get("thinking")
|
||||||
reasoning_signature = thinking_block.get("signature_delta")
|
reasoning_signature = thinking_block.get("signature")
|
||||||
text_block = BedrockConverseReasoningTextBlock(
|
text_block = BedrockConverseReasoningTextBlock(
|
||||||
text=reasoning_text or "",
|
text=reasoning_text or "",
|
||||||
)
|
)
|
||||||
|
|
|
@ -527,6 +527,7 @@ class ModelResponseIterator:
|
||||||
provider_specific_fields = {}
|
provider_specific_fields = {}
|
||||||
content_block = ContentBlockDelta(**chunk) # type: ignore
|
content_block = ContentBlockDelta(**chunk) # type: ignore
|
||||||
thinking_blocks: List[ChatCompletionThinkingBlock] = []
|
thinking_blocks: List[ChatCompletionThinkingBlock] = []
|
||||||
|
|
||||||
self.content_blocks.append(content_block)
|
self.content_blocks.append(content_block)
|
||||||
if "text" in content_block["delta"]:
|
if "text" in content_block["delta"]:
|
||||||
text = content_block["delta"]["text"]
|
text = content_block["delta"]["text"]
|
||||||
|
@ -544,13 +545,13 @@ class ModelResponseIterator:
|
||||||
provider_specific_fields["citation"] = content_block["delta"]["citation"]
|
provider_specific_fields["citation"] = content_block["delta"]["citation"]
|
||||||
elif (
|
elif (
|
||||||
"thinking" in content_block["delta"]
|
"thinking" in content_block["delta"]
|
||||||
or "signature_delta" == content_block["delta"]
|
or "signature" in content_block["delta"]
|
||||||
):
|
):
|
||||||
thinking_blocks = [
|
thinking_blocks = [
|
||||||
ChatCompletionThinkingBlock(
|
ChatCompletionThinkingBlock(
|
||||||
type="thinking",
|
type="thinking",
|
||||||
thinking=content_block["delta"].get("thinking"),
|
thinking=content_block["delta"].get("thinking") or "",
|
||||||
signature_delta=content_block["delta"].get("signature"),
|
signature=content_block["delta"].get("signature"),
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
provider_specific_fields["thinking_blocks"] = thinking_blocks
|
provider_specific_fields["thinking_blocks"] = thinking_blocks
|
||||||
|
|
|
@ -272,7 +272,7 @@ class AmazonConverseConfig(BaseConfig):
|
||||||
optional_params["temperature"] = value
|
optional_params["temperature"] = value
|
||||||
if param == "top_p":
|
if param == "top_p":
|
||||||
optional_params["topP"] = value
|
optional_params["topP"] = value
|
||||||
if param == "tools":
|
if param == "tools" and isinstance(value, list):
|
||||||
optional_params = self._add_tools_to_optional_params(
|
optional_params = self._add_tools_to_optional_params(
|
||||||
optional_params=optional_params, tools=value
|
optional_params=optional_params, tools=value
|
||||||
)
|
)
|
||||||
|
@ -598,7 +598,7 @@ class AmazonConverseConfig(BaseConfig):
|
||||||
if _text is not None:
|
if _text is not None:
|
||||||
_thinking_block["thinking"] = _text
|
_thinking_block["thinking"] = _text
|
||||||
if _signature is not None:
|
if _signature is not None:
|
||||||
_thinking_block["signature_delta"] = _signature
|
_thinking_block["signature"] = _signature
|
||||||
thinking_blocks_list.append(_thinking_block)
|
thinking_blocks_list.append(_thinking_block)
|
||||||
return thinking_blocks_list
|
return thinking_blocks_list
|
||||||
|
|
||||||
|
|
|
@ -360,7 +360,7 @@ class ChatCompletionCachedContent(TypedDict):
|
||||||
class ChatCompletionThinkingBlock(TypedDict, total=False):
|
class ChatCompletionThinkingBlock(TypedDict, total=False):
|
||||||
type: Required[Literal["thinking"]]
|
type: Required[Literal["thinking"]]
|
||||||
thinking: str
|
thinking: str
|
||||||
signature_delta: str
|
signature: str
|
||||||
cache_control: Optional[Union[dict, ChatCompletionCachedContent]]
|
cache_control: Optional[Union[dict, ChatCompletionCachedContent]]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1188,18 +1188,20 @@ def test_anthropic_thinking_output(model):
|
||||||
assert isinstance(resp.choices[0].message.thinking_blocks, list)
|
assert isinstance(resp.choices[0].message.thinking_blocks, list)
|
||||||
assert len(resp.choices[0].message.thinking_blocks) > 0
|
assert len(resp.choices[0].message.thinking_blocks) > 0
|
||||||
|
|
||||||
|
assert resp.choices[0].message.thinking_blocks[0]["signature"] is not None
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"model",
|
"model",
|
||||||
[
|
[
|
||||||
"anthropic/claude-3-7-sonnet-20250219",
|
"anthropic/claude-3-7-sonnet-20250219",
|
||||||
"bedrock/us.anthropic.claude-3-7-sonnet-20250219-v1:0",
|
# "bedrock/us.anthropic.claude-3-7-sonnet-20250219-v1:0",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_anthropic_thinking_output_stream(model):
|
def test_anthropic_thinking_output_stream(model):
|
||||||
# litellm.set_verbose = True
|
# litellm.set_verbose = True
|
||||||
try:
|
try:
|
||||||
litellm._turn_on_debug()
|
# litellm._turn_on_debug()
|
||||||
resp = litellm.completion(
|
resp = litellm.completion(
|
||||||
model=model,
|
model=model,
|
||||||
messages=[{"role": "user", "content": "Tell me a joke."}],
|
messages=[{"role": "user", "content": "Tell me a joke."}],
|
||||||
|
@ -1209,6 +1211,7 @@ def test_anthropic_thinking_output_stream(model):
|
||||||
)
|
)
|
||||||
|
|
||||||
reasoning_content_exists = False
|
reasoning_content_exists = False
|
||||||
|
signature_block_exists = False
|
||||||
for chunk in resp:
|
for chunk in resp:
|
||||||
print(f"chunk 2: {chunk}")
|
print(f"chunk 2: {chunk}")
|
||||||
if (
|
if (
|
||||||
|
@ -1220,8 +1223,11 @@ def test_anthropic_thinking_output_stream(model):
|
||||||
and isinstance(chunk.choices[0].delta.reasoning_content, str)
|
and isinstance(chunk.choices[0].delta.reasoning_content, str)
|
||||||
):
|
):
|
||||||
reasoning_content_exists = True
|
reasoning_content_exists = True
|
||||||
break
|
print(chunk.choices[0].delta.thinking_blocks[0])
|
||||||
|
if chunk.choices[0].delta.thinking_blocks[0].get("signature"):
|
||||||
|
signature_block_exists = True
|
||||||
assert reasoning_content_exists
|
assert reasoning_content_exists
|
||||||
|
assert signature_block_exists
|
||||||
except litellm.Timeout:
|
except litellm.Timeout:
|
||||||
pytest.skip("Model is timing out")
|
pytest.skip("Model is timing out")
|
||||||
|
|
||||||
|
|
|
@ -4084,6 +4084,7 @@ def test_reasoning_content_completion(model):
|
||||||
)
|
)
|
||||||
|
|
||||||
reasoning_content_exists = False
|
reasoning_content_exists = False
|
||||||
|
signature_delta_exists = False
|
||||||
for chunk in resp:
|
for chunk in resp:
|
||||||
print(f"chunk 2: {chunk}")
|
print(f"chunk 2: {chunk}")
|
||||||
if (
|
if (
|
||||||
|
@ -4118,3 +4119,4 @@ def test_is_delta_empty():
|
||||||
audio=None,
|
audio=None,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue