Skip to content

Commit ba000c3

Browse files
authored
Python: Use message cache in agent orchestrations (#12618)
### 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. --> Some agent threads don't support adding messages. An example of this is the copilot studio agent. In an agent orchestration, an agent may receive multiple messages before it is asked to generate a response. The currently approach in the orchestrations would add new messages to an agent thread whenever an agent receives a message, making the copilot studio agent not compatible with some orchestrations. ### Description <!-- Describe your changes, the overall approach, the underlying design. These notes will help understanding how your code works. Thanks! --> Instead of adding messages to the agent thread, this PR introduces a message cache to store messages temporarily before the agent is invoked. ### 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 😄
1 parent 43257cd commit ba000c3

File tree

4 files changed

+15
-34
lines changed

4 files changed

+15
-34
lines changed

python/semantic_kernel/agents/orchestration/agent_actor_base.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ def __init__(
6363
self._streaming_agent_response_callback = streaming_agent_response_callback
6464

6565
self._agent_thread: AgentThread | None = None
66-
# Chat history to temporarily store messages before the agent thread is created
67-
self._chat_history = ChatHistory()
66+
# Chat history to temporarily store messages before each invoke.
67+
self._message_cache: ChatHistory = ChatHistory()
6868

6969
ActorBase.__init__(self, description=agent.description or "Semantic Kernel Agent")
7070

@@ -146,7 +146,10 @@ def _create_messages(self, additional_messages: DefaultTypeAlias | None = None)
146146
Returns:
147147
list[ChatMessageContent]: A list of messages to be sent to the agent.
148148
"""
149-
base_messages = self._chat_history.messages[:] if self._agent_thread is None else []
149+
base_messages = self._message_cache.messages[:]
150+
151+
# Clear the message cache for the next invoke.
152+
self._message_cache.clear()
150153

151154
if additional_messages is None:
152155
return base_messages

python/semantic_kernel/agents/orchestration/group_chat.py

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -107,27 +107,17 @@ async def _handle_start_message(self, message: GroupChatStartMessage, ctx: Messa
107107
"""Handle the start message for the group chat."""
108108
logger.debug(f"{self.id}: Received group chat start message.")
109109
if isinstance(message.body, ChatMessageContent):
110-
if self._agent_thread:
111-
await self._agent_thread.on_new_message(message.body)
112-
else:
113-
self._chat_history.add_message(message.body)
110+
self._message_cache.add_message(message.body)
114111
elif isinstance(message.body, list) and all(isinstance(m, ChatMessageContent) for m in message.body):
115-
if self._agent_thread:
116-
for m in message.body:
117-
await self._agent_thread.on_new_message(m)
118-
else:
119-
for m in message.body:
120-
self._chat_history.add_message(m)
112+
for m in message.body:
113+
self._message_cache.add_message(m)
121114
else:
122115
raise ValueError(f"Invalid message body type: {type(message.body)}. Expected {DefaultTypeAlias}.")
123116

124117
@message_handler
125118
async def _handle_response_message(self, message: GroupChatResponseMessage, ctx: MessageContext) -> None:
126119
logger.debug(f"{self.id}: Received group chat response message.")
127-
if self._agent_thread is not None:
128-
await self._agent_thread.on_new_message(message.body)
129-
else:
130-
self._chat_history.add_message(message.body)
120+
self._message_cache.add_message(message.body)
131121

132122
@message_handler
133123
async def _handle_request_message(self, message: GroupChatRequestMessage, ctx: MessageContext) -> None:

python/semantic_kernel/agents/orchestration/handoffs.py

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -250,27 +250,18 @@ async def _complete_task(self, task_summary: str) -> None:
250250
async def _handle_start_message(self, message: HandoffStartMessage, cts: MessageContext) -> None:
251251
logger.debug(f"{self.id}: Received handoff start message.")
252252
if isinstance(message.body, ChatMessageContent):
253-
if self._agent_thread:
254-
await self._agent_thread.on_new_message(message.body)
255-
else:
256-
self._chat_history.add_message(message.body)
253+
self._message_cache.add_message(message.body)
257254
elif isinstance(message.body, list) and all(isinstance(m, ChatMessageContent) for m in message.body):
258255
for m in message.body:
259-
if self._agent_thread:
260-
await self._agent_thread.on_new_message(m)
261-
else:
262-
self._chat_history.add_message(m)
256+
self._message_cache.add_message(m)
263257
else:
264258
raise ValueError(f"Invalid message body type: {type(message.body)}. Expected {DefaultTypeAlias}.")
265259

266260
@message_handler
267261
async def _handle_response_message(self, message: HandoffResponseMessage, cts: MessageContext) -> None:
268262
"""Handle a response message from an agent in the handoff group."""
269263
logger.debug(f"{self.id}: Received handoff response message.")
270-
if self._agent_thread is not None:
271-
await self._agent_thread.on_new_message(message.body)
272-
else:
273-
self._chat_history.add_message(message.body)
264+
self._message_cache.add_message(message.body)
274265

275266
@message_handler
276267
async def _handle_request_message(self, message: HandoffRequestMessage, cts: MessageContext) -> None:

python/semantic_kernel/agents/orchestration/magentic.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -677,10 +677,7 @@ class MagenticAgentActor(AgentActorBase):
677677
@message_handler
678678
async def _handle_response_message(self, message: MagenticResponseMessage, ctx: MessageContext) -> None:
679679
logger.debug(f"{self.id}: Received response message.")
680-
if self._agent_thread is not None:
681-
await self._agent_thread.on_new_message(message.body)
682-
else:
683-
self._chat_history.add_message(message.body)
680+
self._message_cache.add_message(message.body)
684681

685682
@message_handler
686683
async def _handle_request_message(self, message: MagenticRequestMessage, ctx: MessageContext) -> None:
@@ -703,7 +700,7 @@ async def _handle_request_message(self, message: MagenticRequestMessage, ctx: Me
703700
async def _handle_reset_message(self, message: MagenticResetMessage, ctx: MessageContext) -> None:
704701
"""Handle the reset message for the Magentic One group chat."""
705702
logger.debug(f"{self.id}: Received reset message.")
706-
self._chat_history.clear()
703+
self._message_cache.clear()
707704
if self._agent_thread:
708705
await self._agent_thread.delete()
709706
self._agent_thread = None

0 commit comments

Comments
 (0)