Python: Refactoring and fix bug. AuthorRole instead of string literals. (#6391)

### Motivation and Context

<!-- Thank you for your contribution to the semantic-kernel repo!
Please help reviewers and future users, providing the following
information:
  1. Why is this change required?
  2. What problem does it solve?
  3. What scenario does it contribute to?
  4. If it fixes an open issue, please link to the issue here.
-->

There's an enum called `AuthorRole`. I replaced string literals with the
enum values. PyCharm highlights this in some cases: Expected type
'AuthorRole', got 'str' instead

I also fixed a bug in _function_invocation_filters_stream.py_ where the
argument name was wrong. `author="assistant"` instead of
`role="assistant"`

### Description

<!-- Describe your changes, the overall approach, the underlying design.
These notes will help understanding how your code works. Thanks! -->

### Contribution Checklist

<!-- Before submitting this PR, please make sure: -->

- [x] The code builds clean without any errors or warnings
- [x] The PR follows the [SK Contribution
Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md)
and the [pre-submission formatting
script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts)
raises no violations
- [x] All unit tests pass, and I have added new tests where possible
- [x] I didn't break anyone 😄

---------

Co-authored-by: Evan Mattson <[email protected]>
Co-authored-by: Eduard van Valkenburg <[email protected]>
This commit is contained in:
Stefan Muscalu
2024-06-04 07:09:00 +00:00
committed by GitHub
co-authored by Evan Mattson Eduard van Valkenburg
parent 2a7763aa3b
commit 8828b86fd8
14 changed files with 114 additions and 83 deletions
@@ -12,6 +12,7 @@ from semantic_kernel.connectors.ai.chat_completion_client_base import ChatComple
from semantic_kernel.connectors.ai.ollama.ollama_prompt_execution_settings import OllamaChatPromptExecutionSettings
from semantic_kernel.connectors.ai.ollama.utils import AsyncSession
from semantic_kernel.connectors.ai.text_completion_client_base import TextCompletionClientBase
from semantic_kernel.contents import AuthorRole
from semantic_kernel.contents.chat_history import ChatHistory
from semantic_kernel.contents.chat_message_content import ChatMessageContent
from semantic_kernel.contents.streaming_chat_message_content import StreamingChatMessageContent
@@ -66,7 +67,7 @@ class OllamaChatCompletion(TextCompletionClientBase, ChatCompletionClientBase):
ChatMessageContent(
inner_content=response_object,
ai_model_id=self.ai_model_id,
role="assistant",
role=AuthorRole.ASSISTANT,
content=response_object.get("message", {"content": None}).get("content", None),
)
]
@@ -105,7 +106,7 @@ class OllamaChatCompletion(TextCompletionClientBase, ChatCompletionClientBase):
break
yield [
StreamingChatMessageContent(
role="assistant",
role=AuthorRole.ASSISTANT,
choice_index=0,
inner_content=body,
ai_model_id=self.ai_model_id,
@@ -131,7 +132,7 @@ class OllamaChatCompletion(TextCompletionClientBase, ChatCompletionClientBase):
"""
if not settings.ai_model_id:
settings.ai_model_id = self.ai_model_id
settings.messages = [{"role": "user", "content": prompt}]
settings.messages = [{"role": AuthorRole.USER, "content": prompt}]
settings.stream = False
async with (
AsyncSession(self.session) as session,
@@ -165,7 +166,7 @@ class OllamaChatCompletion(TextCompletionClientBase, ChatCompletionClientBase):
"""
if not settings.ai_model_id:
settings.ai_model_id = self.ai_model_id
settings.messages = [{"role": "user", "content": prompt}]
settings.messages = [{"role": AuthorRole.USER, "content": prompt}]
settings.stream = True
async with (
AsyncSession(self.session) as session,
@@ -249,12 +249,12 @@ class OpenAIChatCompletionBase(OpenAIHandler, ChatCompletionClientBase):
def _chat_message_content_to_dict(self, message: "ChatMessageContent") -> dict[str, str | None]:
msg = super()._chat_message_content_to_dict(message)
if message.role == "assistant":
if message.role == AuthorRole.ASSISTANT:
if tool_calls := getattr(message, "tool_calls", None):
msg["tool_calls"] = [tool_call.model_dump() for tool_call in tool_calls]
if function_call := getattr(message, "function_call", None):
msg["function_call"] = function_call.model_dump_json()
if message.role == "tool":
if message.role == AuthorRole.TOOL:
if tool_call_id := getattr(message, "tool_call_id", None):
msg["tool_call_id"] = tool_call_id
if message.metadata and "function" in message.metadata:
@@ -6,6 +6,7 @@ from xml.etree.ElementTree import Element # nosec
from pydantic import field_validator
from semantic_kernel.contents.author_role import AuthorRole
from semantic_kernel.contents.const import FUNCTION_RESULT_CONTENT_TAG, TEXT_CONTENT_TAG
from semantic_kernel.contents.kernel_content import KernelContent
from semantic_kernel.contents.text_content import TextContent
@@ -104,8 +105,8 @@ class FunctionResultContent(KernelContent):
from semantic_kernel.contents.chat_message_content import ChatMessageContent
if unwrap:
return ChatMessageContent(role="tool", items=[self.result]) # type: ignore
return ChatMessageContent(role="tool", items=[self]) # type: ignore
return ChatMessageContent(role=AuthorRole.TOOL, items=[self.result]) # type: ignore
return ChatMessageContent(role=AuthorRole.TOOL, items=[self]) # type: ignore
def to_dict(self) -> dict[str, str]:
"""Convert the instance to a dictionary."""