Python: Preserve non-adjacent function call/result pairs during compaction - #7244
Python: Preserve non-adjacent function call/result pairs during compaction#7244jstar0 wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR fixes a compaction-grouping bug in the Python core where non-adjacent assistant function_call declarations and tool function_result messages could end up in different groups, allowing group-based strategies to orphan one half and produce provider-invalid model inputs. It extends grouping to pair spans by unique call_id (without changing existing adjacency behavior for ambiguous/invalid cases) and updates incremental annotation so late-appended results rewind to the matching declaration group.
Changes:
- Add a post-pass in
group_messagesto link non-adjacent function result spans to a unique earlier declaration span with the samecall_id, sharinggroup_idand reasoning metadata. - Update incremental annotation to rewind the re-annotation window to the unique declaration group when a matching result is appended later, and ensure group indices remain collision-free with linked/non-contiguous groups.
- Add regression tests covering non-adjacent pairing, multi-result/combined-result scenarios, ambiguous duplicates, incremental append behavior, and truncation atomicity.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
python/packages/core/agent_framework/_compaction.py |
Implements call-id-based linking of non-adjacent function call/result spans and adjusts incremental re-annotation/group index handling to keep linked pairs atomic. |
python/packages/core/tests/core/test_compaction.py |
Adds targeted regression tests validating non-adjacent pairing, ambiguity rules, incremental extension behavior, and truncation atomicity for tool call/result pairs. |
|
please make sure to use the defined PR template @jstar0 |
|
Updated the PR body to use the repository template, including Motivation & Context, Description & Review Guide, Related Issue, verification, and the contribution checklist. |
Motivation & Context
Compaction currently groups only contiguous message spans. When approval or
resume traffic separates an assistant
function_calldeclaration from its toolfunction_result, each half receives a different group id. Group-basedstrategies can then retain the result while excluding the declaration, producing
provider-invalid model input.
This change keeps non-adjacent call/result pairs atomic without changing the
behavior of pending, unmatched, malformed-order, or ambiguous duplicate calls.
Description & Review Guide
declaration span with the same
call_id, share the declaration's group id,group index, and reasoning metadata, and rewind incremental annotation when a
matching result is appended later. Regression coverage includes truncation,
multiple calls, combined result messages, ambiguous ids, and incremental
append state.
strategies now preserve valid function call/result pairs even when unrelated
messages separate them. Hosted and MCP tool grouping, public APIs, and
individual compaction strategies are unchanged.
call_idlinking rules,especially the intentional fallback to existing grouping for ambiguous or
malformed sequences, and the incremental re-annotation boundary.
Verification:
Related Issue
Fixes #7212
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.