Repository navigation
Python: fix(python): return call-level compaction summaries in agent responses - #8117
Conversation
Removes a blank line between stdlib import groups that the locked ruff version (and therefore the pre-commit format hook) now requires.
In-run compaction excluded tool groups via flags on Message objects shared with the function-invocation transcript, but inserted summary messages only into the model-input list. The final ChatResponse (and the history persisted from it) therefore kept only the exclusion flags, so loading history with skip_excluded silently dropped the summarized tool results (microsoft#8099). Merge summaries back into the transcript after each model call, matching each summary to its excluded group via the SUMMARIZED_BY_SUMMARY_ID_KEY back-link. Summaries of caller-owned input messages stay out of the returned transcript. Adds regression tests for the Phase-2 terminal path, the max-iterations terminal path, and agent-level persistence with InMemoryHistoryProvider.
…oop spec Adds the normative invariant that non-streaming runs return inserted compaction summaries in the final response transcript, a traceability matrix row pointing at the new regression tests, and a related-issue entry for microsoft#8099.
|
@microsoft-github-policy-service agree |
|
Eduard van Valkenburg (@eavanvalkenburg) Please do review and let me know! |
|
Eduard van Valkenburg (@eavanvalkenburg) I investigated the failing Python 3.14 Ubuntu job locally. The new #8099 regression cases pass under Python 3.14 (9/9), including the terminal-exit and nested-summary cases. The job’s public annotation only reports a generic exit code 1, while the remaining matrix jobs were cancelled due to fail-fast. Could someone with Actions-log access share the failing node ID and traceback? At present this looks likely to be an unrelated or CI-only failure rather than a reproducible regression from this PR. |
|
Thanks for the contribution. The current head is not green: |
Head branch was pushed to by a user without write access
|
Eduard van Valkenburg (@eavanvalkenburg) Investigated the Python test failure. The Responses tests were using the real local file-backed AgentServer session store while pytest-xdist ran workers in parallel. Workers could write the same agent_sessions.json, causing intermittent storage errors and a failed response status.
|
|
Eduard van Valkenburg (@eavanvalkenburg) All tests seems to be passing now, can we merge this one ? |
Motivation & Context
Call-level compaction (
compaction_strategyon anAgentorclient.as_agent()) works mid-run: it marks older self-generated tool-call/tool-result messages as excluded and inserts a summary the model sees. However, the summary messages never reached the finalAgentResponse- only the exclusion flags did, because the flags are in-place mutations onMessageobjects shared between the model-input list (prepared_messages) and the returned transcript (function_call_messages), while the inserted summaries live only in the model-input list.As a result,
HistoryProvider.after_run()persisted that asymmetric response, and withInMemoryHistoryProvider(skip_excluded=True)- the documented way to combine compaction with history - the nextget_messages()silently dropped the excluded tool groups with no summary replacing them. Any agent using tools + call-level compaction + a history provider hits this.Fixes #8099
Description & Review Guide
What are the major changes?
_reconcile_compaction_summarieshelper in_compaction.pyso bothChatMiddlewareLayerand the function-invocation loop use the same ownership-aware, fixed-point reconciliation algorithm.FunctionInvocationLayer._get_response_with_function_invocation(_tools.py): after each Phase-2 model call and after the Phase-3 final no-tools call, before the transcript is returned or persisted.InMemoryHistoryProvider(skip_excluded=True).docs/specs/004-python-function-calling-loop.md, perpython/AGENTS.md.test_agent_executor.pythat the locked formatter / pre-commit hook now requires (unrelated to the fix, isolated for clarity).What is the impact of these changes?
ChatResponse.messages/AgentResponse.messages, positioned before the group each summary replaces - so history loaded withskip_excludedkeeps the summarized content instead of losing it silently.What do you want reviewers to focus on?
_reconcile_compaction_summarieswith transcript identities as the ownership boundary, especially fixed-point handling of nested summaries and rejection of summaries involving caller-owned input.compaction_strategyparameter: compaction may come from the inner client's own default strategy, which the invocation layer does not see as a parameter.Validated with
uv run poe test -P core(5136 passed, 38 skipped, 2 xfailed),uv run poe syntax -P core,uv run poe pyright -P core, anduv run poe test-typing -P core- all green.Related Issue
Fixes #8099
Contribution Checklist
breaking changelabel (or add "[BREAKING]" to the title prefix, before or after any language prefix) - a workflow keeps the label and title prefix in sync automatically.