mirror of
https://github.com/microsoft/semantic-kernel.git
synced 2026-10-12 02:19:06 +00:00
Python: Relax Agent Invocation Methods to Allow Positional or Keyword Arguments for messages (#12248)
### Motivation and Context
This PR relaxes the API signatures of all agent invocation methods
(`get_response`, `invoke`, `invoke_stream`) by changing the `messages`
parameter from keyword-only to positional-or-keyword. This enhances
ergonomics and Pythonic usability by allowing callers to pass messages
either positionally or as a keyword argument:
```python
agent.get_response("Why is the sky blue?")
agent.get_response(messages="Why is the sky blue?")
```
With our current use of **kwargs, it is possible to explicitly pass None
for messages (like `agent.get_response(messages=None)`). However, this
does not feel idiomatic in Python. If a caller wishes to invoke the
agent on an existing thread (which already contains all relevant
context), it is more natural and Pythonic to simply write:
```python
response = await agent.get_response()
```
This change makes the API more user-friendly, and removes unnecessary
verbosity when no new messages need to be provided.
Impact
- Backward compatible for all previous usage.
- Enables concise and intuitive API calls for primary message arguments.
- Subclasses overriding the prior keyword-only signature will continue
to work at runtime, but static type-checkers may require updating their
signatures to match the new base definition.
- No runtime breaking changes are expected.
| Scenario | Breaks at runtime? | Breaks at type-check? | Notes |
|----------------------------------|----------------------|-------------------------|--------------------------------------------------|
| Subclass w/keyword-only | No | Yes | Type checker error, but runtime
OK |
| Subclass matching base | No | No | Fine |
| Calls expecting keyword-only | No | No | Fine |
| Calls expecting positional | No (now allowed) | No | Improved
ergonomics |
| Decorators relying on kw-only | No | No (unless strict sig) | Only if
decorator is brittle, rare |
| Code generation/docs | No | No | Needs updating docs, not an actual
code break |
| Reflection-based invocation | No | No | Slight difference in behavior,
but not breaking |
Documentation and usage examples will be updated to reflect the improved
invocation style.
<!-- 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.
-->
### Description
Relaxes the API signatures of all agent invocation methods.
<!-- 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 😄
This commit is contained in:
@@ -306,8 +306,8 @@ class Agent(KernelBaseModel, ABC):
|
||||
@abstractmethod
|
||||
def get_response(
|
||||
self,
|
||||
*,
|
||||
messages: str | ChatMessageContent | list[str | ChatMessageContent] | None = None,
|
||||
*,
|
||||
thread: AgentThread | None = None,
|
||||
**kwargs,
|
||||
) -> Awaitable[AgentResponseItem[ChatMessageContent]]:
|
||||
@@ -336,8 +336,8 @@ class Agent(KernelBaseModel, ABC):
|
||||
@abstractmethod
|
||||
def invoke(
|
||||
self,
|
||||
*,
|
||||
messages: str | ChatMessageContent | list[str | ChatMessageContent] | None = None,
|
||||
*,
|
||||
thread: AgentThread | None = None,
|
||||
on_intermediate_message: Callable[[ChatMessageContent], Awaitable[None]] | None = None,
|
||||
**kwargs,
|
||||
@@ -367,8 +367,8 @@ class Agent(KernelBaseModel, ABC):
|
||||
@abstractmethod
|
||||
def invoke_stream(
|
||||
self,
|
||||
*,
|
||||
messages: str | ChatMessageContent | list[str | ChatMessageContent] | None = None,
|
||||
*,
|
||||
thread: AgentThread | None = None,
|
||||
on_intermediate_message: Callable[[ChatMessageContent], Awaitable[None]] | None = None,
|
||||
**kwargs,
|
||||
|
||||
@@ -135,6 +135,7 @@ class AutoGenConversableAgent(Agent):
|
||||
async def get_response(
|
||||
self,
|
||||
messages: str | ChatMessageContent | list[str | ChatMessageContent] | None = None,
|
||||
*,
|
||||
thread: AgentThread | None = None,
|
||||
**kwargs: Any,
|
||||
) -> AgentResponseItem[ChatMessageContent]:
|
||||
@@ -170,8 +171,8 @@ class AutoGenConversableAgent(Agent):
|
||||
@override
|
||||
async def invoke(
|
||||
self,
|
||||
*,
|
||||
messages: str | ChatMessageContent | list[str | ChatMessageContent] | None = None,
|
||||
*,
|
||||
thread: AgentThread | None = None,
|
||||
recipient: "AutoGenConversableAgent | None" = None,
|
||||
clear_history: bool = True,
|
||||
@@ -254,8 +255,8 @@ class AutoGenConversableAgent(Agent):
|
||||
@override
|
||||
def invoke_stream(
|
||||
self,
|
||||
*,
|
||||
messages: str | ChatMessageContent | list[str | ChatMessageContent] | None = None,
|
||||
*,
|
||||
thread: AgentThread | None = None,
|
||||
kernel: "Kernel | None" = None,
|
||||
arguments: KernelArguments | None = None,
|
||||
|
||||
@@ -606,8 +606,8 @@ class AzureAIAgent(DeclarativeSpecMixin, Agent):
|
||||
@override
|
||||
async def get_response(
|
||||
self,
|
||||
*,
|
||||
messages: str | ChatMessageContent | list[str | ChatMessageContent] | None = None,
|
||||
*,
|
||||
thread: AgentThread | None = None,
|
||||
arguments: KernelArguments | None = None,
|
||||
kernel: Kernel | None = None,
|
||||
@@ -710,8 +710,8 @@ class AzureAIAgent(DeclarativeSpecMixin, Agent):
|
||||
@override
|
||||
async def invoke(
|
||||
self,
|
||||
*,
|
||||
messages: str | ChatMessageContent | list[str | ChatMessageContent] | None = None,
|
||||
*,
|
||||
thread: AgentThread | None = None,
|
||||
on_intermediate_message: Callable[[ChatMessageContent], Awaitable[None]] | None = None,
|
||||
arguments: KernelArguments | None = None,
|
||||
@@ -815,8 +815,8 @@ class AzureAIAgent(DeclarativeSpecMixin, Agent):
|
||||
@override
|
||||
async def invoke_stream(
|
||||
self,
|
||||
*,
|
||||
messages: str | ChatMessageContent | list[str | ChatMessageContent] | None = None,
|
||||
*,
|
||||
thread: AgentThread | None = None,
|
||||
on_intermediate_message: Callable[[ChatMessageContent], Awaitable[None]] | None = None,
|
||||
arguments: KernelArguments | None = None,
|
||||
|
||||
@@ -261,8 +261,8 @@ class BedrockAgent(BedrockAgentBase):
|
||||
@override
|
||||
async def get_response(
|
||||
self,
|
||||
*,
|
||||
messages: str | ChatMessageContent | list[str | ChatMessageContent] | None = None,
|
||||
*,
|
||||
thread: AgentThread | None = None,
|
||||
agent_alias: str | None = None,
|
||||
arguments: KernelArguments | None = None,
|
||||
@@ -358,8 +358,8 @@ class BedrockAgent(BedrockAgentBase):
|
||||
@override
|
||||
async def invoke(
|
||||
self,
|
||||
*,
|
||||
messages: str | ChatMessageContent | list[str | ChatMessageContent] | None = None,
|
||||
*,
|
||||
thread: AgentThread | None = None,
|
||||
on_new_message: Callable[[ChatMessageContent], Awaitable[None]] | None = None,
|
||||
agent_alias: str | None = None,
|
||||
@@ -462,8 +462,8 @@ class BedrockAgent(BedrockAgentBase):
|
||||
@override
|
||||
async def invoke_stream(
|
||||
self,
|
||||
*,
|
||||
messages: str | ChatMessageContent | list[str | ChatMessageContent] | None = None,
|
||||
*,
|
||||
thread: AgentThread | None = None,
|
||||
on_new_message: Callable[[ChatMessageContent], Awaitable[None]] | None = None,
|
||||
agent_alias: str | None = None,
|
||||
|
||||
@@ -265,8 +265,8 @@ class ChatCompletionAgent(DeclarativeSpecMixin, Agent):
|
||||
@override
|
||||
async def get_response(
|
||||
self,
|
||||
*,
|
||||
messages: str | ChatMessageContent | list[str | ChatMessageContent] | None = None,
|
||||
*,
|
||||
thread: AgentThread | None = None,
|
||||
arguments: KernelArguments | None = None,
|
||||
kernel: "Kernel | None" = None,
|
||||
@@ -317,8 +317,8 @@ class ChatCompletionAgent(DeclarativeSpecMixin, Agent):
|
||||
@override
|
||||
async def invoke(
|
||||
self,
|
||||
*,
|
||||
messages: str | ChatMessageContent | list[str | ChatMessageContent] | None = None,
|
||||
*,
|
||||
thread: AgentThread | None = None,
|
||||
on_intermediate_message: Callable[[ChatMessageContent], Awaitable[None]] | None = None,
|
||||
arguments: KernelArguments | None = None,
|
||||
@@ -365,8 +365,8 @@ class ChatCompletionAgent(DeclarativeSpecMixin, Agent):
|
||||
@override
|
||||
async def invoke_stream(
|
||||
self,
|
||||
*,
|
||||
messages: str | ChatMessageContent | list[str | ChatMessageContent] | None = None,
|
||||
*,
|
||||
thread: AgentThread | None = None,
|
||||
on_intermediate_message: Callable[[ChatMessageContent], Awaitable[None]] | None = None,
|
||||
arguments: KernelArguments | None = None,
|
||||
|
||||
@@ -420,8 +420,8 @@ class CopilotStudioAgent(Agent):
|
||||
@override
|
||||
async def get_response(
|
||||
self,
|
||||
*,
|
||||
messages: str | ChatMessageContent | list[str | ChatMessageContent] | None = None,
|
||||
*,
|
||||
thread: AgentThread | None = None,
|
||||
arguments: KernelArguments | None = None,
|
||||
kernel: "Kernel | None" = None,
|
||||
@@ -467,8 +467,8 @@ class CopilotStudioAgent(Agent):
|
||||
@override
|
||||
async def invoke(
|
||||
self,
|
||||
*,
|
||||
messages: str | ChatMessageContent | list[str | ChatMessageContent] | None = None,
|
||||
*,
|
||||
thread: AgentThread | None = None,
|
||||
on_intermediate_message: Callable[[ChatMessageContent], Awaitable[None]] | None = None,
|
||||
arguments: KernelArguments | None = None,
|
||||
@@ -512,8 +512,8 @@ class CopilotStudioAgent(Agent):
|
||||
@override
|
||||
def invoke_stream(
|
||||
self,
|
||||
*,
|
||||
messages: str | ChatMessageContent | list[str | ChatMessageContent] | None = None,
|
||||
*,
|
||||
thread: AgentThread | None = None,
|
||||
on_intermediate_message: Callable[[ChatMessageContent], Awaitable[None]] | None = None,
|
||||
arguments: KernelArguments | None = None,
|
||||
|
||||
@@ -442,8 +442,8 @@ class OpenAIAssistantAgent(Agent):
|
||||
@override
|
||||
async def get_response(
|
||||
self,
|
||||
*,
|
||||
messages: str | ChatMessageContent | list[str | ChatMessageContent] | None = None,
|
||||
*,
|
||||
thread: AgentThread | None = None,
|
||||
arguments: KernelArguments | None = None,
|
||||
additional_instructions: str | None = None,
|
||||
@@ -549,8 +549,8 @@ class OpenAIAssistantAgent(Agent):
|
||||
@override
|
||||
async def invoke(
|
||||
self,
|
||||
*,
|
||||
messages: str | ChatMessageContent | list[str | ChatMessageContent] | None = None,
|
||||
*,
|
||||
thread: AgentThread | None = None,
|
||||
on_intermediate_message: Callable[[ChatMessageContent], Awaitable[None]] | None = None,
|
||||
arguments: KernelArguments | None = None,
|
||||
@@ -657,8 +657,8 @@ class OpenAIAssistantAgent(Agent):
|
||||
@override
|
||||
async def invoke_stream(
|
||||
self,
|
||||
*,
|
||||
messages: str | ChatMessageContent | list[str | ChatMessageContent] | None = None,
|
||||
*,
|
||||
thread: AgentThread | None = None,
|
||||
on_intermediate_message: Callable[[ChatMessageContent], Awaitable[None]] | None = None,
|
||||
additional_instructions: str | None = None,
|
||||
|
||||
@@ -548,8 +548,8 @@ class OpenAIResponsesAgent(Agent):
|
||||
@override
|
||||
async def get_response(
|
||||
self,
|
||||
*,
|
||||
messages: str | ChatMessageContent | list[str | ChatMessageContent] | None = None,
|
||||
*,
|
||||
thread: AgentThread | None = None,
|
||||
arguments: KernelArguments | None = None,
|
||||
kernel: "Kernel | None" = None,
|
||||
@@ -668,8 +668,8 @@ class OpenAIResponsesAgent(Agent):
|
||||
@override
|
||||
async def invoke(
|
||||
self,
|
||||
*,
|
||||
messages: str | ChatMessageContent | list[str | ChatMessageContent] | None = None,
|
||||
*,
|
||||
thread: AgentThread | None = None,
|
||||
on_intermediate_message: Callable[[ChatMessageContent], Awaitable[None]] | None = None,
|
||||
arguments: KernelArguments | None = None,
|
||||
@@ -786,8 +786,8 @@ class OpenAIResponsesAgent(Agent):
|
||||
@override
|
||||
async def invoke_stream(
|
||||
self,
|
||||
*,
|
||||
messages: str | ChatMessageContent | list[str | ChatMessageContent] | None = None,
|
||||
*,
|
||||
thread: AgentThread | None = None,
|
||||
on_intermediate_message: Callable[[ChatMessageContent], Awaitable[None]] | None = None,
|
||||
arguments: KernelArguments | None = None,
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ async def test_autogen_conversable_agent_get_response(mock_conversable_agent):
|
||||
agent = AutoGenConversableAgent(mock_conversable_agent)
|
||||
thread: AutoGenConversableAgentThread = None
|
||||
|
||||
response = await agent.get_response("Hello", thread)
|
||||
response = await agent.get_response("Hello", thread=thread)
|
||||
assert response.message.role == AuthorRole.ASSISTANT
|
||||
assert response.message.content == "Mocked assistant response"
|
||||
assert response.thread is not None
|
||||
|
||||
Reference in New Issue
Block a user