From 28d4f4e9baccb976134a731e6ba30d4232a4a130 Mon Sep 17 00:00:00 2001
From: Jicheng Lu <103353@smsassist.com>
Date: Tue, 27 May 2025 15:23:37 -0500
Subject: [PATCH] add utility visibility expression
---
.../Agents/IAgentService.cs | 2 +
.../Agents/Models/AgentUtility.cs | 4 ++
.../Agents/Hooks/BasicAgentHook.cs | 38 ++++++++++++-------
.../Agents/Services/AgentService.LoadAgent.cs | 6 ++-
.../Agents/Services/AgentService.Rendering.cs | 17 +++++++++
.../Models/AgentUtilityMongoElement.cs | 3 ++
.../Core/TestAgentService.cs | 6 +++
7 files changed, 61 insertions(+), 15 deletions(-)
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs
index 45fd3251..b50be071 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs
@@ -36,6 +36,8 @@ public interface IAgentService
FunctionParametersDef? RenderFunctionProperty(Agent agent, FunctionDef def);
+ bool RenderUtility(Agent agent, AgentUtility utility);
+
///
/// Get agent detail without trigger any hook.
///
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentUtility.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentUtility.cs
index ce39c568..1d426600 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentUtility.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentUtility.cs
@@ -4,6 +4,10 @@ public class AgentUtility
{
public string Name { get; set; }
public bool Disabled { get; set; }
+
+ [JsonPropertyName("visibility_expression")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? VisibilityExpression { get; set; }
public IEnumerable Functions { get; set; } = [];
public IEnumerable Templates { get; set; } = [];
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Hooks/BasicAgentHook.cs b/src/Infrastructure/BotSharp.Core/Agents/Hooks/BasicAgentHook.cs
index 10fa376c..03e7bb68 100644
--- a/src/Infrastructure/BotSharp.Core/Agents/Hooks/BasicAgentHook.cs
+++ b/src/Infrastructure/BotSharp.Core/Agents/Hooks/BasicAgentHook.cs
@@ -19,9 +19,9 @@ public class BasicAgentHook : AgentHookBase
var isConvMode = conv.IsConversationMode();
if (!isConvMode) return;
+ agent.Utilities ??= [];
agent.SecondaryFunctions ??= [];
agent.SecondaryInstructions ??= [];
- agent.Utilities ??= [];
var (functions, templates) = GetUtilityContent(agent);
@@ -34,7 +34,7 @@ public class BasicAgentHook : AgentHookBase
private (IEnumerable, IEnumerable) GetUtilityContent(Agent agent)
{
var db = _services.GetRequiredService();
- var (functionNames, templateNames) = GetUniqueContent(agent.Utilities);
+ var (functionNames, templateNames) = FilterUtilityContent(agent.Utilities, agent);
if (agent.MergeUtility)
{
@@ -43,7 +43,7 @@ public class BasicAgentHook : AgentHookBase
if (!string.IsNullOrEmpty(entryAgentId))
{
var entryAgent = db.GetAgent(entryAgentId, basicsOnly: true);
- var (fns, tps) = GetUniqueContent(entryAgent?.Utilities);
+ var (fns, tps) = FilterUtilityContent(entryAgent?.Utilities, agent);
functionNames = functionNames.Concat(fns).Distinct().ToList();
templateNames = templateNames.Concat(tps).Distinct().ToList();
}
@@ -55,22 +55,34 @@ public class BasicAgentHook : AgentHookBase
return (functions, templates);
}
- private (IEnumerable, IEnumerable) GetUniqueContent(IEnumerable? utilities)
+ private (IEnumerable, IEnumerable) FilterUtilityContent(IEnumerable? utilities, Agent agent)
{
if (utilities.IsNullOrEmpty())
{
return ([], []);
}
- utilities = utilities?.Where(x => !string.IsNullOrEmpty(x.Name) && !x.Disabled)?.ToList() ?? [];
- var functionNames = utilities.SelectMany(x => x.Functions)
- .Where(x => !string.IsNullOrEmpty(x.Name) && x.Name.StartsWith(UTIL_PREFIX))
- .Select(x => x.Name)
- .Distinct().ToList();
- var templateNames = utilities.SelectMany(x => x.Templates)
- .Where(x => !string.IsNullOrEmpty(x.Name) && x.Name.StartsWith(UTIL_PREFIX))
- .Select(x => x.Name)
- .Distinct().ToList();
+ var agentService = _services.GetRequiredService();
+ var innerUtilities = utilities!.Where(x =>
+ {
+ var isVisible = !string.IsNullOrEmpty(x.Name) && !x.Disabled;
+ if (!isVisible)
+ {
+ return isVisible;
+ }
+
+ isVisible = agentService.RenderUtility(agent, x);
+ return isVisible;
+ }).ToList();
+
+ var functionNames = innerUtilities.SelectMany(x => x.Functions)
+ .Where(x => !string.IsNullOrEmpty(x.Name) && x.Name.StartsWith(UTIL_PREFIX))
+ .Select(x => x.Name)
+ .Distinct().ToList();
+ var templateNames = innerUtilities.SelectMany(x => x.Templates)
+ .Where(x => !string.IsNullOrEmpty(x.Name) && x.Name.StartsWith(UTIL_PREFIX))
+ .Select(x => x.Name)
+ .Distinct().ToList();
return (functionNames, templateNames);
}
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs
index 7fbfffdc..a15b2907 100644
--- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs
+++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs
@@ -1,4 +1,3 @@
-using BotSharp.Abstraction.Infrastructures;
using BotSharp.Abstraction.Routing.Models;
using System.Collections.Concurrent;
@@ -18,12 +17,15 @@ public partial class AgentService
var agent = await GetAgent(id);
if (agent == null) return null;
+ agent.TemplateDict = [];
+ agent.SecondaryInstructions = [];
+ agent.SecondaryFunctions = [];
+
await InheritAgent(agent);
OverrideInstructionByChannel(agent);
AddOrUpdateParameters(agent);
// Populate state into dictionary
- agent.TemplateDict = new Dictionary();
PopulateState(agent.TemplateDict);
// After agent is loaded
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.Rendering.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.Rendering.cs
index f862482c..89979663 100644
--- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.Rendering.cs
+++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.Rendering.cs
@@ -1,5 +1,6 @@
using BotSharp.Abstraction.Loggers;
using BotSharp.Abstraction.Templating;
+using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json.Linq;
namespace BotSharp.Core.Agents.Services;
@@ -137,4 +138,20 @@ public partial class AgentService
return content;
}
+
+ public bool RenderUtility(Agent agent, AgentUtility utility)
+ {
+ if (string.IsNullOrWhiteSpace(utility?.VisibilityExpression))
+ {
+ return true;
+ }
+
+ var render = _services.GetRequiredService();
+ var result = render.Render(utility.VisibilityExpression, new Dictionary
+ {
+ { "states", agent.TemplateDict }
+ });
+
+ return result == "visible";
+ }
}
\ No newline at end of file
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Models/AgentUtilityMongoElement.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/AgentUtilityMongoElement.cs
index 131226b3..518939cc 100644
--- a/src/Plugins/BotSharp.Plugin.MongoStorage/Models/AgentUtilityMongoElement.cs
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/AgentUtilityMongoElement.cs
@@ -7,6 +7,7 @@ public class AgentUtilityMongoElement
{
public string Name { get; set; } = default!;
public bool Disabled { get; set; }
+ public string? VisibilityExpression { get; set; }
public List Functions { get; set; } = [];
public List Templates { get; set; } = [];
@@ -16,6 +17,7 @@ public class AgentUtilityMongoElement
{
Name = utility.Name,
Disabled = utility.Disabled,
+ VisibilityExpression = utility.VisibilityExpression,
Functions = utility.Functions?.Select(x => new UtilityFunctionMongoElement(x.Name))?.ToList() ?? [],
Templates = utility.Templates?.Select(x => new UtilityTemplateMongoElement(x.Name))?.ToList() ?? []
};
@@ -27,6 +29,7 @@ public class AgentUtilityMongoElement
{
Name = utility.Name,
Disabled = utility.Disabled,
+ VisibilityExpression = utility.VisibilityExpression,
Functions = utility.Functions?.Select(x => new UtilityFunction(x.Name))?.ToList() ?? [],
Templates = utility.Templates?.Select(x => new UtilityTemplate(x.Name))?.ToList() ?? []
};
diff --git a/tests/BotSharp.LLM.Tests/Core/TestAgentService.cs b/tests/BotSharp.LLM.Tests/Core/TestAgentService.cs
index 6716519a..7d58637d 100644
--- a/tests/BotSharp.LLM.Tests/Core/TestAgentService.cs
+++ b/tests/BotSharp.LLM.Tests/Core/TestAgentService.cs
@@ -6,6 +6,7 @@ using BotSharp.Abstraction.Models;
using BotSharp.Abstraction.Plugins.Models;
using BotSharp.Abstraction.Repositories.Filters;
using BotSharp.Abstraction.Utilities;
+using NetTopologySuite.Algorithm;
namespace BotSharp.Plugin.Google.Core
{
@@ -61,6 +62,11 @@ namespace BotSharp.Plugin.Google.Core
return def.Parameters;
}
+ public bool RenderUtility(Agent agent, AgentUtility utility)
+ {
+ return true;
+ }
+
public Task GetAgent(string id)
{
return Task.FromResult(new Agent());