Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,16 @@ public interface IRuleCriteriaEvaluator
/// Evaluate the criteria for a single agent's rule.
/// </summary>
/// <param name="agent">The agent whose rule is being considered</param>
/// <param name="agentRule">
/// The rule being considered. An agent can carry more than one rule on the same trigger, so the
/// evaluator is handed the one under evaluation rather than resolving it from the agent itself.
/// </param>
/// <param name="trigger">The rule trigger</param>
/// <param name="context">The per-request criteria context</param>
/// <returns>
/// True if the rule should be executed for this request, false if it should be skipped,
/// or null when the evaluator could not produce an answer (missing script/template,
/// failed execution, error).
/// </returns>
Task<bool?> EvaluateAsync(Agent agent, IRuleTrigger trigger, RuleCriteriaContext context);
Task<bool?> EvaluateAsync(Agent agent, AgentRule agentRule, IRuleTrigger trigger, RuleCriteriaContext context);
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public CodeCriteriaEvaluator(

public string Type => BuiltInRuleCriteria.PythonScript;

public async Task<bool?> EvaluateAsync(Agent agent, IRuleTrigger trigger, RuleCriteriaContext context)
public async Task<bool?> EvaluateAsync(Agent agent, AgentRule agentRule, IRuleTrigger trigger, RuleCriteriaContext context)
{
var settings = context.Options.GetData<CodeCriteriaSettings>() ?? new();
var provider = settings.CodeProcessor ?? BuiltInCodeProcessor.PyInterpreter;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,16 @@ public LlmCriteriaEvaluator(

public string Type => BuiltInRuleCriteria.Llm;

public async Task<bool?> EvaluateAsync(Agent agent, IRuleTrigger trigger, RuleCriteriaContext context)
public async Task<bool?> EvaluateAsync(Agent agent, AgentRule agentRule, IRuleTrigger trigger, RuleCriteriaContext context)
{
var settings = context.Options.GetData<LlmCriteriaSettings>() ?? new();
var rule = agent.Rules.FirstOrDefault(x => x.TriggerName.IsEqualTo(trigger.Name));

// The Rules agent hosts the criteria-check template by default.
var agentId = !string.IsNullOrWhiteSpace(settings.AgentId) ? settings.AgentId! : BuiltInAgentId.RulesInterpreter;
var templateName = !string.IsNullOrWhiteSpace(settings.TemplateName)
? settings.TemplateName! : (agentId == BuiltInAgentId.RulesInterpreter ? DefaultTemplateName : $"{trigger.Name}_criteria");

var input = BuildInput(rule?.CriteriaConfig, settings);
var input = BuildInput(agentRule.CriteriaConfig, settings);
var msg = $"rule trigger ({trigger.Name}) llm criteria (agent {agentId}, template {templateName}).";

try
Expand Down
47 changes: 28 additions & 19 deletions src/Infrastructure/BotSharp.Core.Rules/Engines/RuleEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,33 +44,41 @@ public async Task<IEnumerable<string>> Triggered(IRuleTrigger trigger, string te
var filteredAgents = agents.Items.Where(x => x.Rules.Exists(r => r.TriggerName.IsEqualTo(trigger.Name) && !x.Disabled)).ToList();
foreach (var agent in filteredAgents)
{
var rule = agent.Rules.FirstOrDefault(x => x.TriggerName.IsEqualTo(trigger.Name) && !x.Disabled);
if (rule == null)
var rules = agent.Rules.Where(x => x.TriggerName.IsEqualTo(trigger.Name) && !x.Disabled).ToList();
if (rules.IsNullOrEmpty())
{
continue;
}

// The rule's own mode wins over the mode carried on the trigger options, so an agent can
// pick how its criteria is judged without the caller knowing.
var evaluator = ResolveCriteriaEvaluator(rule.CriteriaConfig?.Mode) ?? criteriaEvaluator;
if (evaluator != null && options?.Criteria != null)
foreach (var rule in rules)
{
var criteriaContext = new RuleCriteriaContext
if (rule == null)
{
Options = options.Criteria,
States = states
};
continue;
}

var isTriggered = await EvaluateCriteria(evaluator, agent, trigger, criteriaContext);
if (!isTriggered)
// The rule's own mode wins over the mode carried on the trigger options, so an agent can
// pick how its criteria is judged without the caller knowing.
var evaluator = ResolveCriteriaEvaluator(rule.CriteriaConfig?.Mode) ?? criteriaEvaluator;
if (evaluator != null && options?.Criteria != null)
{
continue;
var criteriaContext = new RuleCriteriaContext
{
Options = options.Criteria,
States = states
};

var isTriggered = await EvaluateCriteria(evaluator, agent, rule, trigger, criteriaContext);
if (!isTriggered)
{
continue;
}
}
}

var msg = !string.IsNullOrWhiteSpace(rule.Message) ? rule.Message : text;
var convId = await SendMessageToAgent(agent, trigger, text, msg, states);
newConversationIds.Add(convId);
var msg = !string.IsNullOrWhiteSpace(rule.Message) ? rule.Message : text;
var convId = await SendMessageToAgent(agent, trigger, text, msg, states);
newConversationIds.Add(convId);
}
}

return newConversationIds;
Expand All @@ -96,10 +104,11 @@ public async Task<IEnumerable<string>> Triggered(IRuleTrigger trigger, string te
private async Task<bool> EvaluateCriteria(
IRuleCriteriaEvaluator evaluator,
Agent agent,
AgentRule agentRule,
IRuleTrigger trigger,
RuleCriteriaContext context)
{
var isTriggered = await evaluator.EvaluateAsync(agent, trigger, context);
var isTriggered = await evaluator.EvaluateAsync(agent, agentRule, trigger, context);
if (isTriggered != null)
{
return isTriggered.Value;
Expand All @@ -118,7 +127,7 @@ private async Task<bool> EvaluateCriteria(
}

_logger.LogInformation($"Rule criteria evaluator ({evaluator.Type}) returned no result, falling back to llm for agent ({agent.Name}) and trigger ({trigger.Name}).");
return await llmEvaluator.EvaluateAsync(agent, trigger, context) ?? false;
return await llmEvaluator.EvaluateAsync(agent, agentRule, trigger, context) ?? false;
}
#endregion

Expand Down
Loading