// 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;
};
}