Skip to content

Python: Fix Chat History Agent format instructions regression. #10512

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 13, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
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 @@ -123,6 +123,9 @@ async def invoke(
else:
arguments.update(kwargs)

# Add the chat history to the args in the event that it is needed for prompt template configuration
arguments["chat_history"] = history

kernel = kernel or self.kernel
arguments = self.merge_arguments(arguments)

Expand Down Expand Up @@ -188,6 +191,9 @@ async def invoke_stream(
else:
arguments.update(kwargs)

# Add the chat history to the args in the event that it is needed for prompt template configuration
arguments["chat_history"] = history

kernel = kernel or self.kernel
arguments = self.merge_arguments(arguments)

Expand Down Expand Up @@ -245,11 +251,13 @@ async def _setup_agent_chat_history(
self, history: ChatHistory, kernel: "Kernel", arguments: KernelArguments
) -> ChatHistory:
"""Setup the agent chat history."""
return (
ChatHistory(messages=history.messages)
if self.instructions is None
else ChatHistory(system_message=self.instructions, messages=history.messages)
)
formatted_instructions = await self.format_instructions(kernel, arguments)
messages = []
if formatted_instructions:
messages.append(ChatMessageContent(role=AuthorRole.SYSTEM, content=formatted_instructions, name=self.name))
if history.messages:
messages.extend(history.messages)
return ChatHistory(messages=messages)

async def _get_chat_completion_service_and_settings(
self, kernel: "Kernel", arguments: KernelArguments
Expand Down
45 changes: 41 additions & 4 deletions python/tests/unit/agents/test_chat_completion_agent.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Copyright (c) Microsoft. All rights reserved.

from collections.abc import AsyncGenerator, Callable
from unittest.mock import AsyncMock, create_autospec, patch

import pytest
Expand All @@ -18,15 +19,13 @@


@pytest.fixture
def mock_streaming_chat_completion_response() -> AsyncMock:
"""A fixture that returns a mock response for a streaming chat completion response."""

def mock_streaming_chat_completion_response() -> Callable[..., AsyncGenerator[list[ChatMessageContent], None]]:
async def mock_response(
chat_history: ChatHistory,
settings: PromptExecutionSettings,
kernel: Kernel,
arguments: KernelArguments,
):
) -> AsyncGenerator[list[ChatMessageContent], None]:
content1 = ChatMessageContent(role=AuthorRole.SYSTEM, content="Processed Message 1")
content2 = ChatMessageContent(role=AuthorRole.TOOL, content="Processed Message 2")
chat_history.messages.append(content1)
Expand Down Expand Up @@ -242,3 +241,41 @@ async def test_create_channel():
channel = await agent.create_channel()

assert isinstance(channel, ChatHistoryChannel)


async def test_setup_agent_chat_history_with_formatted_instructions():
agent = ChatCompletionAgent(
name="TestAgent", id="test_id", description="Test Description", instructions="Test Instructions"
)
with patch.object(
ChatCompletionAgent, "format_instructions", new=AsyncMock(return_value="Formatted instructions for testing")
) as mock_format_instructions:
dummy_kernel = create_autospec(Kernel)
dummy_args = KernelArguments(param="value")
user_message = ChatMessageContent(role=AuthorRole.USER, content="User message")
history = ChatHistory(messages=[user_message])
result_history = await agent._setup_agent_chat_history(history, dummy_kernel, dummy_args)
mock_format_instructions.assert_awaited_once_with(dummy_kernel, dummy_args)
assert len(result_history.messages) == 2
system_message = result_history.messages[0]
assert system_message.role == AuthorRole.SYSTEM
assert system_message.content == "Formatted instructions for testing"
assert system_message.name == agent.name
assert result_history.messages[1] == user_message


async def test_setup_agent_chat_history_without_formatted_instructions():
agent = ChatCompletionAgent(
name="TestAgent", id="test_id", description="Test Description", instructions="Test Instructions"
)
with patch.object(
ChatCompletionAgent, "format_instructions", new=AsyncMock(return_value=None)
) as mock_format_instructions:
dummy_kernel = create_autospec(Kernel)
dummy_args = KernelArguments(param="value")
user_message = ChatMessageContent(role=AuthorRole.USER, content="User message")
history = ChatHistory(messages=[user_message])
result_history = await agent._setup_agent_chat_history(history, dummy_kernel, dummy_args)
mock_format_instructions.assert_awaited_once_with(dummy_kernel, dummy_args)
assert len(result_history.messages) == 1
assert result_history.messages[0] == user_message
Loading