Skip to content

Python: Bound summarization input before provider call - #7375

Open
scarab-systems wants to merge 4 commits into
microsoft:mainfrom
scarab-systems:scarab-systems/python-summarization-budget-7214
Open

Python: Bound summarization input before provider call#7375
scarab-systems wants to merge 4 commits into
microsoft:mainfrom
scarab-systems:scarab-systems/python-summarization-budget-7214

Conversation

@scarab-systems

@scarab-systems scarab-systems commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Motivation & Context

SummarizationStrategy currently formats every older message selected for summarization into a single summarizer request. For long histories, that can exceed a provider context limit; the strategy then logs a warning, returns False, and stops contributing summary compaction for that round.

This fixes #7214 by bounding the summarizer input before the provider call and making persistent summarize failures louder than the existing per-round warning.

Description & Review Guide

  • What are the major changes?

    • Adds a configurable max_summary_input_tokens budget for SummarizationStrategy, with the existing character-estimator tokenizer as the default estimator.
    • Selects whole message groups until the next group would exceed the summarizer request budget.
    • Skips individually over-budget leading groups so a single large old group does not prevent later compactable groups from being summarized.
    • Marks only the groups actually sent to the summarizer as summarized/excluded, leaving unsent or oversized groups intact for a later compaction pass.
    • Tracks consecutive summary failures and emits a single ERROR after three consecutive failures, resetting that escalation state after a successful summary.
    • Adds regression tests for bounded summarizer input, oversized leading groups, repeated-failure escalation, and escalation reset after recovery.
  • What is the impact of these changes?

    • Summarization no longer ships the entire selected transcript to the provider unbounded by default.
    • Persistent summary failures are no longer only per-round WARNINGs; repeated failures produce one louder ERROR signal.
    • Existing callers remain source-compatible; callers can pass None to max_summary_input_tokens to opt out of the budget.
  • What do you want reviewers to focus on?

    • Whether the default budget value and opt-out shape are appropriate for the Python core API.
    • Whether preserving whole groups for later compaction is the preferred behavior when the next group would exceed the budget.
    • Whether three consecutive failures is the right default threshold for the one-shot ERROR escalation.
  • Scope note

    • The issue also calls out incremental/content-keyed summarization as optional high-value follow-up. I left that out of this PR to keep the patch focused on the two direct failure modes: unbounded provider input and persistent warning-only failure. I am happy to add incremental summarization here or in a follow-up if maintainers prefer that scope.

Related Issue

Fixes #7214

No other open PR for this issue was found before submitting.

Contribution Checklist

  • The code builds clean without any errors or warnings
  • All unit tests pass, and I have added new tests where possible
  • The PR follows the Contribution Guidelines
  • This PR is linked to an issue and there is no other open PR for this issue (see Related Issue above).
  • This is not a breaking change. If it is a breaking change, add the breaking change label (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.

Copilot AI review requested due to automatic review settings July 28, 2026 22:07
@agent-framework-automation agent-framework-automation Bot added the python Usage: [Issues, PRs], Target: Python label Jul 28, 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.

Pull request overview

This PR updates the Python core compaction pipeline’s SummarizationStrategy to bound the size of the summarizer request before calling the provider, preventing summarization from failing due to context-window overruns in long-running conversations (fixing #7214).

Changes:

  • Added max_summary_input_tokens (defaulted) and a configurable TokenizerProtocol implementation to estimate summarizer request size.
  • Implemented group-wise selection to include only whole message groups up to the configured input budget and only mark those groups as summarized/excluded.
  • Added a regression test to verify bounded summarizer input and that unsent/oversized groups remain eligible for later compaction.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
python/packages/core/agent_framework/_compaction.py Adds token-budgeted selection of summary input groups and new SummarizationStrategy configuration for bounded summarizer requests.
python/packages/core/tests/core/test_compaction.py Adds a test double and regression test validating bounded summarization and preservation of unsent groups.

Comment on lines +1003 to +1004
if candidate_token_count > max_summary_input_tokens:
break
@scarab-systems
scarab-systems marked this pull request as ready for review July 28, 2026 22:31
@scarab-systems
scarab-systems marked this pull request as draft July 28, 2026 22:43
@scarab-systems
scarab-systems marked this pull request as ready for review July 28, 2026 22:57
@scarab-systems
scarab-systems requested a review from Copilot July 29, 2026 00:28

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.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (3)

python/packages/core/tests/core/test_compaction.py:495

  • _ScriptedSummarizer uses BaseException in its outcomes type and isinstance check. In tests this makes it easy to accidentally raise SystemExit/KeyboardInterrupt and abort the test run; using Exception is the safer, conventional choice for expected failures.
    def __init__(self, outcomes: list[str | BaseException]) -> None:

python/packages/core/agent_framework/_compaction.py:1003

  • _select_summary_input_groups rebuilds the full formatted transcript and re-tokenizes it on every group iteration. For long histories this is O(n^2) in both formatting and tokenization work, which can become a bottleneck exactly in the large-history scenarios this change targets.
    for group_id, group_messages in groups:
        candidate_messages = [*selected_messages, *group_messages]
        candidate_text = _format_messages_for_summary(candidate_messages)
        candidate_token_count = prompt_token_count + tokenizer.count_tokens(candidate_text)
        if candidate_token_count > max_summary_input_tokens:

python/packages/core/agent_framework/_compaction.py:1109

  • Failure escalation state is stored on the SummarizationStrategy instance (_consecutive_summary_failures, _summary_failure_error_emitted). Since compaction strategies are commonly configured per chat client and reused across independent conversations, this can mix failure counts across conversations and produce misleading ERROR escalation (or suppress it) for a given thread.
        self.tokenizer = tokenizer or CharacterEstimatorTokenizer()
        self._consecutive_summary_failures = 0
        self._summary_failure_error_emitted = False

SummarizationStrategy now selects complete message groups that fit a configurable summary input token budget before calling the summary client. Only messages actually sent to the summarizer are annotated and excluded, leaving oversized later groups for a later compaction pass instead of shipping the whole transcript unbounded.

Validation: uv run pytest packages/core/tests/core/test_compaction.py -k bounds_summary_input -m "not integration" failed before the implementation and passed after it; uv run pytest packages/core/tests/core/test_compaction.py -m "not integration" passed; uv run poe test -P core passed; uv run poe install completed; uv run poe check -P core passed.
Skip individually over-budget leading groups when selecting summarization input so a large early transcript item does not prevent later compactable groups from being summarized.

Validation: uv run pytest packages/core/tests/core/test_compaction.py -k skips_oversized_first_group -q; uv run pytest packages/core/tests/core/test_compaction.py -q; uv run poe check -P core.
Track consecutive SummarizationStrategy failures and emit a single error once the strategy has failed three times without a successful summary. Reset the escalation state after a successful summary so only persistent failures become loud.

Validation: uv run pytest packages/core/tests/core/test_compaction.py -k 'repeated_summary_failures or resets_failure_escalation' -q; uv run pytest packages/core/tests/core/test_compaction.py -q; uv run poe check -P core.
Avoid rebuilding and re-tokenizing the full selected summary transcript on every candidate group while preserving complete-group selection and oversized leading group skipping.

Tighten the scripted summarizer test helper to expected Exception failures instead of BaseException.

Verification: uv run pytest packages/core/tests/core/test_compaction.py -q; uv run poe syntax -P core.
@scarab-systems
scarab-systems force-pushed the scarab-systems/python-summarization-budget-7214 branch from 3da6007 to 086442c Compare July 29, 2026 00:51
@scarab-systems
scarab-systems requested a review from Copilot July 29, 2026 00:53

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.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

python/packages/core/agent_framework/_compaction.py:1192

  • The warning logged when no group fits the input budget doesn’t include the actual max_summary_input_tokens value, which makes it harder to diagnose misconfiguration or unexpectedly large prompts/groups in production logs.
            if self.max_summary_input_tokens is not None:
                logger.warning(
                    "Skipping summarization compaction: no complete message group fits within max_summary_input_tokens."
                )

@github-actions

Copy link
Copy Markdown
Contributor

Python Test Coverage

Python Test Coverage Report •
FileStmtsMissCoverMissing
packages/core/agent_framework
   _compaction.py7556391%117–118, 126, 193–194, 212–213, 230, 264, 278, 285, 300–301, 355, 362, 378, 428, 452, 483, 532, 538, 540, 559, 603–608, 620, 704, 706, 721, 766, 828, 954, 960–964, 967–969, 975, 994, 1107, 1109, 1111, 1148, 1155, 1160, 1175, 1189–1190, 1193–1194, 1296, 1319, 1331, 1427, 1454, 1538
TOTAL45640448490% 

Python Unit Test Overview

Tests Skipped Failures Errors Time
9419 34 💤 0 ❌ 0 🔥 2m 24s ⏱️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Usage: [Issues, PRs], Target: Python

Projects

None yet

3 participants