Skip to content

Python: fix(python): wire ChatHistoryReducer into ChatCompletionAgent invocation (#12303) - #14607

Open
SparkyPunk (sparkysolutions10-pixel) wants to merge 2 commits into
microsoft:mainfrom
sparkysolutions10-pixel:fix/python-chat-history-summarizer-12303
Open

SparkyPunk (sparkysolutions10-pixel) wants to merge 2 commits into
microsoft:mainfrom
sparkysolutions10-pixel:fix/python-chat-history-summarizer-12303

Conversation

@sparkysolutions10-pixel

Copy link
Copy Markdown

Motivation and Context

Fixes #12303

  1. Why is this change required?
    Currently, configuring a ChatHistorySummarizationReducer or ChatHistoryTruncationReducer on a ChatCompletionAgent (e.g. via arguments=KernelArguments(chat_history=reducer) or thread injection) fails to reduce the chat history before dispatching calls to the LLM. The full, unbounded conversation history is passed in the request payload, causing context window overflows and unnecessary token consumption.

  2. What problem does it solve?

    • Enables ChatCompletionAgent to respect active ChatHistoryReducer implementations (such as summarization and truncation reducers).
    • Allows users and multi-agent orchestrations to manage context size efficiently without token explosion.
  3. What scenario does it contribute to?
    Multi-turn agent interactions and multi-agent group chats where long-running conversations require summarizing or truncating older messages to stay within LLM context boundaries.


Description

  • Auto-reduction on thread updates: In ChatHistoryAgentThread._on_new_message, check if self._chat_history is a ChatHistoryReducer with auto_reduce=True. If so, invoke await self._chat_history.add_message_async(new_message) so the reduction boundary triggers as designed.
  • Reducer propagation from KernelArguments: In ChatCompletionAgent.get_response(), invoke(), and invoke_stream(), check if arguments contains an active chat_history reducer and pass it into the constructor when initializing ChatHistoryAgentThread.
  • Pre-invocation reduction pass: Before constructing the final chat_history payload for _inner_invoke() / _inner_invoke_stream(), check if the active thread contains a ChatHistoryReducer and call await thread.reduce().
  • Unit test suite: Added unit tests verifying ChatCompletionAgent respects both thread-injected and argument-injected reducers during get_response().

Contribution Checklist

…ion (microsoft#12303)

- Propagate initial chat_history reducer from KernelArguments into ChatHistoryAgentThread
- Await thread.reduce() prior to dispatching messages to ChatCompletionClientBase
- Trigger auto_reduce via add_message_async in ChatHistoryAgentThread._on_new_message

Signed-off-by: sparkysolutions10-pixelmy <sparkysolutions10@gmail.com>
…Reducer (microsoft#12303)

- Test ChatCompletionAgent respecting ChatHistoryTruncationReducer during get_response
- Test ChatCompletionAgent automatic reduction via KernelArguments

Signed-off-by: sparkysolutions10-pixelmy <sparkysolutions10@gmail.com>
Copilot AI balanced review requested due to automatic review settings October 16, 2026 00:28
@semantic-kernel-automation semantic-kernel-automation Bot added the python Pull requests for the Python Semantic Kernel label Oct 16, 2026
@github-actions github-actions Bot changed the title fix(python): wire ChatHistoryReducer into ChatCompletionAgent invocation (#12303) Python: fix(python): wire ChatHistoryReducer into ChatCompletionAgent invocation (#12303) Oct 16, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Constructor-configured reducers remain ignored, and incomplete service mocks prevent the new tests from reaching their assertions.

3 open findings
What changed in this PR

This PR connects chat-history reducers to Python ChatCompletionAgent invocations to limit conversation payload size.

Changes:

  • Enables automatic reduction when threads receive messages.
  • Propagates invocation-provided history and reduces it before model calls.
  • Adds tests for thread- and argument-injected reducers.
File Description
python/​tests/​unit/​agents/​chat_completion/​test_chat_completion_agent.py Adds reducer integration tests.
python/​semantic_kernel/​agents/​chat_completion/​chat_completion_agent.py Integrates reducers into thread updates and invocation paths.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.



async def test_chat_completion_agent_with_chat_history_reducer():
mock_service = AsyncMock(spec=ChatCompletionClientBase)
Comment on lines +301 to +305
initial_history = (
arguments.get("chat_history")
if arguments and isinstance(arguments.get("chat_history"), ChatHistory)
else None
)
assert response.message.content == "Agent answer"

passed_history = mock_service.get_chat_message_contents.call_args.kwargs["chat_history"]
assert len([m for m in passed_history.messages if m.role != AuthorRole.SYSTEM]) <= 2
@sparkysolutions10-pixel

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Community review. This does not clear the merge gate.

The behavior change works, but the two new tests do not run, and one behavior choice needs a decision.

  1. The new tests fail on the PR branch itself. I applied the PR to upstream/main (7a92cd4, separate worktree, venv at C:/skv2) and ran python/tests/unit/agents/chat_completion plus tests/unit/agents/test_agent.py. The two added tests, test_chat_completion_agent_with_chat_history_reducer and test_chat_completion_agent_auto_reduce_via_arguments, fail the same way on main and on the PR: 2 failed, 62 passed in both runs. The error is AttributeError: Mock object has no attribute 'service_id', raised from ChatCompletionAgent.__init__ -> configure_service -> kernel_services_extension.add_service, because AsyncMock(spec=ChatCompletionClientBase) is passed as service=. The other tests in this file use the kernel_with_ai_service fixture from conftest.py instead. So these tests never reach the code they are meant to cover.

  2. The change itself does what the description says. I wrote my own probe using the same create_autospec kernel pattern as the chat_completion conftest, with a ChatHistoryTruncationReducer(target_count=2, threshold_count=0) and 5 or 6 user messages, and compared what reaches get_chat_message_contents:

  • reducer in a ChatHistoryAgentThread, auto_reduce=True, get_response: main sends M0..M4, PR sends M3, M4.
  • the same thread with auto_reduce=False: main sends M0..M4, PR sends M3, M4.
  • reducer passed as KernelArguments(chat_history=reducer) with no thread: main sends an empty history (the argument is ignored), PR sends the last two messages.
  • invoke with the auto-reduce thread: main sends M0..M4, PR sends M3, M4.
    I did not run invoke_stream; it has the same code added as the other two, which I read in the diff only.
  1. Design question. thread.reduce() is now called whenever the history is a ChatHistoryReducer, including with auto_reduce=False (second bullet above). If auto_reduce=False is meant to mean "I will call reduce myself", this overrides it. The PR's own second test uses auto_reduce=False and expects reduction, so it looks deliberate, but the description does not say so. Worth a maintainer decision.

  2. Also, initial_history from arguments["chat_history"] is only used when a new thread is created. If a thread is passed in along with chat_history in the arguments, the argument is ignored; I did not test that case.

Issue #12303 is open and assigned to TaoChenOSU (read from the API), so you may want to confirm with them before this goes further.

This branch was successfully deployed

1 active deployment
github-app-auth — 9ca96005 Deployed Oct 16, 2026 by sparkysolutions10-pixel via team_check #632
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Pull requests for the Python Semantic Kernel

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: Bug: Complete chat history is getting passed to LLM - chat history summarizer is not working

3 participants