Merge pull request #761 from iceljc/features/merge-origin-agent

Features/merge origin agent
This commit is contained in:
iceljc 2024-11-27 11:33:55 -06:00 committed by GitHub
commit ad27596959
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
75 changed files with 625 additions and 1060 deletions

View file

@ -1,5 +1,10 @@
using BotSharp.Abstraction.Agents.Settings;
using BotSharp.Abstraction.Conversations;
using BotSharp.Abstraction.Functions.Models;
using BotSharp.Abstraction.Repositories;
using BotSharp.Abstraction.Routing;
using Microsoft.Extensions.DependencyInjection;
using System.Data;
namespace BotSharp.Abstraction.Agents;
@ -49,7 +54,71 @@ public abstract class AgentHookBase : IAgentHook
return true;
}
public virtual void OnAgentLoaded(Agent agent)
public virtual void OnAgentLoaded(Agent agent)
{
}
public virtual void OnAgentUtilityLoaded(Agent agent)
{
if (agent.Type == AgentType.Routing) return;
var conv = _services.GetRequiredService<IConversationService>();
var isConvMode = conv.IsConversationMode();
if (!isConvMode) return;
agent.Functions ??= [];
agent.Utilities ??= [];
var (functions, templates) = GetUtilityContent(agent);
agent.Functions.AddRange(functions);
foreach (var prompt in templates)
{
agent.Instruction += $"\r\n\r\n{prompt}\r\n\r\n";
}
}
private (IEnumerable<FunctionDef>, IEnumerable<string>) GetUtilityContent(Agent agent)
{
var db = _services.GetRequiredService<IBotSharpRepository>();
var (functionNames, templateNames) = GetUniqueContent(agent.Utilities);
if (agent.MergeUtility)
{
var routing = _services.GetRequiredService<IRoutingContext>();
var entryAgentId = routing.EntryAgentId;
if (!string.IsNullOrEmpty(entryAgentId))
{
var entryAgent = db.GetAgent(entryAgentId);
var (fns, tps) = GetUniqueContent(entryAgent?.Utilities);
functionNames = functionNames.Concat(fns).Distinct().ToList();
templateNames = templateNames.Concat(tps).Distinct().ToList();
}
}
var ua = db.GetAgent(BuiltInAgentId.UtilityAssistant);
var functions = ua?.Functions?.Where(x => functionNames.Contains(x.Name, StringComparer.OrdinalIgnoreCase))?.ToList() ?? [];
var templates = ua?.Templates?.Where(x => templateNames.Contains(x.Name, StringComparer.OrdinalIgnoreCase))?.Select(x => x.Content)?.ToList() ?? [];
return (functions, templates);
}
private (IEnumerable<string>, IEnumerable<string>) GetUniqueContent(IEnumerable<AgentUtility>? utilities)
{
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))
.Select(x => x.Name)
.Distinct().ToList();
var templateNames = utilities.SelectMany(x => x.Templates)
.Where(x => !string.IsNullOrEmpty(x.Name))
.Select(x => x.Name)
.Distinct().ToList();
return (functionNames, templateNames);
}
}

View file

@ -25,6 +25,8 @@ public interface IAgentHook
bool OnSamplesLoaded(List<string> samples);
void OnAgentUtilityLoaded(Agent agent);
/// <summary>
/// Triggered when agent is loaded completely.
/// </summary>

View file

@ -59,5 +59,5 @@ public interface IAgentService
PluginDef GetPlugin(string agentId);
IEnumerable<string> GetAgentUtilities();
IEnumerable<AgentUtility> GetAgentUtilityOptions();
}

View file

@ -2,5 +2,5 @@ namespace BotSharp.Abstraction.Agents;
public interface IAgentUtilityHook
{
void AddUtilities(List<string> utilities);
void AddUtilities(List<AgentUtility> utilities);
}

View file

@ -87,13 +87,17 @@ public class Agent
/// <summary>
/// Profile by channel
/// </summary>
public List<string> Profiles { get; set; }
= new List<string>();
public List<string> Profiles { get; set; } = new();
/// <summary>
/// Merge utilities from entry agent
/// </summary>
public bool MergeUtility { get; set; }
/// <summary>
/// Agent utilities
/// </summary>
public List<string> Utilities { get; set; } = new();
public List<AgentUtility> Utilities { get; set; } = new();
/// <summary>
/// Inherit from agent
@ -173,9 +177,9 @@ public class Agent
return this;
}
public Agent SetUtilities(List<string> utilities)
public Agent SetUtilities(List<AgentUtility> utilities)
{
Utilities = utilities ?? new List<string>();
Utilities = utilities ?? new List<AgentUtility>();
return this;
}
@ -215,6 +219,12 @@ public class Agent
return this;
}
public Agent SetMergeUtility(bool merge)
{
MergeUtility = merge;
return this;
}
public Agent SetAgentType(string type)
{
Type = type;

View file

@ -0,0 +1,56 @@
namespace BotSharp.Abstraction.Agents.Models;
public class AgentUtility
{
public string Name { get; set; }
public bool Disabled { get; set; }
public IEnumerable<UtilityFunction> Functions { get; set; } = [];
public IEnumerable<UtilityTemplate> Templates { get; set; } = [];
public AgentUtility()
{
}
public AgentUtility(
string name,
IEnumerable<UtilityFunction>? functions = null,
IEnumerable<UtilityTemplate>? templates = null)
{
Name = name;
Functions = functions ?? [];
Templates = templates ?? [];
}
}
public class UtilityFunction : UtilityBase
{
public UtilityFunction()
{
}
public UtilityFunction(string name)
{
Name = name;
}
}
public class UtilityTemplate : UtilityBase
{
public UtilityTemplate()
{
}
public UtilityTemplate(string name)
{
Name = name;
}
}
public class UtilityBase
{
public string Name { get; set; }
}

View file

@ -6,6 +6,7 @@ public interface IRoutingContext
string FirstGoalAgentId();
bool ContainsAgentId(string agentId);
string OriginAgentId { get; }
string EntryAgentId { get; }
string ConversationId { get; }
string MessageId { get; }
void SetMessageId(string conversationId, string messageId);

View file

@ -3,4 +3,5 @@ namespace BotSharp.Abstraction.Templating;
public interface ITemplateRender
{
string Render(string template, Dictionary<string, object> dict);
void Register(Type type);
}

View file

@ -1,5 +1,8 @@
namespace BotSharp.Abstraction.Users.Enums;
/// <summary>
/// User actions on agent level
/// </summary>
public static class UserAction
{
public const string Edit = "edit";

View file

@ -1,5 +1,8 @@
namespace BotSharp.Abstraction.Users.Enums;
/// <summary>
/// User permission
/// </summary>
public static class UserPermission
{
public const string CreateAgent = "create-agent";

View file

@ -22,4 +22,26 @@ public static class UserAuthorizationExtension
var actions = found.Actions ?? [];
return actions.Any(x => x == targetAction);
}
/// <summary>
/// Get allowed user actions on the agent. If user is admin, returns null;
/// </summary>
/// <param name="auth"></param>
/// <param name="agentId"></param>
/// <returns></returns>
public static IEnumerable<string>? GetAllowedAgentActions(this UserAuthorization auth, string agentId)
{
if (auth == null || string.IsNullOrEmpty(agentId))
{
return [];
}
if (auth.IsAdmin)
{
return null;
}
var found = auth.AgentActions.FirstOrDefault(x => x.AgentId == agentId);
return found?.Actions ?? [];
}
}

View file

@ -10,7 +10,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\BotSharp.Abstraction\BotSharp.Abstraction.csproj" />
<ProjectReference Include="..\BotSharp.Core\BotSharp.Core.csproj" />
</ItemGroup>
</Project>

View file

@ -1,3 +1,5 @@
using BotSharp.Core.Infrastructures;
namespace BotSharp.Core.SideCar.Services;
public class BotSharpConversationSideCar : IConversationSideCar
@ -116,7 +118,7 @@ public class BotSharpConversationSideCar : IConversationSideCar
state.ResetCurrentState();
routing.Context.ResetRecursiveCounter();
routing.Context.ResetAgentStack();
Utilities.ClearCache();
}
private void AfterExecute()
@ -130,6 +132,7 @@ public class BotSharpConversationSideCar : IConversationSideCar
state.SetCurrentState(node.State);
routing.Context.SetRecursiveCounter(node.RecursiveCounter);
routing.Context.SetAgentStack(node.RoutingStack);
Utilities.ClearCache();
enabled = false;
}
}

View file

@ -1,6 +1,7 @@
using BotSharp.Abstraction.MLTasks;
using BotSharp.Abstraction.Plugins.Models;
using BotSharp.Abstraction.Settings;
using BotSharp.Abstraction.Templating;
using BotSharp.Abstraction.Users.Enums;
using Microsoft.Extensions.Configuration;
@ -33,6 +34,8 @@ public class AgentPlugin : IBotSharpPlugin
services.AddScoped(provider =>
{
var settingService = provider.GetRequiredService<ISettingService>();
var render = provider.GetRequiredService<ITemplateRender>();
render.Register(typeof(AgentSettings));
return settingService.Bind<AgentSettings>("Agent");
});
}

View file

@ -67,6 +67,7 @@ public partial class AgentService
hook.OnSamplesLoaded(agent.Samples);
}
hook.OnAgentUtilityLoaded(agent);
hook.OnAgentLoaded(agent);
}

View file

@ -9,13 +9,16 @@ public partial class AgentService
public string RenderedInstruction(Agent agent)
{
var render = _services.GetRequiredService<ITemplateRender>();
// update states
var conv = _services.GetRequiredService<IConversationService>();
// update states
foreach (var t in conv.States.GetStates())
{
agent.TemplateDict[t.Key] = t.Value;
}
return render.Render(agent.Instruction, agent.TemplateDict);
var res = render.Render(agent.Instruction, agent.TemplateDict);
return res;
}
public bool RenderFunction(Agent agent, FunctionDef def)
@ -108,16 +111,18 @@ public partial class AgentService
public string RenderedTemplate(Agent agent, string templateName)
{
// render liquid template
var render = _services.GetRequiredService<ITemplateRender>();
var template = agent.Templates.First(x => x.Name == templateName).Content;
// update states
var conv = _services.GetRequiredService<IConversationService>();
var render = _services.GetRequiredService<ITemplateRender>();
var template = agent.Templates.First(x => x.Name == templateName).Content;
// update states
foreach (var t in conv.States.GetStates())
{
agent.TemplateDict[t.Key] = t.Value;
}
// render liquid template
var content = render.Render(template, agent.TemplateDict);
HookEmitter.Emit<IContentGeneratingHook>(_services, async hook =>
@ -126,4 +131,4 @@ public partial class AgentService
return content;
}
}
}

View file

@ -1,5 +1,4 @@
using BotSharp.Abstraction.Repositories.Enums;
using BotSharp.Abstraction.Routing.Models;
using BotSharp.Abstraction.Users.Enums;
using BotSharp.Abstraction.Users.Models;
using System.IO;
@ -28,16 +27,17 @@ public partial class AgentService
record.Description = agent.Description ?? string.Empty;
record.IsPublic = agent.IsPublic;
record.Disabled = agent.Disabled;
record.MergeUtility = agent.MergeUtility;
record.Type = agent.Type;
record.Profiles = agent.Profiles ?? new List<string>();
record.RoutingRules = agent.RoutingRules ?? new List<RoutingRule>();
record.Profiles = agent.Profiles ?? [];
record.RoutingRules = agent.RoutingRules ?? [];
record.Instruction = agent.Instruction ?? string.Empty;
record.ChannelInstructions = agent.ChannelInstructions ?? new List<ChannelInstruction>();
record.Functions = agent.Functions ?? new List<FunctionDef>();
record.Templates = agent.Templates ?? new List<AgentTemplate>();
record.Responses = agent.Responses ?? new List<AgentResponse>();
record.Samples = agent.Samples ?? new List<string>();
record.Utilities = agent.Utilities ?? new List<string>();
record.ChannelInstructions = agent.ChannelInstructions ?? [];
record.Functions = agent.Functions ?? [];
record.Templates = agent.Templates ?? [];
record.Responses = agent.Responses ?? [];
record.Samples = agent.Samples ?? [];
record.Utilities = agent.Utilities ?? [];
if (agent.LlmConfig != null && !agent.LlmConfig.IsInherit)
{
record.LlmConfig = agent.LlmConfig;
@ -90,6 +90,7 @@ public partial class AgentService
.SetDescription(foundAgent.Description)
.SetIsPublic(foundAgent.IsPublic)
.SetDisabled(foundAgent.Disabled)
.SetMergeUtility(foundAgent.MergeUtility)
.SetAgentType(foundAgent.Type)
.SetProfiles(foundAgent.Profiles)
.SetRoutingRules(foundAgent.RoutingRules)

View file

@ -57,14 +57,14 @@ public partial class AgentService : IAgentService
return userAgents;
}
public IEnumerable<string> GetAgentUtilities()
public IEnumerable<AgentUtility> GetAgentUtilityOptions()
{
var utilities = new List<string>();
var utilities = new List<AgentUtility>();
var hooks = _services.GetServices<IAgentUtilityHook>();
foreach (var hook in hooks)
{
hook.AddUtilities(utilities);
}
return utilities.Where(x => !string.IsNullOrWhiteSpace(x)).Distinct().OrderBy(x => x).ToList();
return utilities.Where(x => !string.IsNullOrWhiteSpace(x.Name)).OrderBy(x => x.Name).ToList();
}
}

View file

@ -12,6 +12,8 @@ using BotSharp.Core.Processors;
using StackExchange.Redis;
using BotSharp.Core.Infrastructures.Events;
using BotSharp.Core.Roles.Services;
using BotSharp.Abstraction.Templating;
using BotSharp.Core.Templating;
namespace BotSharp.Core;
@ -24,6 +26,8 @@ public static class BotSharpCoreExtensions
services.AddSingleton(x => interpreterSettings);
services.AddSingleton<DistributedLocker>();
// Register template render
services.AddSingleton<ITemplateRender, TemplateRender>();
services.AddScoped<ISettingService, SettingService>();
services.AddScoped<IRoleService, RoleService>();

View file

@ -30,6 +30,8 @@ public class ConversationPlugin : IBotSharpPlugin
services.AddScoped(provider =>
{
var settingService = provider.GetRequiredService<ISettingService>();
var render = provider.GetRequiredService<ITemplateRender>();
render.Register(typeof(ConversationSetting));
return settingService.Bind<ConversationSetting>("Conversation");
});
@ -48,8 +50,6 @@ public class ConversationPlugin : IBotSharpPlugin
// Rich content messaging
services.AddScoped<IRichContentService, RichContentService>();
// Register template render
services.AddSingleton<ITemplateRender, TemplateRender>();
services.AddScoped<IResponseTemplateService, ResponseTemplateService>();
services.AddScoped<IExecutor, InstructExecutor>();

View file

@ -1,5 +1,4 @@
using BotSharp.Abstraction.Conversations.Enums;
using BotSharp.Abstraction.Users.Enums;
namespace BotSharp.Core.Conversations.Services;
@ -21,13 +20,14 @@ public class ConversationStateService : IConversationStateService, IDisposable
/// </summary>
private ConversationState _historyStates;
public ConversationStateService(ILogger<ConversationStateService> logger,
public ConversationStateService(
IServiceProvider services,
IBotSharpRepository db)
IBotSharpRepository db,
ILogger<ConversationStateService> logger)
{
_logger = logger;
_services = services;
_db = db;
_logger = logger;
_curStates = new ConversationState();
_historyStates = new ConversationState();
}
@ -125,8 +125,13 @@ public class ConversationStateService : IConversationStateService, IDisposable
var curMsgId = routingCtx.MessageId;
_historyStates = _db.GetConversationStates(conversationId);
var endNodes = new Dictionary<string, string>();
if (_historyStates.IsNullOrEmpty()) return endNodes;
var dialogs = _db.GetConversationDialogs(conversationId);
var userDialogs = dialogs.Where(x => x.MetaData?.Role == AgentRole.User || x.MetaData?.Role == UserRole.User)
var userDialogs = dialogs.Where(x => x.MetaData?.Role == AgentRole.User)
.GroupBy(x => x.MetaData?.MessageId)
.Select(g => g.First())
.OrderBy(x => x.MetaData?.CreateTime)
@ -134,9 +139,6 @@ public class ConversationStateService : IConversationStateService, IDisposable
var curMsgIndex = userDialogs.FindIndex(x => !string.IsNullOrEmpty(curMsgId) && x.MetaData?.MessageId == curMsgId);
curMsgIndex = curMsgIndex < 0 ? userDialogs.Count() : curMsgIndex;
var endNodes = new Dictionary<string, string>();
if (_historyStates.IsNullOrEmpty()) return endNodes;
foreach (var state in _historyStates)
{
var key = state.Key;

View file

@ -55,7 +55,7 @@ namespace BotSharp.Core.Repository
UpdateAgentLlmConfig(agent.Id, agent.LlmConfig);
break;
case AgentField.Utility:
UpdateAgentUtilities(agent.Id, agent.Utilities);
UpdateAgentUtilities(agent.Id, agent.MergeUtility, agent.Utilities);
break;
case AgentField.All:
UpdateAgentAllFields(agent);
@ -151,13 +151,14 @@ namespace BotSharp.Core.Repository
File.WriteAllText(agentFile, json);
}
private void UpdateAgentUtilities(string agentId, List<string> utilities)
private void UpdateAgentUtilities(string agentId, bool mergeUtility, List<AgentUtility> utilities)
{
if (utilities == null) return;
var (agent, agentFile) = GetAgentFromFile(agentId);
if (agent == null) return;
agent.MergeUtility = mergeUtility;
agent.Utilities = utilities;
agent.UpdatedDateTime = DateTime.UtcNow;
var json = JsonSerializer.Serialize(agent, _options);
@ -291,6 +292,7 @@ namespace BotSharp.Core.Repository
agent.Description = inputAgent.Description;
agent.IsPublic = inputAgent.IsPublic;
agent.Disabled = inputAgent.Disabled;
agent.MergeUtility = inputAgent.MergeUtility;
agent.Type = inputAgent.Type;
agent.Profiles = inputAgent.Profiles;
agent.Utilities = inputAgent.Utilities;

View file

@ -41,7 +41,8 @@ public class RoutingContext : IRoutingContext
var agentService = _services.GetRequiredService<IAgentService>();
_routerAgentIds = agentService.GetAgents(new AgentFilter
{
Type = AgentType.Routing
Type = AgentType.Routing,
Pager = new Pagination { Size = 100 }
}).Result.Items.Select(x => x.Id).ToArray();
}
@ -49,6 +50,17 @@ public class RoutingContext : IRoutingContext
}
}
/// <summary>
/// Entry agent
/// </summary>
public string EntryAgentId
{
get
{
return _stack.LastOrDefault() ?? string.Empty;
}
}
public bool IsEmpty => !_stack.Any();
public string GetCurrentAgentId()
@ -231,12 +243,16 @@ public class RoutingContext : IRoutingContext
public Stack<string> GetAgentStack()
{
return new Stack<string>(_stack);
var copy = _stack.ToList();
copy.Reverse();
return new Stack<string>(copy);
}
public void SetAgentStack(Stack<string> stack)
{
_stack = new Stack<string>(stack);
var copy = stack.ToList();
copy.Reverse();
_stack = new Stack<string>(copy);
}
public void ResetAgentStack()

View file

@ -1,6 +1,5 @@
using BotSharp.Abstraction.Conversations.Enums;
using BotSharp.Abstraction.Routing.Models;
using System.Drawing;
namespace BotSharp.Core.Routing;

View file

@ -4,13 +4,11 @@ namespace BotSharp.Core.Routing;
public partial class RoutingService
{
//private int _currentRecursionDepth = 0;
public async Task<bool> InvokeAgent(string agentId, List<RoleDialogModel> dialogs)
{
var agentService = _services.GetRequiredService<IAgentService>();
var agent = await agentService.LoadAgent(agentId);
//_currentRecursionDepth++;
Context.IncreaseRecursiveCounter();
if (Context.CurrentRecursionDepth > agent.LlmConfig.MaxRecursionDepth)
{

View file

@ -14,21 +14,6 @@ public partial class RoutingService : IRoutingService
public IRoutingContext Context => _context;
public Agent Router => _router;
//public int GetRecursiveCounter()
//{
// return _currentRecursionDepth;
//}
//public void SetRecursiveCounter(int counter)
//{
// _currentRecursionDepth = counter;
//}
//public void ResetRecursiveCounter()
//{
// _currentRecursionDepth = 0;
//}
public RoutingService(
IServiceProvider services,
RoutingSettings settings,

View file

@ -1,10 +1,10 @@
using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Functions.Models;
using BotSharp.Abstraction.Models;
using BotSharp.Abstraction.Routing.Models;
using BotSharp.Abstraction.Templating;
using BotSharp.Abstraction.Translation.Models;
using Fluid;
using System.Collections;
using System.Reflection;
namespace BotSharp.Core.Templating;
@ -48,4 +48,47 @@ public class TemplateRender : ITemplateRender
return template;
}
}
public void Register(Type type)
{
if (type == null || IsStringType(type)) return;
if (IsListType(type))
{
if (type.IsGenericType)
{
var genericType = type.GetGenericArguments()[0];
Register(genericType);
}
}
else if (IsTrackToNextLevel(type))
{
_options.MemberAccessStrategy.Register(type);
var props = type.GetProperties();
foreach (var prop in props)
{
Register(prop.PropertyType);
}
}
}
#region Private methods
private static bool IsStringType(Type type)
{
return type == typeof(string);
}
private static bool IsListType(Type type)
{
var interfaces = type.GetTypeInfo().ImplementedInterfaces;
return type.IsArray || interfaces.Any(x => x.Name == typeof(IEnumerable).Name);
}
private static bool IsTrackToNextLevel(Type type)
{
return type.IsClass || type.IsInterface || type.IsAbstract;
}
#endregion
}

View file

@ -1,4 +1,4 @@
using BotSharp.Abstraction.Users.Enums;
using BotSharp.Abstraction.Agents.Models;
namespace BotSharp.OpenAPI.Controllers;
@ -59,11 +59,7 @@ public class AgentController : ControllerBase
var userService = _services.GetRequiredService<IUserService>();
var auth = await userService.GetUserAuthorizations(new List<string> { targetAgent.Id });
targetAgent.Editable = auth.IsAgentActionAllowed(targetAgent.Id, UserAction.Edit);
targetAgent.Chatable = auth.IsAgentActionAllowed(targetAgent.Id, UserAction.Chat);
targetAgent.Trainable = auth.IsAgentActionAllowed(targetAgent.Id, UserAction.Train);
targetAgent.Evaluable = auth.IsAgentActionAllowed(targetAgent.Id, UserAction.Evaluate);
targetAgent.Actions = auth.GetAllowedAgentActions(targetAgent.Id);
return targetAgent;
}
@ -90,10 +86,7 @@ public class AgentController : ControllerBase
agents = pagedAgents?.Items?.Select(x =>
{
var model = AgentViewModel.FromAgent(x);
model.Editable = auth.IsAgentActionAllowed(x.Id, UserAction.Edit);
model.Chatable = auth.IsAgentActionAllowed(x.Id, UserAction.Chat);
model.Trainable = auth.IsAgentActionAllowed(x.Id, UserAction.Train);
model.Evaluable = auth.IsAgentActionAllowed(x.Id, UserAction.Evaluate);
model.Actions = auth.GetAllowedAgentActions(x.Id);
return model;
})?.ToList() ?? [];
@ -153,9 +146,9 @@ public class AgentController : ControllerBase
return await _agentService.DeleteAgent(agentId);
}
[HttpGet("/agent/utilities")]
public IEnumerable<string> GetAgentUtilities()
[HttpGet("/agent/utility/options")]
public IEnumerable<AgentUtility> GetAgentUtilityOptions()
{
return _agentService.GetAgentUtilities();
return _agentService.GetAgentUtilityOptions();
}
}

View file

@ -48,7 +48,10 @@ public class AgentCreationModel
/// Combine different Agents together to form a Profile.
/// </summary>
public List<string> Profiles { get; set; } = new();
public List<string> Utilities { get; set; } = new();
public bool MergeUtility { get; set; }
public List<AgentUtility> Utilities { get; set; } = new();
public List<RoutingRuleUpdateModel> RoutingRules { get; set; } = new();
public AgentLlmConfig? LlmConfig { get; set; }
@ -68,6 +71,7 @@ public class AgentCreationModel
IsPublic = IsPublic,
Type = Type,
Disabled = Disabled,
MergeUtility = MergeUtility,
Profiles = Profiles,
RoutingRules = RoutingRules?.Select(x => RoutingRuleUpdateModel.ToDomainElement(x))?.ToList() ?? new List<RoutingRule>(),
LlmConfig = LlmConfig

View file

@ -31,10 +31,13 @@ public class AgentUpdateModel
/// </summary>
public List<string>? Samples { get; set; }
[JsonPropertyName("merge_utility")]
public bool MergeUtility { get; set; }
/// <summary>
/// Utilities
/// </summary>
public List<string>? Utilities { get; set; }
public List<AgentUtility>? Utilities { get; set; }
/// <summary>
/// Functions
@ -73,6 +76,7 @@ public class AgentUpdateModel
Description = Description ?? string.Empty,
IsPublic = IsPublic,
Disabled = Disabled,
MergeUtility = MergeUtility,
Type = Type,
Profiles = Profiles ?? new List<string>(),
RoutingRules = RoutingRules?.Select(x => RoutingRuleUpdateModel.ToDomainElement(x))?.ToList() ?? new List<RoutingRule>(),
@ -81,7 +85,7 @@ public class AgentUpdateModel
Templates = Templates ?? new List<AgentTemplate>(),
Functions = Functions ?? new List<FunctionDef>(),
Responses = Responses ?? new List<AgentResponse>(),
Utilities = Utilities ?? new List<string>(),
Utilities = Utilities ?? new List<AgentUtility>(),
LlmConfig = LlmConfig
};

View file

@ -20,7 +20,10 @@ public class AgentViewModel
public List<FunctionDef> Functions { get; set; }
public List<AgentResponse> Responses { get; set; }
public List<string> Samples { get; set; }
public List<string> Utilities { get; set; }
[JsonPropertyName("merge_utility")]
public bool MergeUtility { get; set; }
public List<AgentUtility> Utilities { get; set; }
[JsonPropertyName("is_public")]
public bool IsPublic { get; set; }
@ -33,8 +36,7 @@ public class AgentViewModel
[JsonPropertyName("icon_url")]
public string IconUrl { get; set; }
public List<string> Profiles { get; set; }
= new List<string>();
public List<string> Profiles { get; set; } = new();
[JsonPropertyName("routing_rules")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
@ -46,10 +48,7 @@ public class AgentViewModel
public PluginDef Plugin { get; set; }
public bool Editable { get; set; }
public bool Chatable { get; set; }
public bool Trainable { get; set; }
public bool Evaluable { get; set; }
public IEnumerable<string>? Actions { get; set; }
[JsonPropertyName("created_datetime")]
public DateTime CreatedDateTime { get; set; }
@ -74,6 +73,7 @@ public class AgentViewModel
Utilities = agent.Utilities,
IsPublic= agent.IsPublic,
Disabled = agent.Disabled,
MergeUtility = agent.MergeUtility,
IconUrl = agent.IconUrl,
Profiles = agent.Profiles ?? new List<string>(),
RoutingRules = agent.RoutingRules,

View file

@ -17,7 +17,6 @@ public class AudioHandlerPlugin : IBotSharpPlugin
});
services.AddScoped<IAudioCompletion, NativeWhisperProvider>();
services.AddScoped<IAgentHook, AudioHandlerHook>();
services.AddScoped<IAgentUtilityHook, AudioHandlerUtilityHook>();
}
}

View file

@ -1,60 +0,0 @@
using BotSharp.Abstraction.Agents.Settings;
using BotSharp.Abstraction.Functions.Models;
namespace BotSharp.Plugin.AudioHandler.Hooks;
public class AudioHandlerHook : AgentHookBase, IAgentHook
{
private const string HANDLER_AUDIO = "handle_audio_request";
public override string SelfId => string.Empty;
public AudioHandlerHook(IServiceProvider services, AgentSettings settings) : base(services, settings)
{
}
public override void OnAgentLoaded(Agent agent)
{
var conv = _services.GetRequiredService<IConversationService>();
var isConvMode = conv.IsConversationMode();
var isEnabled = !agent.Utilities.IsNullOrEmpty() && agent.Utilities.Contains(UtilityName.AudioHandler);
if (isEnabled && isConvMode)
{
AddUtility(agent, HANDLER_AUDIO);
}
base.OnAgentLoaded(agent);
}
private void AddUtility(Agent agent, string functionName)
{
var (prompt, fn) = GetPromptAndFunction(functionName);
if (fn != null)
{
if (!string.IsNullOrWhiteSpace(prompt))
{
agent.Instruction += $"\r\n\r\n{prompt}\r\n\r\n";
}
if (agent.Functions == null)
{
agent.Functions = new List<FunctionDef> { fn };
}
else
{
agent.Functions.Add(fn);
}
}
}
private (string, FunctionDef?) GetPromptAndFunction(string functionName)
{
var db = _services.GetRequiredService<IBotSharpRepository>();
var agent = db.GetAgent(BuiltInAgentId.UtilityAssistant);
var prompt = agent?.Templates?.FirstOrDefault(x => x.Name.IsEqualTo($"{functionName}.fn"))?.Content ?? string.Empty;
var loadAttachmentFn = agent?.Functions?.FirstOrDefault(x => x.Name.IsEqualTo(functionName));
return (prompt, loadAttachmentFn);
}
}

View file

@ -2,8 +2,17 @@ namespace BotSharp.Plugin.AudioHandler.Hooks;
public class AudioHandlerUtilityHook : IAgentUtilityHook
{
public void AddUtilities(List<string> utilities)
private const string HANDLER_AUDIO = "handle_audio_request";
public void AddUtilities(List<AgentUtility> utilities)
{
utilities.Add(UtilityName.AudioHandler);
var utility = new AgentUtility
{
Name = UtilityName.AudioHandler,
Functions = [new(HANDLER_AUDIO)],
Templates = [new($"{HANDLER_AUDIO}.fn")]
};
utilities.Add(utility);
}
}

View file

@ -20,8 +20,6 @@ namespace BotSharp.Plugin.EmailHandler
return settingService.Bind<EmailSenderSettings>("EmailSender");
});
services.AddScoped<IAgentHook, EmailSenderHook>();
services.AddScoped<IAgentHook, EmailReaderHook>();
services.AddScoped<IAgentUtilityHook, EmailHandlerUtilityHook>();
var emailReaderSettings = new EmailReaderSettings();

View file

@ -1,18 +1,22 @@
using BotSharp.Abstraction.Agents;
using BotSharp.Plugin.EmailHandler.Enums;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BotSharp.Plugin.EmailHandler.Hooks
namespace BotSharp.Plugin.EmailHandler.Hooks;
public class EmailHandlerUtilityHook : IAgentUtilityHook
{
public class EmailHandlerUtilityHook : IAgentUtilityHook
private static string EMAIL_READER_FN = "handle_email_reader";
private static string EMAIL_SENDER_FN = "handle_email_sender";
public void AddUtilities(List<AgentUtility> utilities)
{
public void AddUtilities(List<string> utilities)
var utility = new AgentUtility
{
utilities.Add(UtilityName.EmailHandler);
}
Name = UtilityName.EmailHandler,
Functions = [new(EMAIL_READER_FN), new(EMAIL_SENDER_FN)],
Templates = [new($"{EMAIL_READER_FN}.fn"), new($"{EMAIL_SENDER_FN}.fn")]
};
utilities.Add(utility);
}
}

View file

@ -1,56 +0,0 @@
using BotSharp.Abstraction.Agents;
using BotSharp.Abstraction.Agents.Settings;
using BotSharp.Abstraction.Functions.Models;
using BotSharp.Plugin.EmailHandler.Enums;
namespace BotSharp.Plugin.EmailHandler.Hooks;
public class EmailReaderHook : AgentHookBase
{
private static string FUNCTION_NAME = "handle_email_reader";
public override string SelfId => string.Empty;
public EmailReaderHook(IServiceProvider services, AgentSettings settings)
: base(services, settings)
{
}
public override void OnAgentLoaded(Agent agent)
{
var conv = _services.GetRequiredService<IConversationService>();
var isConvMode = conv.IsConversationMode();
var isEnabled = !agent.Utilities.IsNullOrEmpty() && agent.Utilities.Contains(UtilityName.EmailHandler);
if (isConvMode && isEnabled)
{
var (prompt, fn) = GetPromptAndFunction();
if (fn != null)
{
if (!string.IsNullOrWhiteSpace(prompt))
{
agent.Instruction += $"\r\n\r\n{prompt}\r\n\r\n";
}
if (agent.Functions == null)
{
agent.Functions = new List<FunctionDef> { fn };
}
else
{
agent.Functions.Add(fn);
}
}
}
base.OnAgentLoaded(agent);
}
private (string, FunctionDef?) GetPromptAndFunction()
{
var db = _services.GetRequiredService<IBotSharpRepository>();
var agent = db.GetAgent(BuiltInAgentId.UtilityAssistant);
var prompt = agent?.Templates?.FirstOrDefault(x => x.Name.IsEqualTo($"{FUNCTION_NAME}.fn"))?.Content ?? string.Empty;
var loadAttachmentFn = agent?.Functions?.FirstOrDefault(x => x.Name.IsEqualTo(FUNCTION_NAME));
return (prompt, loadAttachmentFn);
}
}

View file

@ -1,56 +0,0 @@
using BotSharp.Abstraction.Agents;
using BotSharp.Abstraction.Agents.Settings;
using BotSharp.Abstraction.Functions.Models;
using BotSharp.Plugin.EmailHandler.Enums;
namespace BotSharp.Plugin.EmailHandler.Hooks;
public class EmailSenderHook : AgentHookBase
{
private static string FUNCTION_NAME = "handle_email_sender";
public override string SelfId => string.Empty;
public EmailSenderHook(IServiceProvider services, AgentSettings settings)
: base(services, settings)
{
}
public override void OnAgentLoaded(Agent agent)
{
var conv = _services.GetRequiredService<IConversationService>();
var isConvMode = conv.IsConversationMode();
var isEnabled = !agent.Utilities.IsNullOrEmpty() && agent.Utilities.Contains(UtilityName.EmailHandler);
if (isConvMode && isEnabled)
{
var (prompt, fn) = GetPromptAndFunction();
if (fn != null)
{
if (!string.IsNullOrWhiteSpace(prompt))
{
agent.Instruction += $"\r\n\r\n{prompt}\r\n\r\n";
}
if (agent.Functions == null)
{
agent.Functions = new List<FunctionDef> { fn };
}
else
{
agent.Functions.Add(fn);
}
}
}
base.OnAgentLoaded(agent);
}
private (string, FunctionDef?) GetPromptAndFunction()
{
var db = _services.GetRequiredService<IBotSharpRepository>();
var agent = db.GetAgent(BuiltInAgentId.UtilityAssistant);
var prompt = agent?.Templates?.FirstOrDefault(x => x.Name.IsEqualTo($"{FUNCTION_NAME}.fn"))?.Content ?? string.Empty;
var loadAttachmentFn = agent?.Functions?.FirstOrDefault(x => x.Name.IsEqualTo(FUNCTION_NAME));
return (prompt, loadAttachmentFn);
}
}

View file

@ -1,8 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BotSharp.Abstraction.Plugins;
using BotSharp.Abstraction.Settings;
using BotSharp.Plugin.ExcelHandler.Helpers.MySql;
@ -30,7 +25,6 @@ public class ExcelHandlerPlugin : IBotSharpPlugin
});
services.AddScoped<IAgentUtilityHook, ExcelHandlerUtilityHook>();
services.AddScoped<IAgentHook, ExcelHandlerHook>();
services.AddScoped<ISqliteDbHelpers, SqliteDbHelpers>();
services.AddScoped<IMySqlDbHelper, MySqlDbHelpers>();
services.AddScoped<ISqliteService, SqliteService>();

View file

@ -1,12 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using BotSharp.Plugin.SqlHero.Settings;
using Microsoft.Data.Sqlite;
using BotSharp.Plugin.SqlDriver.Settings;
using MySql.Data.MySqlClient;
namespace BotSharp.Plugin.ExcelHandler.Helpers.MySql

View file

@ -1,11 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BotSharp.Plugin.SqlDriver.Settings;
using Microsoft.Data.Sqlite;
using BotSharp.Plugin.SqlDriver.Models;
using BotSharp.Plugin.SqlHero.Settings;
namespace BotSharp.Plugin.ExcelHandler.Helpers.Sqlite;

View file

@ -1,58 +0,0 @@
namespace BotSharp.Plugin.ExcelHandler.Hooks;
public class ExcelHandlerHook : AgentHookBase, IAgentHook
{
private const string HANDLER_EXCEL = "handle_excel_request";
public override string SelfId => string.Empty;
public ExcelHandlerHook(IServiceProvider services, AgentSettings settings) : base(services, settings)
{
}
public override void OnAgentLoaded(Agent agent)
{
var conv = _services.GetRequiredService<IConversationService>();
var isConvMode = conv.IsConversationMode();
var isEnabled = !agent.Utilities.IsNullOrEmpty() && agent.Utilities.Contains(UtilityName.ExcelHandler);
if (isEnabled && isConvMode)
{
AddUtility(agent, HANDLER_EXCEL);
}
base.OnAgentLoaded(agent);
}
private void AddUtility(Agent agent, string functionName)
{
var (prompt, fn) = GetPromptAndFunction(functionName);
if (fn != null)
{
if (!string.IsNullOrWhiteSpace(prompt))
{
agent.Instruction += $"\r\n\r\n{prompt}\r\n\r\n";
}
if (agent.Functions == null)
{
agent.Functions = new List<FunctionDef> { fn };
}
else
{
agent.Functions.Add(fn);
}
}
}
private (string, FunctionDef?) GetPromptAndFunction(string functionName)
{
var db = _services.GetRequiredService<IBotSharpRepository>();
var agent = db.GetAgent(BuiltInAgentId.UtilityAssistant);
var prompt = agent?.Templates?.FirstOrDefault(x => x.Name.IsEqualTo($"{functionName}.fn"))?.Content ?? string.Empty;
var loadAttachmentFn = agent?.Functions?.FirstOrDefault(x => x.Name.IsEqualTo(functionName));
return (prompt, loadAttachmentFn);
}
}

View file

@ -2,8 +2,17 @@ namespace BotSharp.Plugin.ExcelHandler.Hooks;
public class ExcelHandlerUtilityHook : IAgentUtilityHook
{
public void AddUtilities(List<string> utilities)
private const string HANDLER_EXCEL = "handle_excel_request";
public void AddUtilities(List<AgentUtility> utilities)
{
utilities.Add(UtilityName.ExcelHandler);
var utility = new AgentUtility
{
Name = UtilityName.ExcelHandler,
Functions = [new(HANDLER_EXCEL)],
Templates = [new($"{HANDLER_EXCEL}.fn")]
};
utilities.Add(utility);
}
}

View file

@ -19,7 +19,6 @@ public class FileHandlerPlugin : IBotSharpPlugin
return settingService.Bind<FileHandlerSettings>("FileHandler");
});
services.AddScoped<IAgentHook, FileHandlerHook>();
services.AddScoped<IAgentUtilityHook, FileHandlerUtilityHook>();
}

View file

@ -1,69 +0,0 @@
namespace BotSharp.Plugin.FileHandler.Hooks;
public class FileHandlerHook : AgentHookBase, IAgentHook
{
private const string READ_IMAGE_FN = "read_image";
private const string READ_PDF_FN = "read_pdf";
private const string GENERATE_IMAGE_FN = "generate_image";
private const string EDIT_IMAGE_FN = "edit_image";
public override string SelfId => string.Empty;
public FileHandlerHook(IServiceProvider services, AgentSettings settings) : base(services, settings)
{
}
public override void OnAgentLoaded(Agent agent)
{
var conv = _services.GetRequiredService<IConversationService>();
var isConvMode = conv.IsConversationMode();
if (isConvMode)
{
AddUtility(agent, UtilityName.ImageGenerator, GENERATE_IMAGE_FN);
AddUtility(agent, UtilityName.ImageReader, READ_IMAGE_FN);
AddUtility(agent, UtilityName.ImageEditor, EDIT_IMAGE_FN);
AddUtility(agent, UtilityName.PdfReader, READ_PDF_FN);
}
base.OnAgentLoaded(agent);
}
private void AddUtility(Agent agent, string utility, string functionName)
{
if (!IsEnableUtility(agent, utility)) return;
var (prompt, fn) = GetPromptAndFunction(functionName);
if (fn != null)
{
if (!string.IsNullOrWhiteSpace(prompt))
{
agent.Instruction += $"\r\n\r\n{prompt}\r\n\r\n";
}
if (agent.Functions == null)
{
agent.Functions = new List<FunctionDef> { fn };
}
else
{
agent.Functions.Add(fn);
}
}
}
private bool IsEnableUtility(Agent agent, string utility)
{
return !agent.Utilities.IsNullOrEmpty() && agent.Utilities.Contains(utility);
}
private (string, FunctionDef?) GetPromptAndFunction(string functionName)
{
var db = _services.GetRequiredService<IBotSharpRepository>();
var agent = db.GetAgent(BuiltInAgentId.UtilityAssistant);
var prompt = agent?.Templates?.FirstOrDefault(x => x.Name.IsEqualTo($"{functionName}.fn"))?.Content ?? string.Empty;
var loadAttachmentFn = agent?.Functions?.FirstOrDefault(x => x.Name.IsEqualTo(functionName));
return (prompt, loadAttachmentFn);
}
}

View file

@ -2,11 +2,41 @@ namespace BotSharp.Plugin.FileHandler.Hooks;
public class FileHandlerUtilityHook : IAgentUtilityHook
{
public void AddUtilities(List<string> utilities)
private const string READ_IMAGE_FN = "read_image";
private const string READ_PDF_FN = "read_pdf";
private const string GENERATE_IMAGE_FN = "generate_image";
private const string EDIT_IMAGE_FN = "edit_image";
public void AddUtilities(List<AgentUtility> utilities)
{
utilities.Add(UtilityName.ImageGenerator);
utilities.Add(UtilityName.ImageReader);
utilities.Add(UtilityName.ImageEditor);
utilities.Add(UtilityName.PdfReader);
var items = new List<AgentUtility>
{
new AgentUtility
{
Name = UtilityName.ImageGenerator,
Functions = [new(GENERATE_IMAGE_FN)],
Templates = [new($"{GENERATE_IMAGE_FN}.fn")]
},
new AgentUtility
{
Name = UtilityName.ImageReader,
Functions = [new(READ_IMAGE_FN)],
Templates = [new($"{READ_IMAGE_FN}.fn")]
},
new AgentUtility
{
Name = UtilityName.ImageEditor,
Functions = [new(EDIT_IMAGE_FN)],
Templates = [new($"{EDIT_IMAGE_FN}.fn")]
},
new AgentUtility
{
Name = UtilityName.PdfReader,
Functions = [new(READ_PDF_FN)],
Templates = [new($"{READ_PDF_FN}.fn")]
}
};
utilities.AddRange(items);
}
}

View file

@ -1,58 +0,0 @@
using BotSharp.Abstraction.Agents;
using BotSharp.Abstraction.Agents.Enums;
using BotSharp.Abstraction.Agents.Settings;
using BotSharp.Abstraction.Functions.Models;
using BotSharp.Abstraction.Repositories;
namespace BotSharp.Plugin.HttpHandler.Hooks;
public class HttpHandlerHook : AgentHookBase
{
private static string FUNCTION_NAME = "handle_http_request";
public override string SelfId => string.Empty;
public HttpHandlerHook(IServiceProvider services, AgentSettings settings)
: base(services, settings)
{
}
public override void OnAgentLoaded(Agent agent)
{
var conv = _services.GetRequiredService<IConversationService>();
var isConvMode = conv.IsConversationMode();
var isEnabled = !agent.Utilities.IsNullOrEmpty() && agent.Utilities.Contains(UtilityName.HttpHandler);
if (isConvMode && isEnabled)
{
var (prompt, fn) = GetPromptAndFunction(FUNCTION_NAME);
if (fn != null)
{
if (!string.IsNullOrWhiteSpace(prompt))
{
agent.Instruction += $"\r\n\r\n{prompt}\r\n\r\n";
}
if (agent.Functions == null)
{
agent.Functions = new List<FunctionDef> { fn };
}
else
{
agent.Functions.Add(fn);
}
}
}
base.OnAgentLoaded(agent);
}
private (string, FunctionDef?) GetPromptAndFunction(string functionName)
{
var db = _services.GetRequiredService<IBotSharpRepository>();
var agent = db.GetAgent(BuiltInAgentId.UtilityAssistant);
var prompt = agent?.Templates?.FirstOrDefault(x => x.Name.IsEqualTo($"{functionName}.fn"))?.Content ?? string.Empty;
var loadAttachmentFn = agent?.Functions?.FirstOrDefault(x => x.Name.IsEqualTo(functionName));
return (prompt, loadAttachmentFn);
}
}

View file

@ -4,8 +4,17 @@ namespace BotSharp.Plugin.HttpHandler.Hooks;
public class HttpHandlerUtilityHook : IAgentUtilityHook
{
public void AddUtilities(List<string> utilities)
private static string HTTP_HANDLER_FN = "handle_http_request";
public void AddUtilities(List<AgentUtility> utilities)
{
utilities.Add(UtilityName.HttpHandler);
var utility = new AgentUtility
{
Name = UtilityName.HttpHandler,
Functions = [new(HTTP_HANDLER_FN)],
Templates = [new($"{HTTP_HANDLER_FN}.fn")]
};
utilities.Add(utility);
}
}

View file

@ -20,7 +20,6 @@ public class HttpHandlerPlugin : IBotSharpPlugin
return settingService.Bind<HttpHandlerSettings>("HttpHandler");
});
services.AddScoped<IAgentHook, HttpHandlerHook>();
services.AddScoped<IAgentUtilityHook, HttpHandlerUtilityHook>();
}
}

View file

@ -1,60 +0,0 @@
namespace BotSharp.Plugin.KnowledgeBase.Hooks;
public class KnowledgeBaseAgentHook : AgentHookBase, IAgentHook
{
public override string SelfId => string.Empty;
public KnowledgeBaseAgentHook(IServiceProvider services, AgentSettings settings) : base(services, settings)
{
}
public override void OnAgentLoaded(Agent agent)
{
var conv = _services.GetRequiredService<IConversationService>();
var isConvMode = conv.IsConversationMode();
if (isConvMode)
{
AddUtility(agent, UtilityName.KnowledgeRetrieval, "knowledge_retrieval");
}
base.OnAgentLoaded(agent);
}
private void AddUtility(Agent agent, string utility, string functionName)
{
if (!IsEnableUtility(agent, utility)) return;
var (prompt, fn) = GetPromptAndFunction(functionName);
if (fn != null)
{
if (!string.IsNullOrWhiteSpace(prompt))
{
agent.Instruction += $"\r\n\r\n{prompt}\r\n\r\n";
}
if (agent.Functions == null)
{
agent.Functions = new List<FunctionDef> { fn };
}
else
{
agent.Functions.Add(fn);
}
}
}
private bool IsEnableUtility(Agent agent, string utility)
{
return !agent.Utilities.IsNullOrEmpty() && agent.Utilities.Contains(utility);
}
private (string, FunctionDef?) GetPromptAndFunction(string functionName)
{
var db = _services.GetRequiredService<IBotSharpRepository>();
var agent = db.GetAgent(BuiltInAgentId.UtilityAssistant);
var prompt = agent?.Templates?.FirstOrDefault(x => x.Name.IsEqualTo($"{functionName}.fn"))?.Content ?? string.Empty;
var fn = agent?.Functions?.FirstOrDefault(x => x.Name.IsEqualTo(functionName));
return (prompt, fn);
}
}

View file

@ -2,8 +2,17 @@ namespace BotSharp.Plugin.KnowledgeBase.Hooks;
public class KnowledgeBaseUtilityHook : IAgentUtilityHook
{
public void AddUtilities(List<string> utilities)
private const string KNOWLEDGE_RETRIEVAL_FN = "knowledge_retrieval";
public void AddUtilities(List<AgentUtility> utilities)
{
utilities.Add(UtilityName.KnowledgeRetrieval);
var utility = new AgentUtility
{
Name = UtilityName.KnowledgeRetrieval,
Functions = [new(KNOWLEDGE_RETRIEVAL_FN)],
Templates = [new($"{KNOWLEDGE_RETRIEVAL_FN}.fn")]
};
utilities.Add(utility);
}
}

View file

@ -25,7 +25,6 @@ public class KnowledgeBasePlugin : IBotSharpPlugin
services.AddSingleton<IPdf2TextConverter, PigPdf2TextConverter>();
services.AddScoped<IAgentUtilityHook, KnowledgeBaseUtilityHook>();
services.AddScoped<IAgentHook, KnowledgeBaseAgentHook>();
services.AddScoped<IKnowledgeService, KnowledgeService>();
}

View file

@ -8,14 +8,15 @@ public class AgentDocument : MongoBase
public string? InheritAgentId { get; set; }
public string? IconUrl { get; set; }
public string Instruction { get; set; }
public bool IsPublic { get; set; }
public bool Disabled { get; set; }
public bool MergeUtility { get; set; }
public List<ChannelInstructionMongoElement> ChannelInstructions { get; set; }
public List<AgentTemplateMongoElement> Templates { get; set; }
public List<FunctionDefMongoElement> Functions { get; set; }
public List<AgentResponseMongoElement> Responses { get; set; }
public List<string> Samples { get; set; }
public List<string> Utilities { get; set; }
public bool IsPublic { get; set; }
public bool Disabled { get; set; }
public List<AgentUtilityMongoElement> Utilities { get; set; }
public List<string> Profiles { get; set; }
public List<RoutingRuleMongoElement> RoutingRules { get; set; }
public AgentLlmConfigMongoElement? LlmConfig { get; set; }

View file

@ -0,0 +1,63 @@
using BotSharp.Abstraction.Agents.Models;
namespace BotSharp.Plugin.MongoStorage.Models;
public class AgentUtilityMongoElement
{
public string Name { get; set; }
public bool Disabled { get; set; }
public List<UtilityFunctionMongoElement> Functions { get; set; } = [];
public List<UtilityTemplateMongoElement> Templates { get; set; } = [];
public static AgentUtilityMongoElement ToMongoElement(AgentUtility utility)
{
return new AgentUtilityMongoElement
{
Name = utility.Name,
Disabled = utility.Disabled,
Functions = utility.Functions?.Select(x => new UtilityFunctionMongoElement(x.Name))?.ToList() ?? [],
Templates = utility.Templates?.Select(x => new UtilityTemplateMongoElement(x.Name))?.ToList() ?? []
};
}
public static AgentUtility ToDomainElement(AgentUtilityMongoElement utility)
{
return new AgentUtility
{
Name = utility.Name,
Disabled = utility.Disabled,
Functions = utility.Functions?.Select(x => new UtilityFunction(x.Name))?.ToList() ?? [],
Templates = utility.Templates?.Select(x => new UtilityTemplate(x.Name))?.ToList() ?? []
};
}
}
public class UtilityFunctionMongoElement
{
public string Name { get; set; }
public UtilityFunctionMongoElement()
{
}
public UtilityFunctionMongoElement(string name)
{
Name = name;
}
}
public class UtilityTemplateMongoElement
{
public string Name { get; set; }
public UtilityTemplateMongoElement()
{
}
public UtilityTemplateMongoElement(string name)
{
Name = name;
}
}

View file

@ -2,7 +2,6 @@ using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Functions.Models;
using BotSharp.Abstraction.Repositories.Filters;
using BotSharp.Abstraction.Routing.Models;
using MongoDB.Driver;
namespace BotSharp.Plugin.MongoStorage.Repository;
@ -57,7 +56,7 @@ public partial class MongoRepository
UpdateAgentLlmConfig(agent.Id, agent.LlmConfig);
break;
case AgentField.Utility:
UpdateAgentUtilities(agent.Id, agent.Utilities);
UpdateAgentUtilities(agent.Id, agent.MergeUtility, agent.Utilities);
break;
case AgentField.All:
UpdateAgentAllFields(agent);
@ -224,13 +223,16 @@ public partial class MongoRepository
_dc.Agents.UpdateOne(filter, update);
}
private void UpdateAgentUtilities(string agentId, List<string> utilities)
private void UpdateAgentUtilities(string agentId, bool mergeUtility, List<AgentUtility> utilities)
{
if (utilities == null) return;
var elements = utilities?.Select(x => AgentUtilityMongoElement.ToMongoElement(x))?.ToList() ?? [];
var filter = Builders<AgentDocument>.Filter.Eq(x => x.Id, agentId);
var update = Builders<AgentDocument>.Update
.Set(x => x.Utilities, utilities)
.Set(x => x.MergeUtility, mergeUtility)
.Set(x => x.Utilities, elements)
.Set(x => x.UpdatedTime, DateTime.UtcNow);
_dc.Agents.UpdateOne(filter, update);
@ -254,6 +256,7 @@ public partial class MongoRepository
.Set(x => x.Name, agent.Name)
.Set(x => x.Description, agent.Description)
.Set(x => x.Disabled, agent.Disabled)
.Set(x => x.MergeUtility, agent.MergeUtility)
.Set(x => x.Type, agent.Type)
.Set(x => x.Profiles, agent.Profiles)
.Set(x => x.RoutingRules, agent.RoutingRules.Select(r => RoutingRuleMongoElement.ToMongoElement(r)).ToList())
@ -263,7 +266,7 @@ public partial class MongoRepository
.Set(x => x.Functions, agent.Functions.Select(f => FunctionDefMongoElement.ToMongoElement(f)).ToList())
.Set(x => x.Responses, agent.Responses.Select(r => AgentResponseMongoElement.ToMongoElement(r)).ToList())
.Set(x => x.Samples, agent.Samples)
.Set(x => x.Utilities, agent.Utilities)
.Set(x => x.Utilities, agent.Utilities.Select(u => AgentUtilityMongoElement.ToMongoElement(u)).ToList())
.Set(x => x.LlmConfig, AgentLlmConfigMongoElement.ToMongoElement(agent.LlmConfig))
.Set(x => x.IsPublic, agent.IsPublic)
.Set(x => x.UpdatedTime, DateTime.UtcNow);
@ -406,28 +409,19 @@ public partial class MongoRepository
IconUrl = x.IconUrl,
Description = x.Description,
Instruction = x.Instruction,
ChannelInstructions = x.ChannelInstructions?
.Select(i => ChannelInstructionMongoElement.ToMongoElement(i))?
.ToList() ?? new List<ChannelInstructionMongoElement>(),
Templates = x.Templates?
.Select(t => AgentTemplateMongoElement.ToMongoElement(t))?
.ToList() ?? new List<AgentTemplateMongoElement>(),
Functions = x.Functions?
.Select(f => FunctionDefMongoElement.ToMongoElement(f))?
.ToList() ?? new List<FunctionDefMongoElement>(),
Responses = x.Responses?
.Select(r => AgentResponseMongoElement.ToMongoElement(r))?
.ToList() ?? new List<AgentResponseMongoElement>(),
ChannelInstructions = x.ChannelInstructions?.Select(i => ChannelInstructionMongoElement.ToMongoElement(i))?.ToList() ?? [],
Templates = x.Templates?.Select(t => AgentTemplateMongoElement.ToMongoElement(t))?.ToList() ?? [],
Functions = x.Functions?.Select(f => FunctionDefMongoElement.ToMongoElement(f))?.ToList() ?? [],
Responses = x.Responses?.Select(r => AgentResponseMongoElement.ToMongoElement(r))?.ToList() ?? [],
Samples = x.Samples ?? new List<string>(),
Utilities = x.Utilities ?? new List<string>(),
Utilities = x.Utilities?.Select(u => AgentUtilityMongoElement.ToMongoElement(u))?.ToList() ?? [],
IsPublic = x.IsPublic,
Type = x.Type,
InheritAgentId = x.InheritAgentId,
Disabled = x.Disabled,
MergeUtility = x.MergeUtility,
Profiles = x.Profiles,
RoutingRules = x.RoutingRules?
.Select(r => RoutingRuleMongoElement.ToMongoElement(r))?
.ToList() ?? new List<RoutingRuleMongoElement>(),
RoutingRules = x.RoutingRules?.Select(r => RoutingRuleMongoElement.ToMongoElement(r))?.ToList() ?? [],
LlmConfig = AgentLlmConfigMongoElement.ToMongoElement(x.LlmConfig),
CreatedTime = x.CreatedDateTime,
UpdatedTime = x.UpdatedDateTime
@ -505,26 +499,17 @@ public partial class MongoRepository
IconUrl = agentDoc.IconUrl,
Description = agentDoc.Description,
Instruction = agentDoc.Instruction,
ChannelInstructions = !agentDoc.ChannelInstructions.IsNullOrEmpty() ? agentDoc.ChannelInstructions
.Select(i => ChannelInstructionMongoElement.ToDomainElement(i))
.ToList() : new List<ChannelInstruction>(),
Templates = !agentDoc.Templates.IsNullOrEmpty() ? agentDoc.Templates
.Select(t => AgentTemplateMongoElement.ToDomainElement(t))
.ToList() : new List<AgentTemplate>(),
Functions = !agentDoc.Functions.IsNullOrEmpty() ? agentDoc.Functions
.Select(f => FunctionDefMongoElement.ToDomainElement(f))
.ToList() : new List<FunctionDef>(),
Responses = !agentDoc.Responses.IsNullOrEmpty() ? agentDoc.Responses
.Select(r => AgentResponseMongoElement.ToDomainElement(r))
.ToList() : new List<AgentResponse>(),
RoutingRules = !agentDoc.RoutingRules.IsNullOrEmpty() ? agentDoc.RoutingRules
.Select(r => RoutingRuleMongoElement.ToDomainElement(agentDoc.Id, agentDoc.Name, r))
.ToList() : new List<RoutingRule>(),
ChannelInstructions = agentDoc.ChannelInstructions?.Select(i => ChannelInstructionMongoElement.ToDomainElement(i))?.ToList() ?? [],
Templates = agentDoc.Templates?.Select(t => AgentTemplateMongoElement.ToDomainElement(t))?.ToList() ?? [],
Functions = agentDoc.Functions?.Select(f => FunctionDefMongoElement.ToDomainElement(f)).ToList() ?? [],
Responses = agentDoc.Responses?.Select(r => AgentResponseMongoElement.ToDomainElement(r))?.ToList() ?? [],
RoutingRules = agentDoc.RoutingRules?.Select(r => RoutingRuleMongoElement.ToDomainElement(agentDoc.Id, agentDoc.Name, r))?.ToList() ?? [],
LlmConfig = AgentLlmConfigMongoElement.ToDomainElement(agentDoc.LlmConfig),
Samples = agentDoc.Samples ?? new List<string>(),
Utilities = agentDoc.Utilities ?? new List<string>(),
Samples = agentDoc.Samples ?? [],
Utilities = agentDoc.Utilities?.Select(u => AgentUtilityMongoElement.ToDomainElement(u))?.ToList() ?? [],
IsPublic = agentDoc.IsPublic,
Disabled = agentDoc.Disabled,
MergeUtility = agentDoc.MergeUtility,
Type = agentDoc.Type,
InheritAgentId = agentDoc.InheritAgentId,
Profiles = agentDoc.Profiles,

View file

@ -27,79 +27,4 @@ public class PlannerAgentHook : AgentHookBase
return true;
}
public override void OnAgentLoaded(Agent agent)
{
var conv = _services.GetRequiredService<IConversationService>();
var isConvMode = conv.IsConversationMode();
var isEnabled = !agent.Utilities.IsNullOrEmpty() && agent.Utilities.Contains(UtilityName.TwoStagePlanner);
if (isConvMode && isEnabled)
{
var (prompt, fn) = GetPromptAndFunction("plan_primary_stage");
if (fn != null)
{
if (!string.IsNullOrWhiteSpace(prompt))
{
agent.Instruction += $"\r\n\r\n{prompt}\r\n\r\n";
}
if (agent.Functions == null)
{
agent.Functions = new List<FunctionDef> { fn };
}
else
{
agent.Functions.Add(fn);
}
}
(prompt, fn) = GetPromptAndFunction("plan_secondary_stage");
if (fn != null)
{
if (!string.IsNullOrWhiteSpace(prompt))
{
agent.Instruction += $"\r\n\r\n{prompt}\r\n\r\n";
}
if (agent.Functions == null)
{
agent.Functions = new List<FunctionDef> { fn };
}
else
{
agent.Functions.Add(fn);
}
}
(prompt, fn) = GetPromptAndFunction("plan_summary");
if (fn != null)
{
if (!string.IsNullOrWhiteSpace(prompt))
{
agent.Instruction += $"\r\n\r\n{prompt}\r\n\r\n";
}
if (agent.Functions == null)
{
agent.Functions = new List<FunctionDef> { fn };
}
else
{
agent.Functions.Add(fn);
}
}
}
base.OnAgentLoaded(agent);
}
private (string, FunctionDef?) GetPromptAndFunction(string functionName)
{
var db = _services.GetRequiredService<IBotSharpRepository>();
var agent = db.GetAgent(BuiltInAgentId.UtilityAssistant);
var prompt = agent?.Templates?.FirstOrDefault(x => x.Name.IsEqualTo($"{functionName}.fn"))?.Content ?? string.Empty;
var loadAttachmentFn = agent?.Functions?.FirstOrDefault(x => x.Name.IsEqualTo(functionName));
return (prompt, loadAttachmentFn);
}
}

View file

@ -2,8 +2,27 @@ namespace BotSharp.Plugin.Planner.Hooks;
public class PlannerUtilityHook : IAgentUtilityHook
{
public void AddUtilities(List<string> utilities)
private const string PRIMARY_STAGE_FN = "plan_primary_stage";
private const string SECONDARY_STAGE_FN = "plan_secondary_stage";
private const string SUMMARY_FN = "plan_summary";
public void AddUtilities(List<AgentUtility> utilities)
{
utilities.Add(UtilityName.TwoStagePlanner);
var utility = new AgentUtility
{
Name = UtilityName.TwoStagePlanner,
Functions = [
new(PRIMARY_STAGE_FN),
new(SECONDARY_STAGE_FN),
new(SUMMARY_FN)
],
Templates = [
new($"{PRIMARY_STAGE_FN}.fn"),
new($"{SECONDARY_STAGE_FN}.fn"),
new($"{SUMMARY_FN}.fn")
]
};
utilities.Add(utility);
}
}

View file

@ -9,7 +9,8 @@
"disabled": false,
"isPublic": true,
"profiles": [ "planning" ],
"utilities": [ "two-stage-planner", "sql-dictionary-lookup", "excel-handler" ],
"mergeUtility": true,
"utilities": [],
"llmConfig": {
"provider": "openai",
"model": "gpt-4o",

View file

@ -1,51 +0,0 @@
namespace BotSharp.Plugin.PythonInterpreter.Hooks;
public class InterpreterAgentHook : AgentHookBase
{
private static string FUNCTION_NAME = "python_interpreter";
public override string SelfId => string.Empty;
public InterpreterAgentHook(IServiceProvider services, AgentSettings settings)
: base(services, settings)
{
}
public override void OnAgentLoaded(Agent agent)
{
var conv = _services.GetRequiredService<IConversationService>();
var isConvMode = conv.IsConversationMode();
var isEnabled = !agent.Utilities.IsNullOrEmpty() && agent.Utilities.Contains(UtilityName.PythonInterpreter);
if (isConvMode && isEnabled)
{
var (prompt, fn) = GetPromptAndFunction();
if (fn != null)
{
if (!string.IsNullOrWhiteSpace(prompt))
{
agent.Instruction += $"\r\n\r\n{prompt}\r\n\r\n";
}
if (agent.Functions == null)
{
agent.Functions = new List<FunctionDef> { fn };
}
else
{
agent.Functions.Add(fn);
}
}
}
base.OnAgentLoaded(agent);
}
private (string, FunctionDef?) GetPromptAndFunction()
{
var db = _services.GetRequiredService<IBotSharpRepository>();
var agent = db.GetAgent(BuiltInAgentId.UtilityAssistant);
var prompt = agent?.Templates?.FirstOrDefault(x => x.Name.IsEqualTo($"{FUNCTION_NAME}.fn"))?.Content ?? string.Empty;
var loadAttachmentFn = agent?.Functions?.FirstOrDefault(x => x.Name.IsEqualTo(FUNCTION_NAME));
return (prompt, loadAttachmentFn);
}
}

View file

@ -2,8 +2,17 @@ namespace BotSharp.Plugin.PythonInterpreter.Hooks;
public class InterpreterUtilityHook : IAgentUtilityHook
{
public void AddUtilities(List<string> utilities)
private static string FUNCTION_NAME = "python_interpreter";
public void AddUtilities(List<AgentUtility> utilities)
{
utilities.Add(UtilityName.PythonInterpreter);
var utility = new AgentUtility()
{
Name = UtilityName.PythonInterpreter,
Functions = [new(FUNCTION_NAME)],
Templates = [new($"{FUNCTION_NAME}.fn")]
};
utilities.Add(utility);
}
}

View file

@ -15,7 +15,6 @@ public class InterpreterPlugin : IBotSharpAppPlugin
public void RegisterDI(IServiceCollection services, IConfiguration config)
{
services.AddScoped<IAgentHook, InterpreterAgentHook>();
services.AddScoped<IAgentUtilityHook, InterpreterUtilityHook>();
}

View file

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>$(TargetFramework)</TargetFramework>

View file

@ -1,6 +1,6 @@
namespace BotSharp.Plugin.SqlDriver.Enum;
public class Utility
public class UtilityName
{
public const string SqlExecutor = "sql-executor";
public const string SqlDictionaryLookup = "sql-dictionary-lookup";

View file

@ -0,0 +1,20 @@
namespace BotSharp.Plugin.SqlDriver.Helpers;
internal static class SqlDriverHelper
{
internal static string GetDatabaseType(IServiceProvider services)
{
var settings = services.GetRequiredService<SqlDriverSetting>();
var dbType = "MySQL";
if (!string.IsNullOrWhiteSpace(settings?.SqlServerConnectionString))
{
dbType = "SQL Server";
}
else if (!string.IsNullOrWhiteSpace(settings?.SqlLiteConnectionString))
{
dbType = "SQL Lite";
}
return dbType;
}
}

View file

@ -1,84 +0,0 @@
using BotSharp.Abstraction.Agents.Enums;
using BotSharp.Abstraction.Agents.Settings;
using BotSharp.Abstraction.Functions.Models;
using BotSharp.Abstraction.Repositories;
namespace BotSharp.Plugin.SqlDriver.Hooks;
public class GetTableDefinitionHook : AgentHookBase, IAgentHook
{
private const string SQL_EXECUTOR_TEMPLATE = "sql_table_definition.fn";
private IEnumerable<string> _targetSqlExecutorFunctions = new List<string>
{
"sql_table_definition",
};
public override string SelfId => BuiltInAgentId.Planner;
public GetTableDefinitionHook(IServiceProvider services, AgentSettings settings) : base(services, settings)
{
}
public override void OnAgentLoaded(Agent agent)
{
var conv = _services.GetRequiredService<IConversationService>();
var isConvMode = conv.IsConversationMode();
var isEnabled = !agent.Utilities.IsNullOrEmpty() && agent.Utilities.Contains(Utility.SqlTableDefinition);
if (isConvMode && isEnabled)
{
var (prompt, fns) = GetPromptAndFunctions();
if (!fns.IsNullOrEmpty())
{
if (!string.IsNullOrWhiteSpace(prompt))
{
agent.Instruction += $"\r\n\r\n{prompt}\r\n\r\n";
}
if (agent.Functions == null)
{
agent.Functions = fns;
}
else
{
agent.Functions.AddRange(fns);
}
}
}
base.OnAgentLoaded(agent);
}
private (string, List<FunctionDef>?) GetPromptAndFunctions()
{
var db = _services.GetRequiredService<IBotSharpRepository>();
var agent = db.GetAgent(BuiltInAgentId.UtilityAssistant);
var fns = agent?.Functions?.Where(x => _targetSqlExecutorFunctions.Contains(x.Name))?.ToList();
var prompt = agent?.Templates?.FirstOrDefault(x => x.Name.IsEqualTo(SQL_EXECUTOR_TEMPLATE))?.Content ?? string.Empty;
var dbType = GetDatabaseType();
var render = _services.GetRequiredService<ITemplateRender>();
prompt = render.Render(prompt, new Dictionary<string, object>
{
{ "db_type", dbType }
});
return (prompt, fns);
}
private string GetDatabaseType()
{
var settings = _services.GetRequiredService<SqlDriverSetting>();
var dbType = "MySQL";
if (!string.IsNullOrWhiteSpace(settings?.SqlServerConnectionString))
{
dbType = "SQL Server";
}
else if (!string.IsNullOrWhiteSpace(settings?.SqlLiteConnectionString))
{
dbType = "SQL Lite";
}
return dbType;
}
}

View file

@ -1,84 +0,0 @@
using BotSharp.Abstraction.Agents.Enums;
using BotSharp.Abstraction.Agents.Settings;
using BotSharp.Abstraction.Functions.Models;
using BotSharp.Abstraction.Repositories;
namespace BotSharp.Plugin.SqlDriver.Hooks;
public class SqlDictionaryLookupHook : AgentHookBase, IAgentHook
{
private const string SQL_EXECUTOR_TEMPLATE = "verify_dictionary_term.fn";
private IEnumerable<string> _targetSqlExecutorFunctions = new List<string>
{
"verify_dictionary_term",
};
public override string SelfId => BuiltInAgentId.Planner;
public SqlDictionaryLookupHook(IServiceProvider services, AgentSettings settings) : base(services, settings)
{
}
public override void OnAgentLoaded(Agent agent)
{
var conv = _services.GetRequiredService<IConversationService>();
var isConvMode = conv.IsConversationMode();
var isEnabled = !agent.Utilities.IsNullOrEmpty() && agent.Utilities.Contains(Utility.SqlDictionaryLookup);
if (isConvMode && isEnabled)
{
var (prompt, fns) = GetPromptAndFunctions();
if (!fns.IsNullOrEmpty())
{
if (!string.IsNullOrWhiteSpace(prompt))
{
agent.Instruction += $"\r\n\r\n{prompt}\r\n\r\n";
}
if (agent.Functions == null)
{
agent.Functions = fns;
}
else
{
agent.Functions.AddRange(fns);
}
}
}
base.OnAgentLoaded(agent);
}
private (string, List<FunctionDef>?) GetPromptAndFunctions()
{
var db = _services.GetRequiredService<IBotSharpRepository>();
var agent = db.GetAgent(BuiltInAgentId.UtilityAssistant);
var fns = agent?.Functions?.Where(x => _targetSqlExecutorFunctions.Contains(x.Name))?.ToList();
var prompt = agent?.Templates?.FirstOrDefault(x => x.Name.IsEqualTo(SQL_EXECUTOR_TEMPLATE))?.Content ?? string.Empty;
var dbType = GetDatabaseType();
var render = _services.GetRequiredService<ITemplateRender>();
prompt = render.Render(prompt, new Dictionary<string, object>
{
{ "db_type", dbType }
});
return (prompt, fns);
}
private string GetDatabaseType()
{
var settings = _services.GetRequiredService<SqlDriverSetting>();
var dbType = "MySQL";
if (!string.IsNullOrWhiteSpace(settings?.SqlServerConnectionString))
{
dbType = "SQL Server";
}
else if (!string.IsNullOrWhiteSpace(settings?.SqlLiteConnectionString))
{
dbType = "SQL Lite";
}
return dbType;
}
}

View file

@ -0,0 +1,19 @@
using BotSharp.Abstraction.Agents.Settings;
namespace BotSharp.Plugin.SqlDriver.Hooks;
public class SqlDriverAgentHook : AgentHookBase, IAgentHook
{
public override string SelfId => BuiltInAgentId.Planner;
public SqlDriverAgentHook(IServiceProvider services, AgentSettings settings)
: base(services, settings)
{
}
public override void OnAgentLoaded(Agent agent)
{
var dbType = SqlDriverHelper.GetDatabaseType(_services);
agent.TemplateDict["db_type"] = dbType;
}
}

View file

@ -1,85 +0,0 @@
using BotSharp.Abstraction.Agents.Enums;
using BotSharp.Abstraction.Agents.Settings;
using BotSharp.Abstraction.Functions.Models;
using BotSharp.Abstraction.Repositories;
namespace BotSharp.Plugin.SqlDriver.Hooks;
public class SqlExecutorHook : AgentHookBase, IAgentHook
{
private const string SQL_EXECUTOR_TEMPLATE = "sql_executor.fn";
private IEnumerable<string> _targetSqlExecutorFunctions = new List<string>
{
"sql_select",
"sql_table_definition",
};
public override string SelfId => string.Empty;
public SqlExecutorHook(IServiceProvider services, AgentSettings settings) : base(services, settings)
{
}
public override void OnAgentLoaded(Agent agent)
{
var conv = _services.GetRequiredService<IConversationService>();
var isConvMode = conv.IsConversationMode();
var isEnabled = !agent.Utilities.IsNullOrEmpty() && agent.Utilities.Contains(Utility.SqlExecutor);
if (isConvMode && isEnabled)
{
var (prompt, fns) = GetPromptAndFunctions();
if (!fns.IsNullOrEmpty())
{
if (!string.IsNullOrWhiteSpace(prompt))
{
agent.Instruction += $"\r\n\r\n{prompt}\r\n\r\n";
}
if (agent.Functions == null)
{
agent.Functions = fns;
}
else
{
agent.Functions.AddRange(fns);
}
}
}
base.OnAgentLoaded(agent);
}
private (string, List<FunctionDef>?) GetPromptAndFunctions()
{
var db = _services.GetRequiredService<IBotSharpRepository>();
var agent = db.GetAgent(BuiltInAgentId.UtilityAssistant);
var fns = agent?.Functions?.Where(x => _targetSqlExecutorFunctions.Contains(x.Name))?.ToList();
var prompt = agent?.Templates?.FirstOrDefault(x => x.Name.IsEqualTo(SQL_EXECUTOR_TEMPLATE))?.Content ?? string.Empty;
var dbType = GetDatabaseType(); //need change-> using hook?
var render = _services.GetRequiredService<ITemplateRender>();
prompt = render.Render(prompt, new Dictionary<string, object>
{
{ "db_type", dbType }
});
return (prompt, fns);
}
private string GetDatabaseType()
{
var settings = _services.GetRequiredService<SqlDriverSetting>();
var dbType = "MySQL";
if (!string.IsNullOrWhiteSpace(settings?.SqlServerConnectionString))
{
dbType = "SQL Server";
}
else if (!string.IsNullOrWhiteSpace(settings?.SqlLiteConnectionString))
{
dbType = "SQL Lite";
}
return dbType;
}
}

View file

@ -2,10 +2,34 @@ namespace BotSharp.Plugin.SqlDriver.Hooks;
public class SqlUtilityHook : IAgentUtilityHook
{
public void AddUtilities(List<string> utilities)
private const string SQL_TABLE_DEFINITION_FN = "sql_table_definition";
private const string VERIFY_DICTIONARY_TERM_FN = "verify_dictionary_term";
private const string SQL_SELECT_FN = "sql_select";
public void AddUtilities(List<AgentUtility> utilities)
{
utilities.Add(Utility.SqlExecutor);
utilities.Add(Utility.SqlDictionaryLookup);
utilities.Add(Utility.SqlTableDefinition);
var items = new List<AgentUtility>
{
new AgentUtility
{
Name = UtilityName.SqlTableDefinition,
Functions = [new(SQL_TABLE_DEFINITION_FN)],
Templates = [new($"{SQL_TABLE_DEFINITION_FN}.fn")]
},
new AgentUtility
{
Name = UtilityName.SqlDictionaryLookup,
Functions = [new(VERIFY_DICTIONARY_TERM_FN)],
Templates = [new($"{VERIFY_DICTIONARY_TERM_FN}.fn")]
},
new AgentUtility
{
Name = UtilityName.SqlExecutor,
Functions = [new(SQL_SELECT_FN), new(SQL_TABLE_DEFINITION_FN)],
Templates = [new($"sql_executor.fn")]
}
};
utilities.AddRange(items);
}
}

View file

@ -1,4 +1,4 @@
namespace BotSharp.Plugin.SqlHero.Settings;
namespace BotSharp.Plugin.SqlDriver.Settings;
public class SqlDriverSetting
{

View file

@ -1,4 +1,3 @@
using BotSharp.Abstraction.Agents.Enums;
using BotSharp.Abstraction.Planning;
namespace BotSharp.Plugin.SqlDriver;
@ -25,12 +24,10 @@ public class SqlDriverPlugin : IBotSharpPlugin
services.AddScoped<SqlDriverService>();
services.AddScoped<DbKnowledgeService>();
services.AddScoped<IKnowledgeHook, SqlDriverKnowledgeHook>();
services.AddScoped<IAgentHook, SqlExecutorHook>();
services.AddScoped<IAgentUtilityHook, SqlUtilityHook>();
services.AddScoped<IPlanningHook, SqlDriverPlanningHook>();
services.AddScoped<IAgentHook, SqlDictionaryLookupHook>();
services.AddScoped<IAgentHook, GetTableDefinitionHook>();
services.AddScoped<IKnowledgeHook, SqlDriverKnowledgeHook>();
services.AddScoped<IAgentHook, SqlDriverAgentHook>();
services.AddScoped<IConversationHook, SqlDriverConversationHook>();
services.AddScoped<IAgentUtilityHook, SqlUtilityHook>();
}
}

View file

@ -6,10 +6,8 @@ global using System.Text.RegularExpressions;
global using System.Threading.Tasks;
global using System.Linq;
global using System.Text.Json;
global using Microsoft.Extensions.Configuration;
global using Microsoft.Extensions.Logging;
global using BotSharp.Abstraction.Conversations;
global using BotSharp.Abstraction.Plugins;
global using BotSharp.Abstraction.Conversations.Models;
@ -26,9 +24,10 @@ global using BotSharp.Abstraction.Settings;
global using BotSharp.Plugin.SqlDriver.Hooks;
global using BotSharp.Plugin.SqlDriver.Services;
global using BotSharp.Plugin.SqlDriver.Enum;
global using BotSharp.Plugin.SqlHero.Settings;
global using BotSharp.Abstraction.Agents.Enums;
global using BotSharp.Abstraction.Instructs;
global using BotSharp.Abstraction.Instructs.Models;
global using BotSharp.Abstraction.Routing;
global using BotSharp.Plugin.SqlDriver.Interfaces;
global using BotSharp.Plugin.SqlDriver.Helpers;
global using BotSharp.Plugin.SqlDriver.Settings;

View file

@ -1,58 +0,0 @@
using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Agents.Settings;
using BotSharp.Abstraction.Repositories;
using BotSharp.Abstraction.Utilities;
using BotSharp.Plugin.Twilio.OutboundPhoneCallHandler.Enums;
namespace BotSharp.Plugin.Twilio.OutboundPhoneCallHandler.Hooks
{
internal class OutboundPhoneCallHandlerHook : AgentHookBase
{
private static string FUNCTION_NAME = "twilio_outbound_phone_call";
public override string SelfId => string.Empty;
public OutboundPhoneCallHandlerHook(IServiceProvider services, AgentSettings settings) : base(services, settings)
{
}
public override void OnAgentLoaded(Agent agent)
{
var conv = _services.GetRequiredService<IConversationService>();
var isConvMode = conv.IsConversationMode();
var isEnabled = !agent.Utilities.IsNullOrEmpty() && agent.Utilities.Contains(UtilityName.OutboundPhoneCall);
if (isConvMode && isEnabled)
{
var (prompt, fn) = GetPromptAndFunction();
if (fn != null)
{
if (!string.IsNullOrWhiteSpace(prompt))
{
agent.Instruction += $"\r\n\r\n{prompt}\r\n\r\n";
}
if (agent.Functions == null)
{
agent.Functions = new List<FunctionDef> { fn };
}
else
{
agent.Functions.Add(fn);
}
}
}
base.OnAgentLoaded(agent);
}
private (string, FunctionDef) GetPromptAndFunction()
{
var db = _services.GetRequiredService<IBotSharpRepository>();
var agent = db.GetAgent(BuiltInAgentId.UtilityAssistant);
var prompt = agent?.Templates?.FirstOrDefault(x => x.Name.IsEqualTo($"{FUNCTION_NAME}.fn"))?.Content ?? string.Empty;
var loadAttachmentFn = agent?.Functions?.FirstOrDefault(x => x.Name.IsEqualTo(FUNCTION_NAME));
return (prompt, loadAttachmentFn);
}
}
}

View file

@ -1,12 +1,21 @@
using BotSharp.Abstraction.Agents.Models;
using BotSharp.Plugin.Twilio.OutboundPhoneCallHandler.Enums;
namespace BotSharp.Plugin.Twilio.OutboundPhoneCallHandler.Hooks
namespace BotSharp.Plugin.Twilio.OutboundPhoneCallHandler.Hooks;
public class OutboundPhoneCallHandlerUtilityHook : IAgentUtilityHook
{
public class OutboundPhoneCallHandlerUtilityHook : IAgentUtilityHook
private static string OUTBOUND_PHONE_CALL_FN = "twilio_outbound_phone_call";
public void AddUtilities(List<AgentUtility> utilities)
{
public void AddUtilities(List<string> utilities)
var utility = new AgentUtility
{
utilities.Add(UtilityName.OutboundPhoneCall);
}
Name = UtilityName.OutboundPhoneCall,
Functions = [new(OUTBOUND_PHONE_CALL_FN)],
Templates = [new($"{OUTBOUND_PHONE_CALL_FN}.fn")]
};
utilities.Add(utility);
}
}

View file

@ -31,7 +31,6 @@ public class TwilioPlugin : IBotSharpPlugin
services.AddSingleton<TwilioMessageQueue>();
services.AddHostedService<TwilioMessageQueueService>();
services.AddTwilioRequestValidation();
services.AddScoped<IAgentHook, OutboundPhoneCallHandlerHook>();
services.AddScoped<IAgentUtilityHook, OutboundPhoneCallHandlerUtilityHook>();
}
}