// Copyright (c) Microsoft. All rights reserved. using System.Diagnostics.CodeAnalysis; using System.Linq; using Microsoft.Shared.DiagnosticIds; namespace Microsoft.Agents.AI.Compaction; /// /// Factory to create predicates. /// /// /// /// A defines a condition based on metrics used /// by a to determine when to trigger compaction and when the target /// compaction threshold has been met. /// /// /// Combine triggers with or for compound conditions. /// /// [Experimental(DiagnosticIds.Experiments.AgentsAIExperiments)] public static class CompactionTriggers { /// /// Always trigger, regardless of the message index state. /// public static readonly CompactionTrigger Always = _ => true; /// /// Never trigger, regardless of the message index state. /// public static readonly CompactionTrigger Never = _ => false; /// /// Creates a trigger that fires when the included token count is below the specified maximum. /// /// The token threshold. /// A that evaluates included token count. public static CompactionTrigger TokensBelow(int maxTokens) => index => index.IncludedTokenCount < maxTokens; /// /// Creates a trigger that fires when the included token count exceeds the specified maximum. /// /// The token threshold. /// A that evaluates included token count. public static CompactionTrigger TokensExceed(int maxTokens) => index => index.IncludedTokenCount > maxTokens; /// /// Creates a trigger that fires when the included message count exceeds the specified maximum. /// /// The message threshold. /// A that evaluates included message count. public static CompactionTrigger MessagesExceed(int maxMessages) => index => index.IncludedMessageCount > maxMessages; /// /// Creates a trigger that fires when the included user turn count exceeds the specified maximum. /// /// The turn threshold. /// A that evaluates included turn count. /// /// /// A user turn starts with a group and includes all subsequent /// non-user, non-system groups until the next user group or end of conversation. Each group is assigned /// a indicating which user turn it belongs to. /// System messages () are always assigned a /// since they never belong to a user turn. /// /// /// The turn count is the number of distinct values defined by . /// /// public static CompactionTrigger TurnsExceed(int maxTurns) => index => index.IncludedTurnCount > maxTurns; /// /// Creates a trigger that fires when the included group count exceeds the specified maximum. /// /// The group threshold. /// A that evaluates included group count. public static CompactionTrigger GroupsExceed(int maxGroups) => index => index.IncludedGroupCount > maxGroups; /// /// Creates a trigger that fires when the included message index contains at least one /// non-excluded group. /// /// A that evaluates included tool call presence. public static CompactionTrigger HasToolCalls() => index => index.Groups.Any(g => !g.IsExcluded && g.Kind == CompactionGroupKind.ToolCall); /// /// Creates a compound trigger that fires only when all of the specified triggers fire. /// /// The triggers to combine with logical AND. /// A that requires all conditions to be met. public static CompactionTrigger All(params CompactionTrigger[] triggers) => index => { for (int i = 0; i < triggers.Length; i++) { if (!triggers[i](index)) { return false; } } return true; }; /// /// Creates a compound trigger that fires when any of the specified triggers fire. /// /// The triggers to combine with logical OR. /// A that requires at least one condition to be met. public static CompactionTrigger Any(params CompactionTrigger[] triggers) => index => { for (int i = 0; i < triggers.Length; i++) { if (triggers[i](index)) { return true; } } return false; }; }