Skip to content

Python: [Feature]: a budget-gated escalating compaction composition (summarize before you delete) #7226

Description

@antsok

Description

Problem

The stock before-phase default (ContextWindowCompactionStrategy) escalates from tool-result collapse straight to deleting the oldest groups at 80% of budget. The middle options the library already ships — SummarizationStrategy (degrade content gracefully) and SelectiveToolCallCompactionStrategy (drop stale tool traffic first) — are not reachable from any composed default, so a long conversation loses history that a cheaper, less destructive stage could have preserved.

TokenBudgetComposedStrategy is close but not usable as the harness before-phase:

  • its strict fallback loop can exclude every group, including system groups (_compaction.py ~1189-1209) — an empty projection the provider rejects (contents are required / Messages are required);
  • stages are not individually budget-gated: there is no "stop escalating as soon as the target is met" contract, no per-stage keep-N configuration, and no observability of what each stage did.

Requested

A composed strategy (or an extension of TokenBudgetComposedStrategy) with:

  1. Ordered stages with early-stop: run stage N only if included tokens still exceed the target after stage N-1; re-annotate/re-tokenize between stages (inserted summaries carry token_count=None and silently under-count otherwise).
  2. Per-stage configuration: keep-N for tool-result/selective stages, target count for summarization, and a separate (higher) threshold for the destructive truncation stage.
  3. A floor: never produce a projection with zero non-system messages.
  4. Observability: a log line (or callback) per stage that changed — counts, not content.
  5. Loop-aware after-phase cadence: harness auto-loops re-invoke the agent per iteration, so after_run digestion fires per iteration — at small keep-N a model's fresh parallel tool results are digested to assistant text before its next roundtrip reads them (observed live: the model concluded its tools returned "no results" and looped re-searching). The composition should digest at user-turn boundaries or debounce while the loop will immediately continue.
  6. Bounded summarization input — now split out as its own upstream bug report, filed as microsoft/agent-framework#7214: SummarizationStrategy ships the whole transcript unbounded and silently stops contributing past the provider cap; any composition should design the bound in from the start.

Evidence it matters (live, harness + AG-UI deployment)

  • Escalation preserved the task: with the composed ladder, an over-budget research conversation summarized down (S2: 20→5 messages, 106,949→11,191 est. tokens) and the model still recalled the opening request's verbatim marker afterwards. Stock behavior (delete-oldest) removed the opening request in the same scenario.
  • Scale run (906 messages / est. 1.1M tokens, 1M-context model): the ladder kept every run alive (zero run errors) where a single-stage design had nothing between "collapse tool results" and "delete history". The same run — and a second incident on a 262k-cap model (2026-07-17) — surfaced the unbounded-summarizer-input defect, filed separately as microsoft/agent-framework#7214.

Workaround (application-side, today)

ats.compaction.EscalatingCompactionStrategy: composes the three stock strategies plus a first-user-preserving truncation (separate FR, filed as microsoft/agent-framework#7216), gated on input_budget = window − output, early-stopping at 50%, truncating only above 80%, with INFO/DEBUG logging and a chunking + memoizing client in front of the summarizer (bounded map-reduce summarize requests; the before phase otherwise re-summarizes identical content every roundtrip under per-service-call persistence). All of it is composition glue that would be deleted if upstream shipped what's requested above.

Code Sample

Language/SDK

Both

Metadata

Metadata

Labels

pythonUsage: [Issues, PRs], Target: Python

Projects

Status
No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions