Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,11 @@
# map finish reasons from Anthropic to Semantic Kernel
ANTHROPIC_TO_SEMANTIC_KERNEL_FINISH_REASON_MAP = {
"end_turn": SemanticKernelFinishReason.STOP,
"stop_sequence": SemanticKernelFinishReason.STOP,
"max_tokens": SemanticKernelFinishReason.LENGTH,
"model_context_window_exceeded": SemanticKernelFinishReason.LENGTH,
"tool_use": SemanticKernelFinishReason.TOOL_CALLS,
"refusal": SemanticKernelFinishReason.CONTENT_FILTER,
}

logger: logging.Logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -274,7 +277,7 @@ def _create_chat_message_content(

finish_reason = None
if response.stop_reason:
finish_reason = ANTHROPIC_TO_SEMANTIC_KERNEL_FINISH_REASON_MAP[response.stop_reason]
finish_reason = ANTHROPIC_TO_SEMANTIC_KERNEL_FINISH_REASON_MAP.get(response.stop_reason)

return ChatMessageContent(
inner_content=response,
Expand Down Expand Up @@ -312,7 +315,7 @@ def _create_streaming_chat_message_content(
)
)
elif isinstance(stream_event, RawMessageDeltaEvent):
finish_reason = ANTHROPIC_TO_SEMANTIC_KERNEL_FINISH_REASON_MAP[str(stream_event.delta.stop_reason)]
finish_reason = ANTHROPIC_TO_SEMANTIC_KERNEL_FINISH_REASON_MAP.get(str(stream_event.delta.stop_reason))
usage = _get_completion_usage(stream_event.usage)
start_usage = metadata.get("usage") if metadata else None
if getattr(stream_event.usage, "input_tokens", None) is None and isinstance(start_usage, CompletionUsage):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from semantic_kernel.contents.chat_message_content import ChatMessageContent, FunctionCallContent, TextContent
from semantic_kernel.contents.streaming_chat_message_content import StreamingChatMessageContent
from semantic_kernel.contents.utils.author_role import AuthorRole
from semantic_kernel.contents.utils.finish_reason import FinishReason
from semantic_kernel.exceptions import (
ServiceInitializationError,
ServiceInvalidExecutionSettingsError,
Expand Down Expand Up @@ -666,3 +667,40 @@ async def async_generator():
gen_ai_attributes.INPUT_TOKENS: 130,
gen_ai_attributes.OUTPUT_TOKENS: 7,
}


@pytest.mark.parametrize(
("stop_reason", "finish_reason"),
[
("end_turn", FinishReason.STOP),
("stop_sequence", FinishReason.STOP),
("max_tokens", FinishReason.LENGTH),
("model_context_window_exceeded", FinishReason.LENGTH),
("tool_use", FinishReason.TOOL_CALLS),
("refusal", FinishReason.CONTENT_FILTER),
("pause_turn", None),
],
)
def test_stop_reason_maps_to_finish_reason(anthropic_unit_test_env, stop_reason, finish_reason) -> None:
chat_completion = AnthropicChatCompletion()
message = Message(
id="msg_1",
type="message",
role="assistant",
model="claude-sonnet-4-5",
content=[TextBlock(type="text", text="Hello")],
stop_reason=stop_reason,
stop_sequence=None,
usage=Usage(input_tokens=1, output_tokens=1),
)
delta_event = RawMessageDeltaEvent(
type="message_delta",
delta=Delta(stop_reason=stop_reason, stop_sequence=None),
usage=MessageDeltaUsage(output_tokens=1),
)

content = chat_completion._create_chat_message_content(message, {})
streaming_content = chat_completion._create_streaming_chat_message_content(delta_event)

assert content.finish_reason == finish_reason
assert streaming_content.finish_reason == finish_reason
Loading