From 7e2c5ad4e6acf3792e701c2ae5c78a5b50b1cfe9 Mon Sep 17 00:00:00 2001 From: Chris Rickman Date: Thu, 5 Mar 2026 03:10:40 -0800 Subject: [PATCH] Tuning --- .../Program.cs | 2 +- .../SlidingWindowCompactionStrategy.cs | 82 ++++++++++++------- .../SummarizationCompactionStrategy.cs | 24 ++++-- .../ToolResultCompactionStrategy.cs | 27 +++--- .../TruncationCompactionStrategy.cs | 28 ++++--- .../SlidingWindowCompactionStrategyTests.cs | 64 +++++++++++---- .../SummarizationCompactionStrategyTests.cs | 20 ++--- .../ToolResultCompactionStrategyTests.cs | 16 ++-- .../TruncationCompactionStrategyTests.cs | 26 +++--- 9 files changed, 181 insertions(+), 108 deletions(-) diff --git a/dotnet/samples/02-agents/Agents/Agent_Step18_CompactionPipeline/Program.cs b/dotnet/samples/02-agents/Agents/Agent_Step18_CompactionPipeline/Program.cs index 0a57de892e..0118ac1d60 100644 --- a/dotnet/samples/02-agents/Agents/Agent_Step18_CompactionPipeline/Program.cs +++ b/dotnet/samples/02-agents/Agents/Agent_Step18_CompactionPipeline/Program.cs @@ -47,7 +47,7 @@ PipelineCompactionStrategy compactionPipeline = new SummarizationCompactionStrategy(summarizerChatClient, CompactionTriggers.TokensExceed(0x500)), // 3. Aggressive: keep only the last N user turns and their responses - new SlidingWindowCompactionStrategy(maximumTurns: 4), + new SlidingWindowCompactionStrategy(CompactionTriggers.TurnsExceed(4)), // 4. Emergency: drop oldest groups until under the token budget new TruncationCompactionStrategy(CompactionTriggers.TokensExceed(0x8000))); diff --git a/dotnet/src/Microsoft.Agents.AI/Compaction/SlidingWindowCompactionStrategy.cs b/dotnet/src/Microsoft.Agents.AI/Compaction/SlidingWindowCompactionStrategy.cs index a811da19f7..6a7f2e5c73 100644 --- a/dotnet/src/Microsoft.Agents.AI/Compaction/SlidingWindowCompactionStrategy.cs +++ b/dotnet/src/Microsoft.Agents.AI/Compaction/SlidingWindowCompactionStrategy.cs @@ -1,5 +1,6 @@ // Copyright (c) Microsoft. All rights reserved. +using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -7,20 +8,18 @@ using System.Threading.Tasks; namespace Microsoft.Agents.AI.Compaction; /// -/// A compaction strategy that keeps only the most recent user turns and their -/// associated response groups, removing older turns to bound conversation length. +/// A compaction strategy that removes the oldest user turns and their associated response groups +/// to bound conversation length. /// /// /// /// This strategy always preserves system messages. It identifies user turns in the -/// conversation (via ) and keeps the last -/// turns along with all response groups (assistant replies, -/// tool call groups) that belong to each kept turn. +/// conversation (via ) and excludes the oldest turns +/// one at a time until the condition is met. /// /// -/// The predicate controls when compaction proceeds. -/// When , a default trigger of -/// with is used. +/// is a hard floor: even if the +/// has not been reached, compaction will not touch the last non-system groups. /// /// /// This strategy is more predictable than token-based truncation for bounding conversation @@ -30,62 +29,87 @@ namespace Microsoft.Agents.AI.Compaction; public sealed class SlidingWindowCompactionStrategy : CompactionStrategy { /// - /// The default maximum number of user turns to retain before compaction occurs. This default is a reasonable starting point - /// for many conversations, but should be tuned based on the expected conversation length and token budget. + /// The default minimum number of most-recent non-system groups to preserve. /// - public const int DefaultMaximumTurns = 32; + public const int DefaultMinimumPreserved = 1; /// /// Initializes a new instance of the class. /// - /// - /// The maximum number of user turns to keep. Older turns and their associated responses are removed. + /// + /// The that controls when compaction proceeds. + /// Use for turn-based thresholds. + /// + /// + /// The minimum number of most-recent non-system message groups to preserve. + /// This is a hard floor — compaction will not exclude groups beyond this limit, + /// regardless of the target condition. /// /// /// An optional target condition that controls when compaction stops. When , - /// defaults to the inverse of the auto-derived trigger — compaction stops as soon as the turn count is within bounds. + /// defaults to the inverse of the — compaction stops as soon as the trigger would no longer fire. /// - public SlidingWindowCompactionStrategy(int maximumTurns = DefaultMaximumTurns, CompactionTrigger? target = null) - : base(CompactionTriggers.TurnsExceed(maximumTurns), target) + public SlidingWindowCompactionStrategy(CompactionTrigger trigger, int minimumPreserved = DefaultMinimumPreserved, CompactionTrigger? target = null) + : base(trigger, target) { - this.MaxTurns = maximumTurns; + this.MinimumPreserved = minimumPreserved; } /// - /// Gets the maximum number of user turns to retain after compaction. + /// Gets the minimum number of most-recent non-system groups that are always preserved. + /// This is a hard floor that compaction cannot exceed, regardless of the target condition. /// - public int MaxTurns { get; } + public int MinimumPreserved { get; } /// protected override Task ApplyCompactionAsync(MessageIndex index, CancellationToken cancellationToken) { - // Collect distinct included turn indices in order - List includedTurns = []; + // Identify protected groups: the N most-recent non-system, non-excluded groups + List nonSystemIncludedIndices = []; foreach (MessageGroup group in index.Groups) { - if (!group.IsExcluded && group.TurnIndex is int turnIndex && !includedTurns.Contains(turnIndex)) + if (!group.IsExcluded && group.Kind != MessageGroupKind.System) { - includedTurns.Add(turnIndex); + nonSystemIncludedIndices.Add(index.Groups.IndexOf(group)); } } - if (includedTurns.Count <= this.MaxTurns) + int protectedStart = Math.Max(0, nonSystemIncludedIndices.Count - this.MinimumPreserved); + HashSet protectedGroupIndices = []; + for (int i = protectedStart; i < nonSystemIncludedIndices.Count; i++) { - return Task.FromResult(false); + protectedGroupIndices.Add(nonSystemIncludedIndices[i]); + } + + // Collect distinct included turn indices in order (oldest first), excluding protected groups + List excludableTurns = []; + for (int i = 0; i < index.Groups.Count; i++) + { + MessageGroup group = index.Groups[i]; + if (!group.IsExcluded + && group.Kind != MessageGroupKind.System + && !protectedGroupIndices.Contains(i) + && group.TurnIndex is int turnIndex + && !excludableTurns.Contains(turnIndex)) + { + excludableTurns.Add(turnIndex); + } } // Exclude one turn at a time from oldest, re-checking target after each - int turnsToRemove = includedTurns.Count - this.MaxTurns; bool compacted = false; - for (int t = 0; t < turnsToRemove; t++) + for (int t = 0; t < excludableTurns.Count; t++) { - int turnToExclude = includedTurns[t]; + int turnToExclude = excludableTurns[t]; for (int i = 0; i < index.Groups.Count; i++) { MessageGroup group = index.Groups[i]; - if (!group.IsExcluded && group.Kind != MessageGroupKind.System && group.TurnIndex == turnToExclude) + if (!group.IsExcluded + && group.Kind != MessageGroupKind.System + && !protectedGroupIndices.Contains(i) + && group.TurnIndex == turnToExclude) { group.IsExcluded = true; group.ExcludeReason = $"Excluded by {nameof(SlidingWindowCompactionStrategy)}"; diff --git a/dotnet/src/Microsoft.Agents.AI/Compaction/SummarizationCompactionStrategy.cs b/dotnet/src/Microsoft.Agents.AI/Compaction/SummarizationCompactionStrategy.cs index 3ec645e372..0e7c01719c 100644 --- a/dotnet/src/Microsoft.Agents.AI/Compaction/SummarizationCompactionStrategy.cs +++ b/dotnet/src/Microsoft.Agents.AI/Compaction/SummarizationCompactionStrategy.cs @@ -16,12 +16,16 @@ namespace Microsoft.Agents.AI.Compaction; /// /// /// -/// This strategy protects system messages and the most recent +/// This strategy protects system messages and the most recent /// non-system groups. All older groups are collected and sent to the /// for summarization. The resulting summary replaces those messages as a single assistant message /// with . /// /// +/// is a hard floor: even if the +/// has not been reached, compaction will not touch the last non-system groups. +/// +/// /// The predicate controls when compaction proceeds. /// When , the strategy compacts whenever there are groups older than the preserve window. /// Use for common trigger conditions such as token thresholds. @@ -50,9 +54,10 @@ public sealed class SummarizationCompactionStrategy : CompactionStrategy /// /// The that controls when compaction proceeds. /// - /// - /// The number of most-recent non-system message groups to protect from summarization. - /// Defaults to 4, preserving the current and recent exchanges. + /// + /// The minimum number of most-recent non-system message groups to preserve. + /// This is a hard floor — compaction will not summarize groups beyond this limit, + /// regardless of the target condition. Defaults to 4, preserving the current and recent exchanges. /// /// /// An optional custom system prompt for the summarization LLM call. When , @@ -65,13 +70,13 @@ public sealed class SummarizationCompactionStrategy : CompactionStrategy public SummarizationCompactionStrategy( IChatClient chatClient, CompactionTrigger trigger, - int preserveRecentGroups = 4, + int minimumPreserved = 4, string? summarizationPrompt = null, CompactionTrigger? target = null) : base(trigger, target) { this.ChatClient = Throw.IfNull(chatClient); - this.PreserveRecentGroups = preserveRecentGroups; + this.MinimumPreserved = minimumPreserved; this.SummarizationPrompt = summarizationPrompt ?? DefaultSummarizationPrompt; } @@ -81,9 +86,10 @@ public sealed class SummarizationCompactionStrategy : CompactionStrategy public IChatClient ChatClient { get; } /// - /// Gets the number of most-recent non-system groups to protect from summarization. + /// Gets the minimum number of most-recent non-system groups that are always preserved. + /// This is a hard floor that compaction cannot exceed, regardless of the target condition. /// - public int PreserveRecentGroups { get; } + public int MinimumPreserved { get; } /// /// Gets the prompt used when requesting summaries from the chat client. @@ -104,7 +110,7 @@ public sealed class SummarizationCompactionStrategy : CompactionStrategy } } - int protectedFromEnd = Math.Min(this.PreserveRecentGroups, nonSystemIncludedCount); + int protectedFromEnd = Math.Min(this.MinimumPreserved, nonSystemIncludedCount); int maxSummarizable = nonSystemIncludedCount - protectedFromEnd; if (maxSummarizable <= 0) diff --git a/dotnet/src/Microsoft.Agents.AI/Compaction/ToolResultCompactionStrategy.cs b/dotnet/src/Microsoft.Agents.AI/Compaction/ToolResultCompactionStrategy.cs index 8692e47159..a54c096cd2 100644 --- a/dotnet/src/Microsoft.Agents.AI/Compaction/ToolResultCompactionStrategy.cs +++ b/dotnet/src/Microsoft.Agents.AI/Compaction/ToolResultCompactionStrategy.cs @@ -21,6 +21,10 @@ namespace Microsoft.Agents.AI.Compaction; /// [Tool calls: get_weather, search_docs]. /// /// +/// is a hard floor: even if the +/// has not been reached, compaction will not touch the last non-system groups. +/// +/// /// The predicate controls when compaction proceeds. /// When , a default compound trigger of /// AND @@ -30,9 +34,9 @@ namespace Microsoft.Agents.AI.Compaction; public sealed class ToolResultCompactionStrategy : CompactionStrategy { /// - /// The default number of most-recent non-system groups to protect from collapsing. + /// The default minimum number of most-recent non-system groups to preserve. /// - public const int DefaultPreserveRecentGroups = 2; + public const int DefaultMinimumPreserved = 2; /// /// Initializes a new instance of the class. @@ -40,24 +44,27 @@ public sealed class ToolResultCompactionStrategy : CompactionStrategy /// /// The that controls when compaction proceeds. /// - /// - /// The number of most-recent non-system message groups to protect from collapsing. - /// Defaults to , ensuring the current turn's tool interactions remain visible. + /// + /// The minimum number of most-recent non-system message groups to preserve. + /// This is a hard floor — compaction will not collapse groups beyond this limit, + /// regardless of the target condition. + /// Defaults to , ensuring the current turn's tool interactions remain visible. /// /// /// An optional target condition that controls when compaction stops. When , /// defaults to the inverse of the — compaction stops as soon as the trigger would no longer fire. /// - public ToolResultCompactionStrategy(CompactionTrigger trigger, int preserveRecentGroups = DefaultPreserveRecentGroups, CompactionTrigger? target = null) + public ToolResultCompactionStrategy(CompactionTrigger trigger, int minimumPreserved = DefaultMinimumPreserved, CompactionTrigger? target = null) : base(trigger, target) { - this.PreserveRecentGroups = preserveRecentGroups; + this.MinimumPreserved = minimumPreserved; } /// - /// Gets the number of most-recent non-system groups to protect from collapsing. + /// Gets the minimum number of most-recent non-system groups that are always preserved. + /// This is a hard floor that compaction cannot exceed, regardless of the target condition. /// - public int PreserveRecentGroups { get; } + public int MinimumPreserved { get; } /// protected override Task ApplyCompactionAsync(MessageIndex index, CancellationToken cancellationToken) @@ -73,7 +80,7 @@ public sealed class ToolResultCompactionStrategy : CompactionStrategy } } - int protectedStart = Math.Max(0, nonSystemIncludedIndices.Count - this.PreserveRecentGroups); + int protectedStart = Math.Max(0, nonSystemIncludedIndices.Count - this.MinimumPreserved); HashSet protectedGroupIndices = []; for (int i = protectedStart; i < nonSystemIncludedIndices.Count; i++) { diff --git a/dotnet/src/Microsoft.Agents.AI/Compaction/TruncationCompactionStrategy.cs b/dotnet/src/Microsoft.Agents.AI/Compaction/TruncationCompactionStrategy.cs index 57a0eea528..3c7d8890f2 100644 --- a/dotnet/src/Microsoft.Agents.AI/Compaction/TruncationCompactionStrategy.cs +++ b/dotnet/src/Microsoft.Agents.AI/Compaction/TruncationCompactionStrategy.cs @@ -7,7 +7,7 @@ namespace Microsoft.Agents.AI.Compaction; /// /// A compaction strategy that removes the oldest non-system message groups, -/// keeping the most recent groups up to . +/// keeping at least most-recent groups intact. /// /// /// @@ -16,6 +16,10 @@ namespace Microsoft.Agents.AI.Compaction; /// corresponding tool result messages are always removed together. /// /// +/// is a hard floor: even if the +/// has not been reached, compaction will not touch the last non-system groups. +/// +/// /// The controls when compaction proceeds. /// Use for common trigger conditions such as token or group thresholds. /// @@ -23,9 +27,9 @@ namespace Microsoft.Agents.AI.Compaction; public sealed class TruncationCompactionStrategy : CompactionStrategy { /// - /// The default number of most-recent non-system groups to protect from collapsing. + /// The default minimum number of most-recent non-system groups to preserve. /// - public const int DefaultPreserveRecentGroups = 32; + public const int DefaultMinimumPreserved = 32; /// /// Initializes a new instance of the class. @@ -33,24 +37,26 @@ public sealed class TruncationCompactionStrategy : CompactionStrategy /// /// The that controls when compaction proceeds. /// - /// - /// The minimum number of most-recent non-system message groups to keep. - /// Defaults to 1 so that at least the latest exchange is always preserved. + /// + /// The minimum number of most-recent non-system message groups to preserve. + /// This is a hard floor — compaction will not remove groups beyond this limit, + /// regardless of the target condition. /// /// /// An optional target condition that controls when compaction stops. When , /// defaults to the inverse of the — compaction stops as soon as the trigger would no longer fire. /// - public TruncationCompactionStrategy(CompactionTrigger trigger, int preserveRecentGroups = DefaultPreserveRecentGroups, CompactionTrigger? target = null) + public TruncationCompactionStrategy(CompactionTrigger trigger, int minimumPreserved = DefaultMinimumPreserved, CompactionTrigger? target = null) : base(trigger, target) { - this.PreserveRecentGroups = preserveRecentGroups; + this.MinimumPreserved = minimumPreserved; } /// - /// Gets the minimum number of most-recent non-system message groups to retain after compaction. + /// Gets the minimum number of most-recent non-system message groups that are always preserved. + /// This is a hard floor that compaction cannot exceed, regardless of the target condition. /// - public int PreserveRecentGroups { get; } + public int MinimumPreserved { get; } /// protected override Task ApplyCompactionAsync(MessageIndex index, CancellationToken cancellationToken) @@ -66,7 +72,7 @@ public sealed class TruncationCompactionStrategy : CompactionStrategy } } - int maxRemovable = removableCount - this.PreserveRecentGroups; + int maxRemovable = removableCount - this.MinimumPreserved; if (maxRemovable <= 0) { return Task.FromResult(false); diff --git a/dotnet/tests/Microsoft.Agents.AI.UnitTests/Compaction/SlidingWindowCompactionStrategyTests.cs b/dotnet/tests/Microsoft.Agents.AI.UnitTests/Compaction/SlidingWindowCompactionStrategyTests.cs index 74d057e9f0..2d78c2e720 100644 --- a/dotnet/tests/Microsoft.Agents.AI.UnitTests/Compaction/SlidingWindowCompactionStrategyTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.UnitTests/Compaction/SlidingWindowCompactionStrategyTests.cs @@ -15,8 +15,8 @@ public class SlidingWindowCompactionStrategyTests [Fact] public async Task CompactAsyncBelowMaxTurnsReturnsFalseAsync() { - // Arrange - SlidingWindowCompactionStrategy strategy = new(maximumTurns: 3); + // Arrange — trigger requires > 3 turns, conversation has 2 + SlidingWindowCompactionStrategy strategy = new(CompactionTriggers.TurnsExceed(3)); MessageIndex groups = MessageIndex.Create( [ new ChatMessage(ChatRole.User, "Q1"), @@ -35,8 +35,8 @@ public class SlidingWindowCompactionStrategyTests [Fact] public async Task CompactAsyncExceedsMaxTurnsExcludesOldestTurnsAsync() { - // Arrange — keep 2 turns, conversation has 3 - SlidingWindowCompactionStrategy strategy = new(maximumTurns: 2); + // Arrange — trigger on > 2 turns, conversation has 3 + SlidingWindowCompactionStrategy strategy = new(CompactionTriggers.TurnsExceed(2)); MessageIndex groups = MessageIndex.Create( [ new ChatMessage(ChatRole.User, "Q1"), @@ -65,8 +65,8 @@ public class SlidingWindowCompactionStrategyTests [Fact] public async Task CompactAsyncPreservesSystemMessagesAsync() { - // Arrange - SlidingWindowCompactionStrategy strategy = new(maximumTurns: 1); + // Arrange — trigger on > 1 turn + SlidingWindowCompactionStrategy strategy = new(CompactionTriggers.TurnsExceed(1)); MessageIndex groups = MessageIndex.Create( [ new ChatMessage(ChatRole.System, "You are helpful."), @@ -89,8 +89,8 @@ public class SlidingWindowCompactionStrategyTests [Fact] public async Task CompactAsyncPreservesToolCallGroupsInKeptTurnsAsync() { - // Arrange - SlidingWindowCompactionStrategy strategy = new(maximumTurns: 1); + // Arrange — trigger on > 1 turn + SlidingWindowCompactionStrategy strategy = new(CompactionTriggers.TurnsExceed(1)); MessageIndex groups = MessageIndex.Create( [ new ChatMessage(ChatRole.User, "Q1"), @@ -114,10 +114,10 @@ public class SlidingWindowCompactionStrategyTests } [Fact] - public async Task CompactAsyncCustomTriggerOverridesDefaultAsync() + public async Task CompactAsyncTriggerNotMetReturnsFalseAsync() { - // Arrange — custom trigger: only compact when tokens exceed threshold - SlidingWindowCompactionStrategy strategy = new(maximumTurns: 99); + // Arrange — trigger requires > 99 turns + SlidingWindowCompactionStrategy strategy = new(CompactionTriggers.TurnsExceed(99)); MessageIndex groups = MessageIndex.Create( [ @@ -126,7 +126,7 @@ public class SlidingWindowCompactionStrategyTests new ChatMessage(ChatRole.User, "Q3"), ]); - // Act — tokens are tiny, trigger not met + // Act bool result = await strategy.CompactAsync(groups); // Assert @@ -136,8 +136,8 @@ public class SlidingWindowCompactionStrategyTests [Fact] public async Task CompactAsyncIncludedMessagesContainOnlyKeptTurnsAsync() { - // Arrange - SlidingWindowCompactionStrategy strategy = new(maximumTurns: 1); + // Arrange — trigger on > 1 turn + SlidingWindowCompactionStrategy strategy = new(CompactionTriggers.TurnsExceed(1)); MessageIndex groups = MessageIndex.Create( [ new ChatMessage(ChatRole.System, "System"), @@ -161,13 +161,13 @@ public class SlidingWindowCompactionStrategyTests [Fact] public async Task CompactAsyncCustomTargetStopsExcludingEarlyAsync() { - // Arrange — 4 turns, maxTurns=1 means 3 should be excluded - // But custom target stops after removing 1 turn + // Arrange — trigger on > 1 turn, custom target stops after removing 1 turn int removeCount = 0; CompactionTrigger targetAfterOne = _ => ++removeCount >= 1; SlidingWindowCompactionStrategy strategy = new( - maximumTurns: 1, + CompactionTriggers.TurnsExceed(1), + minimumPreserved: 0, target: targetAfterOne); MessageIndex index = MessageIndex.Create( @@ -191,4 +191,34 @@ public class SlidingWindowCompactionStrategyTests Assert.False(index.Groups[2].IsExcluded); // Q2 (turn 2) — kept Assert.False(index.Groups[3].IsExcluded); // A2 (turn 2) } + + [Fact] + public async Task CompactAsyncMinimumPreservedStopsCompactionAsync() + { + // Arrange — always trigger with never-satisfied target, but MinimumPreserved = 2 is hard floor + SlidingWindowCompactionStrategy strategy = new( + CompactionTriggers.TurnsExceed(1), + minimumPreserved: 2, + target: _ => false); + + MessageIndex index = MessageIndex.Create( + [ + new ChatMessage(ChatRole.User, "Q1"), + new ChatMessage(ChatRole.Assistant, "A1"), + new ChatMessage(ChatRole.User, "Q2"), + new ChatMessage(ChatRole.Assistant, "A2"), + new ChatMessage(ChatRole.User, "Q3"), + new ChatMessage(ChatRole.Assistant, "A3"), + ]); + + // Act + bool result = await strategy.CompactAsync(index); + + // Assert — target never says stop, but MinimumPreserved=2 prevents removing the last 2 groups + Assert.True(result); + Assert.Equal(2, index.IncludedGroupCount); + // Last 2 non-system groups must be preserved + Assert.False(index.Groups[4].IsExcluded); // Q3 + Assert.False(index.Groups[5].IsExcluded); // A3 + } } diff --git a/dotnet/tests/Microsoft.Agents.AI.UnitTests/Compaction/SummarizationCompactionStrategyTests.cs b/dotnet/tests/Microsoft.Agents.AI.UnitTests/Compaction/SummarizationCompactionStrategyTests.cs index a71fc4697f..d12d490dd4 100644 --- a/dotnet/tests/Microsoft.Agents.AI.UnitTests/Compaction/SummarizationCompactionStrategyTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.UnitTests/Compaction/SummarizationCompactionStrategyTests.cs @@ -38,7 +38,7 @@ public class SummarizationCompactionStrategyTests SummarizationCompactionStrategy strategy = new( CreateMockChatClient(), CompactionTriggers.TokensExceed(100000), - preserveRecentGroups: 1); + minimumPreserved: 1); MessageIndex index = MessageIndex.Create( [ @@ -61,7 +61,7 @@ public class SummarizationCompactionStrategyTests SummarizationCompactionStrategy strategy = new( CreateMockChatClient("Key facts from earlier."), AlwaysTrigger, - preserveRecentGroups: 1); + minimumPreserved: 1); MessageIndex index = MessageIndex.Create( [ @@ -92,7 +92,7 @@ public class SummarizationCompactionStrategyTests SummarizationCompactionStrategy strategy = new( CreateMockChatClient(), AlwaysTrigger, - preserveRecentGroups: 1); + minimumPreserved: 1); MessageIndex index = MessageIndex.Create( [ @@ -119,7 +119,7 @@ public class SummarizationCompactionStrategyTests SummarizationCompactionStrategy strategy = new( CreateMockChatClient("Summary text."), AlwaysTrigger, - preserveRecentGroups: 1); + minimumPreserved: 1); MessageIndex index = MessageIndex.Create( [ @@ -146,7 +146,7 @@ public class SummarizationCompactionStrategyTests SummarizationCompactionStrategy strategy = new( CreateMockChatClient(" "), AlwaysTrigger, - preserveRecentGroups: 1); + minimumPreserved: 1); MessageIndex index = MessageIndex.Create( [ @@ -169,7 +169,7 @@ public class SummarizationCompactionStrategyTests SummarizationCompactionStrategy strategy = new( CreateMockChatClient(), AlwaysTrigger, - preserveRecentGroups: 5); + minimumPreserved: 5); MessageIndex index = MessageIndex.Create( [ @@ -202,7 +202,7 @@ public class SummarizationCompactionStrategyTests SummarizationCompactionStrategy strategy = new( mockClient.Object, AlwaysTrigger, - preserveRecentGroups: 1, + minimumPreserved: 1, summarizationPrompt: customPrompt); MessageIndex index = MessageIndex.Create( @@ -226,7 +226,7 @@ public class SummarizationCompactionStrategyTests SummarizationCompactionStrategy strategy = new( CreateMockChatClient(), AlwaysTrigger, - preserveRecentGroups: 1); + minimumPreserved: 1); MessageIndex index = MessageIndex.Create( [ @@ -253,7 +253,7 @@ public class SummarizationCompactionStrategyTests SummarizationCompactionStrategy strategy = new( CreateMockChatClient("Partial summary."), AlwaysTrigger, - preserveRecentGroups: 1, + minimumPreserved: 1, target: targetAfterOne); MessageIndex index = MessageIndex.Create( @@ -279,7 +279,7 @@ public class SummarizationCompactionStrategyTests SummarizationCompactionStrategy strategy = new( CreateMockChatClient("Summary."), AlwaysTrigger, - preserveRecentGroups: 2); + minimumPreserved: 2); MessageIndex index = MessageIndex.Create( [ diff --git a/dotnet/tests/Microsoft.Agents.AI.UnitTests/Compaction/ToolResultCompactionStrategyTests.cs b/dotnet/tests/Microsoft.Agents.AI.UnitTests/Compaction/ToolResultCompactionStrategyTests.cs index 39c03f2631..66300e69f0 100644 --- a/dotnet/tests/Microsoft.Agents.AI.UnitTests/Compaction/ToolResultCompactionStrategyTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.UnitTests/Compaction/ToolResultCompactionStrategyTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. using System.Collections.Generic; using System.Threading.Tasks; @@ -41,7 +41,7 @@ public class ToolResultCompactionStrategyTests // Arrange — always trigger ToolResultCompactionStrategy strategy = new( trigger: _ => true, - preserveRecentGroups: 1); + minimumPreserved: 1); MessageIndex groups = MessageIndex.Create( [ @@ -71,7 +71,7 @@ public class ToolResultCompactionStrategyTests // Arrange — protect 2 recent non-system groups (the tool group + Q2) ToolResultCompactionStrategy strategy = new( trigger: _ => true, - preserveRecentGroups: 3); + minimumPreserved: 3); MessageIndex groups = MessageIndex.Create( [ @@ -94,7 +94,7 @@ public class ToolResultCompactionStrategyTests // Arrange ToolResultCompactionStrategy strategy = new( trigger: _ => true, - preserveRecentGroups: 1); + minimumPreserved: 1); MessageIndex groups = MessageIndex.Create( [ @@ -119,7 +119,7 @@ public class ToolResultCompactionStrategyTests // Arrange — assistant calls two tools ToolResultCompactionStrategy strategy = new( trigger: _ => true, - preserveRecentGroups: 1); + minimumPreserved: 1); ChatMessage multiToolCall = new(ChatRole.Assistant, [ @@ -152,7 +152,7 @@ public class ToolResultCompactionStrategyTests // Arrange — trigger fires but no tool groups to collapse ToolResultCompactionStrategy strategy = new( trigger: _ => true, - preserveRecentGroups: 0); + minimumPreserved: 0); MessageIndex groups = MessageIndex.Create( [ @@ -175,7 +175,7 @@ public class ToolResultCompactionStrategyTests CompactionTriggers.All( CompactionTriggers.TokensExceed(0), CompactionTriggers.HasToolCalls()), - preserveRecentGroups: 1); + minimumPreserved: 1); MessageIndex groups = MessageIndex.Create( [ @@ -201,7 +201,7 @@ public class ToolResultCompactionStrategyTests ToolResultCompactionStrategy strategy = new( trigger: _ => true, - preserveRecentGroups: 1, + minimumPreserved: 1, target: targetAfterOne); MessageIndex index = MessageIndex.Create( diff --git a/dotnet/tests/Microsoft.Agents.AI.UnitTests/Compaction/TruncationCompactionStrategyTests.cs b/dotnet/tests/Microsoft.Agents.AI.UnitTests/Compaction/TruncationCompactionStrategyTests.cs index 1799758ddd..ee08611653 100644 --- a/dotnet/tests/Microsoft.Agents.AI.UnitTests/Compaction/TruncationCompactionStrategyTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.UnitTests/Compaction/TruncationCompactionStrategyTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. using System.Linq; using System.Threading.Tasks; @@ -18,7 +18,7 @@ public class TruncationCompactionStrategyTests public async Task CompactAsyncAlwaysTriggerCompactsToPreserveRecentAsync() { // Arrange — always-trigger means always compact - TruncationCompactionStrategy strategy = new(s_alwaysTrigger, preserveRecentGroups: 1); + TruncationCompactionStrategy strategy = new(s_alwaysTrigger, minimumPreserved: 1); MessageIndex groups = MessageIndex.Create( [ new ChatMessage(ChatRole.User, "First"), @@ -39,7 +39,7 @@ public class TruncationCompactionStrategyTests { // Arrange — trigger requires > 1000 tokens, conversation is tiny TruncationCompactionStrategy strategy = new( - preserveRecentGroups: 1, + minimumPreserved: 1, trigger: CompactionTriggers.TokensExceed(1000)); MessageIndex groups = MessageIndex.Create( @@ -61,7 +61,7 @@ public class TruncationCompactionStrategyTests { // Arrange — trigger on groups > 2 TruncationCompactionStrategy strategy = new( - preserveRecentGroups: 1, + minimumPreserved: 1, trigger: CompactionTriggers.GroupsExceed(2)); MessageIndex groups = MessageIndex.Create( @@ -89,7 +89,7 @@ public class TruncationCompactionStrategyTests public async Task CompactAsyncPreservesSystemMessagesAsync() { // Arrange - TruncationCompactionStrategy strategy = new(s_alwaysTrigger, preserveRecentGroups: 1); + TruncationCompactionStrategy strategy = new(s_alwaysTrigger, minimumPreserved: 1); MessageIndex groups = MessageIndex.Create( [ new ChatMessage(ChatRole.System, "You are helpful."), @@ -117,7 +117,7 @@ public class TruncationCompactionStrategyTests public async Task CompactAsyncPreservesToolCallGroupAtomicityAsync() { // Arrange - TruncationCompactionStrategy strategy = new(s_alwaysTrigger, preserveRecentGroups: 1); + TruncationCompactionStrategy strategy = new(s_alwaysTrigger, minimumPreserved: 1); ChatMessage assistantToolCall= new(ChatRole.Assistant, [new FunctionCallContent("call1", "get_weather")]); ChatMessage toolResult = new(ChatRole.Tool, "Sunny"); @@ -141,7 +141,7 @@ public class TruncationCompactionStrategyTests public async Task CompactAsyncSetsExcludeReasonAsync() { // Arrange - TruncationCompactionStrategy strategy = new(s_alwaysTrigger, preserveRecentGroups: 1); + TruncationCompactionStrategy strategy = new(s_alwaysTrigger, minimumPreserved: 1); MessageIndex groups = MessageIndex.Create( [ new ChatMessage(ChatRole.User, "Old"), @@ -160,7 +160,7 @@ public class TruncationCompactionStrategyTests public async Task CompactAsyncSkipsAlreadyExcludedGroupsAsync() { // Arrange - TruncationCompactionStrategy strategy = new(s_alwaysTrigger, preserveRecentGroups: 1); + TruncationCompactionStrategy strategy = new(s_alwaysTrigger, minimumPreserved: 1); MessageIndex groups = MessageIndex.Create( [ new ChatMessage(ChatRole.User, "Already excluded"), @@ -180,10 +180,10 @@ public class TruncationCompactionStrategyTests } [Fact] - public async Task CompactAsyncPreserveRecentGroupsKeepsMultipleAsync() + public async Task CompactAsyncMinimumPreservedKeepsMultipleAsync() { // Arrange — keep 2 most recent - TruncationCompactionStrategy strategy = new(s_alwaysTrigger, preserveRecentGroups: 2); + TruncationCompactionStrategy strategy = new(s_alwaysTrigger, minimumPreserved: 2); MessageIndex groups = MessageIndex.Create( [ new ChatMessage(ChatRole.User, "Q1"), @@ -207,7 +207,7 @@ public class TruncationCompactionStrategyTests public async Task CompactAsyncNothingToRemoveReturnsFalseAsync() { // Arrange — preserve 5 but only 2 groups - TruncationCompactionStrategy strategy = new(s_alwaysTrigger, preserveRecentGroups: 5); + TruncationCompactionStrategy strategy = new(s_alwaysTrigger, minimumPreserved: 5); MessageIndex groups = MessageIndex.Create( [ new ChatMessage(ChatRole.User, "Hello"), @@ -230,7 +230,7 @@ public class TruncationCompactionStrategyTests TruncationCompactionStrategy strategy = new( s_alwaysTrigger, - preserveRecentGroups: 1, + minimumPreserved: 1, target: targetAfterOne); MessageIndex groups = MessageIndex.Create( @@ -258,7 +258,7 @@ public class TruncationCompactionStrategyTests // Arrange — trigger on groups > 2, target is default (inverse of trigger: groups <= 2) TruncationCompactionStrategy strategy = new( CompactionTriggers.GroupsExceed(2), - preserveRecentGroups: 1); + minimumPreserved: 1); MessageIndex groups = MessageIndex.Create( [