Skip to content

.NET: Introduce ToolResultReductionStrategy#4910

Open
arjendev wants to merge 1 commit intomicrosoft:mainfrom
arjendev:feat/tool-result-reduction-strategy
Open

.NET: Introduce ToolResultReductionStrategy#4910
arjendev wants to merge 1 commit intomicrosoft:mainfrom
arjendev:feat/tool-result-reduction-strategy

Conversation

@arjendev
Copy link

Motivation and Context

When using tools that return very large results — such as the M365 Retrieval API returning hundreds of thousands of tokens with relevance scores — there is currently no way for a framework user to selectively reduce individual tool results while preserving the tool-call message structure. The existing ToolResultCompactionStrategy collapses entire tool-call groups into YAML summaries, which loses the assistant/tool message pairing needed for multi-turn tool interactions.

This PR proposes a new ToolResultReductionStrategy that allows users to register per-tool Func<string, string> reducers — enabling them to deserialize, filter, sort, and re-serialize tool results within their own logic, while the framework handles the plumbing. I've submitted this as a PR (rather than an issue) to best convey the intent and proposed implementation for discussion.

Description

New classes:

  • ToolResultStrategyBase — Abstract base class extracted from the shared logic between compaction and reduction. Implements a sealed CompactCoreAsync with a template-method pattern, delegating to two hooks:

    • IsToolGroupEligible(group) — virtual, defaults to true
    • TransformToolGroup(group) — abstract, returns the transformed messages
  • ToolResultReductionStrategy — Applies per-tool Func<string, string> reducers to FunctionResultContent while preserving the original message structure (assistant tool-call + tool result messages). Defaults minimumPreservedGroups to 0 so reducers apply even to the current turn. Only tool-call groups containing at least one registered tool name are eligible; unregistered tools within a group are preserved as-is.

Refactored:

  • ToolResultCompactionStrategy — Now extends ToolResultStrategyBase instead of CompactionStrategy directly, removing ~110 lines of duplicated loop/protect/eligibility logic. Behavior is unchanged.

Tests:

  • 13 new tests in ToolResultReductionStrategyTests covering: trigger/target, reducer application, unregistered tool preservation, message structure preservation, current-turn reduction, minimum preserved groups, eligibility filtering, system message preservation, pre-excluded groups, no tool groups, pipeline composition, and a real-world RAG scenario (JSON chunks with relevance scores filtered within a character budget).

Key design decisions:

Compaction Reduction
Output YAML summary (single message) Structure-preserving (rebuilt tool-call group)
minimumPreservedGroups default 16 0
Group kind Summary ToolCall
Customization ToolCallFormatter delegate Per-tool Func<string, string> reducers

Both strategies compose naturally in a PipelineCompactionStrategy — reduction first (shrink results), then compaction (collapse older groups).

Contribution Checklist

  • The code builds clean without any errors or warnings
  • The PR follows the Contribution Guidelines
  • All unit tests pass, and I have added new tests where possible
  • Not a breaking change. No existing APIs are modified; ToolResultCompactionStrategy behavior is identical after the base-class refactor.

Copilot AI review requested due to automatic review settings March 25, 2026 17:46
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Introduces a new .NET compaction strategy to reduce individual tool results (per-tool reducers) while preserving assistant tool-call + tool-result message structure, and refactors shared tool-group processing into a new base class used by both reduction and existing compaction.

Changes:

  • Added ToolResultReductionStrategy to apply per-tool Func<string,string> reducers to FunctionResultContent while keeping tool-call group structure.
  • Added ToolResultStrategyBase to centralize the shared protected-group / eligibility / exclude+insert loop for tool-call-group strategies.
  • Refactored ToolResultCompactionStrategy to inherit from ToolResultStrategyBase and added unit tests for reduction behavior.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
dotnet/src/Microsoft.Agents.AI/Compaction/ToolResultStrategyBase.cs New shared base class implementing the common “exclude + insert replacement group” loop for tool-call groups.
dotnet/src/Microsoft.Agents.AI/Compaction/ToolResultReductionStrategy.cs New strategy that reduces per-tool results while attempting to preserve tool-call message structure.
dotnet/src/Microsoft.Agents.AI/Compaction/ToolResultCompactionStrategy.cs Refactor to use the new base class; core behavior moved into TransformToolGroup.
dotnet/tests/Microsoft.Agents.AI.UnitTests/Compaction/ToolResultReductionStrategyTests.cs New unit tests validating reducer application, preservation semantics, and pipeline composition.

@arjendev arjendev force-pushed the feat/tool-result-reduction-strategy branch from f293963 to 75c6468 Compare March 25, 2026 18:26
@arjendev arjendev requested a review from Copilot March 25, 2026 18:27
Copy link
Contributor

Copilot AI left a comment

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 4 out of 4 changed files in this pull request and generated 5 comments.

Copy link
Contributor

Copilot AI left a comment

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 4 out of 4 changed files in this pull request and generated no new comments.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants