Skip to content

Python: fix(python): preserve non-adjacent tool pairs during history truncation - #14658

Draft
hylin (linhongyu510) wants to merge 1 commit into
microsoft:mainfrom
linhongyu510:fix/nonadjacent-tool-pair-truncation
Draft

hylin (linhongyu510) wants to merge 1 commit into
microsoft:mainfrom
linhongyu510:fix/nonadjacent-tool-pair-truncation

Conversation

@linhongyu510

Copy link
Copy Markdown

Title

fix(python): preserve non-adjacent tool pairs during history truncation

Motivation and Context

  • Problem: ChatHistoryTruncationReducer could retain a FunctionResultContent while dropping its matching FunctionCallContent when the two were separated by non-function messages.
  • Existing contract: adjacent tool blocks were already protected, and matched ID pairs are used elsewhere by the reducer utilities. A retained tool result should not become an orphan after truncation.
  • Why this is minimal: the fix chooses the existing user-threshold candidate boundary first, then applies a final matched-ID pair closure.
  • Scope: offline chat-history reduction only; no provider, network, E2E, public API, dependency, lockfile, or documentation-only refactor.
  • Issue: self-discovered during audit; independent dedup found no equivalent open issue/PR.

Description

locate_safe_reduction_index now builds an O(n) suffix minimum-call map from get_call_result_pairs(history). After the existing adjacency and threshold-window candidate selection, it moves the cut back only when a retained result requires an earlier matched call. Chained non-adjacent pairs are closed transitively. If the required call is before offset_count, reduction returns None rather than crossing offset/summary territory.

Offset, threshold, system/developer preservation, unknown/unpaired content, and existing user-boundary search semantics are otherwise unchanged.

Local verification

  • Base: 483ffb487a33a1644886992d56599feae3b69b76.
  • Pre-fix formal regression: 4 failed, 4 passed.
  • Post-fix formal regression: 8 passed.
  • Production-only revert cycle: red exit 1, restore green exit 0.
  • Related chat-history suite: 105 passed.
  • Ruff: 0.9.10; check and format check pass.
  • Mypy: targeted changed production file passes.
  • Multi-Python matrix and wheel build were not run in this preparation step.
  • AI assistance was used; an independent local review was rerun before publication. No external CLI review is claimed.

Contribution Checklist

  • The code builds clean without any errors or warnings in the focused local checks.
  • The PR follows the Semantic Kernel Contribution Guide and local Ruff/Mypy checks.
  • All unit tests pass, and I added focused tests for the non-adjacent call/result regression.
  • I did not break anyone.
  • AI assistance is disclosed.

Preserve matched FunctionCallContent and FunctionResultContent pairs when ChatHistoryTruncationReducer cuts between a call and its result.

Co-authored-by: AI assistance was used and reviewed.

Signed-off-by: hylin <linhongyu510@gmail.com>
@semantic-kernel-automation semantic-kernel-automation Bot added the python Pull requests for the Python Semantic Kernel label Oct 24, 2026
@github-actions github-actions Bot changed the title fix(python): preserve non-adjacent tool pairs during history truncation Python: fix(python): preserve non-adjacent tool pairs during history truncation Oct 24, 2026

This branch was successfully deployed

1 active deployment
github-app-auth — 3cd8e4b7 Deployed Oct 24, 2026 by linhongyu510 via add_label #29435
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.

1 participant