Merge branch 'SciSharp:master' into master
This commit is contained in:
commit
4841c43755
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ public interface IAgentHook
|
|||
|
||||
bool OnSamplesLoaded(List<string> samples);
|
||||
|
||||
void OnAgentUtilityLoaded(Agent agent);
|
||||
|
||||
/// <summary>
|
||||
/// Triggered when agent is loaded completely.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -59,5 +59,5 @@ public interface IAgentService
|
|||
|
||||
PluginDef GetPlugin(string agentId);
|
||||
|
||||
IEnumerable<string> GetAgentUtilities();
|
||||
IEnumerable<AgentUtility> GetAgentUtilityOptions();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,5 +2,5 @@ namespace BotSharp.Abstraction.Agents;
|
|||
|
||||
public interface IAgentUtilityHook
|
||||
{
|
||||
void AddUtilities(List<string> utilities);
|
||||
void AddUtilities(List<AgentUtility> utilities);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Abstraction.Routing;
|
||||
|
||||
namespace BotSharp.Abstraction.Routing.Planning;
|
||||
namespace BotSharp.Abstraction.Planning;
|
||||
|
||||
public interface IExecutor
|
||||
{
|
||||
|
|
@ -1,9 +1,19 @@
|
|||
using BotSharp.Abstraction.Functions.Models;
|
||||
|
||||
namespace BotSharp.Abstraction.Planning;
|
||||
|
||||
/// <summary>
|
||||
/// Planning process for Task Agent
|
||||
/// https://www.promptingguide.ai/techniques/cot
|
||||
/// </summary>
|
||||
public class ITaskPlanner
|
||||
public interface ITaskPlanner
|
||||
{
|
||||
|
||||
Task<FunctionCallFromLlm> GetNextInstruction(Agent router, string messageId, List<RoleDialogModel> dialogs);
|
||||
Task<bool> AgentExecuting(Agent router, FunctionCallFromLlm inst, RoleDialogModel message, List<RoleDialogModel> dialogs);
|
||||
Task<bool> AgentExecuted(Agent router, FunctionCallFromLlm inst, RoleDialogModel message, List<RoleDialogModel> dialogs);
|
||||
List<RoleDialogModel> BeforeHandleContext(FunctionCallFromLlm inst, RoleDialogModel message, List<RoleDialogModel> dialogs)
|
||||
=> dialogs;
|
||||
bool AfterHandleContext(List<RoleDialogModel> dialogs, List<RoleDialogModel> taskAgentDialogs)
|
||||
=> true;
|
||||
int MaxLoopCount => 5;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,9 +33,13 @@ public interface IBotSharpRepository : IHaveServiceProvider
|
|||
List<User> GetUserByIds(List<string> ids) => throw new NotImplementedException();
|
||||
List<User> GetUsersByAffiliateId(string affiliateId) => throw new NotImplementedException();
|
||||
User? GetUserByUserName(string userName) => throw new NotImplementedException();
|
||||
Dashboard? GetDashboard(string id = null) => throw new NotImplementedException();
|
||||
void CreateUser(User user) => throw new NotImplementedException();
|
||||
void UpdateExistUser(string userId, User user) => throw new NotImplementedException();
|
||||
void UpdateUserVerified(string userId) => throw new NotImplementedException();
|
||||
void AddDashboardConversation(string userId, string conversationId) => throw new NotImplementedException();
|
||||
void RemoveDashboardConversation(string userId, string conversationId) => throw new NotImplementedException();
|
||||
void UpdateDashboardConversation(string userId, DashboardConversation dashConv) => throw new NotImplementedException();
|
||||
void UpdateUserVerificationCode(string userId, string verficationCode) => throw new NotImplementedException();
|
||||
void UpdateUserPassword(string userId, string password) => throw new NotImplementedException();
|
||||
void UpdateUserEmail(string userId, string email) => throw new NotImplementedException();
|
||||
|
|
|
|||
|
|
@ -12,6 +12,11 @@ public class RuleType
|
|||
/// </summary>
|
||||
public const string DataValidation = "data-validation";
|
||||
|
||||
/// <summary>
|
||||
/// The reasoning approach name for next step
|
||||
/// </summary>
|
||||
public const string Reasoner = "reasoner";
|
||||
|
||||
/// <summary>
|
||||
/// The planning approach name for next step
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
using BotSharp.Abstraction.Functions.Models;
|
||||
|
||||
namespace BotSharp.Abstraction.Routing.Planning;
|
||||
|
||||
/// <summary>
|
||||
/// Task breakdown and execution plan
|
||||
/// https://www.promptingguide.ai/techniques/cot
|
||||
/// </summary>
|
||||
public interface IRoutingPlaner
|
||||
{
|
||||
Task<FunctionCallFromLlm> GetNextInstruction(Agent router, string messageId, List<RoleDialogModel> dialogs);
|
||||
Task<bool> AgentExecuting(Agent router, FunctionCallFromLlm inst, RoleDialogModel message, List<RoleDialogModel> dialogs);
|
||||
Task<bool> AgentExecuted(Agent router, FunctionCallFromLlm inst, RoleDialogModel message, List<RoleDialogModel> dialogs);
|
||||
List<RoleDialogModel> BeforeHandleContext(FunctionCallFromLlm inst, RoleDialogModel message, List<RoleDialogModel> dialogs)
|
||||
=> dialogs;
|
||||
bool AfterHandleContext(List<RoleDialogModel> dialogs, List<RoleDialogModel> taskAgentDialogs)
|
||||
=> true;
|
||||
int MaxLoopCount => 5;
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
using BotSharp.Abstraction.Functions.Models;
|
||||
|
||||
namespace BotSharp.Abstraction.Routing.Reasoning;
|
||||
|
||||
/// <summary>
|
||||
/// Reasoning approaches for large language models (LLMs) help enhance their ability to solve complex problems,
|
||||
/// handle tasks requiring logic, and provide accurate and contextually appropriate responses.
|
||||
/// </summary>
|
||||
public interface IRoutingReasoner
|
||||
{
|
||||
string Name => "Unnamed Reasoner";
|
||||
string Description => "Each of these approaches leverages the capabilities of LLMs to reason more effectively, " +
|
||||
"ensuring better performance and more coherent outputs across various types of complex tasks.";
|
||||
|
||||
int MaxLoopCount => 5;
|
||||
|
||||
Task<FunctionCallFromLlm> GetNextInstruction(Agent router, string messageId, List<RoleDialogModel> dialogs);
|
||||
|
||||
Task<bool> AgentExecuting(Agent router, FunctionCallFromLlm inst, RoleDialogModel message, List<RoleDialogModel> dialogs)
|
||||
=> Task.FromResult(true);
|
||||
|
||||
Task<bool> AgentExecuted(Agent router, FunctionCallFromLlm inst, RoleDialogModel message, List<RoleDialogModel> dialogs)
|
||||
=> Task.FromResult(true);
|
||||
|
||||
List<RoleDialogModel> BeforeHandleContext(FunctionCallFromLlm inst, RoleDialogModel message, List<RoleDialogModel> dialogs)
|
||||
=> dialogs;
|
||||
|
||||
bool AfterHandleContext(List<RoleDialogModel> dialogs, List<RoleDialogModel> taskAgentDialogs)
|
||||
=> true;
|
||||
}
|
||||
|
|
@ -3,4 +3,5 @@ namespace BotSharp.Abstraction.Templating;
|
|||
public interface ITemplateRender
|
||||
{
|
||||
string Render(string template, Dictionary<string, object> dict);
|
||||
void Register(Type type);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
namespace BotSharp.Abstraction.Users.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// User permission
|
||||
/// </summary>
|
||||
public static class UserPermission
|
||||
{
|
||||
public const string CreateAgent = "create-agent";
|
||||
|
|
|
|||
|
|
@ -29,4 +29,8 @@ public interface IUserService
|
|||
Task<bool> UpdatePassword(string newPassword, string verificationCode);
|
||||
Task<DateTime> GetUserTokenExpires();
|
||||
Task<bool> UpdateUsersIsDisable(List<string> userIds, bool isDisable);
|
||||
Task<bool> AddDashboardConversation(string userId, string conversationId);
|
||||
Task<bool> RemoveDashboardConversation(string userId, string conversationId);
|
||||
Task UpdateDashboardConversation(string userId, DashboardConversation dashConv);
|
||||
Task<Dashboard?> GetDashboard(string userId);
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
namespace BotSharp.Abstraction.Users.Models;
|
||||
|
||||
public class Dashboard
|
||||
{
|
||||
public IList<DashboardConversation> ConversationList { get; set; } = [];
|
||||
}
|
||||
|
||||
public class DashboardComponent
|
||||
{
|
||||
public required string Id { get; set; }
|
||||
public string? Name { get; set; }
|
||||
}
|
||||
|
||||
public class DashboardConversation : DashboardComponent
|
||||
{
|
||||
public string? ConversationId { get; set; }
|
||||
public string? Instruction { get; set; } = "";
|
||||
}
|
||||
|
||||
|
|
@ -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 ?? [];
|
||||
}
|
||||
}
|
||||
|
|
@ -12,7 +12,6 @@ global using BotSharp.Abstraction.Agents.Enums;
|
|||
global using BotSharp.Abstraction.Infrastructures.Enums;
|
||||
global using BotSharp.Abstraction.Models;
|
||||
global using BotSharp.Abstraction.Routing.Models;
|
||||
global using BotSharp.Abstraction.Routing.Planning;
|
||||
global using BotSharp.Abstraction.Templating;
|
||||
global using BotSharp.Abstraction.Translation.Attributes;
|
||||
global using BotSharp.Abstraction.Messaging.Enums;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BotSharp.Abstraction\BotSharp.Abstraction.csproj" />
|
||||
<ProjectReference Include="..\BotSharp.Core\BotSharp.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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");
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ public partial class AgentService
|
|||
hook.OnSamplesLoaded(agent.Samples);
|
||||
}
|
||||
|
||||
hook.OnAgentUtilityLoaded(agent);
|
||||
hook.OnAgentLoaded(agent);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,6 +59,11 @@
|
|||
|
||||
<ItemGroup>
|
||||
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\database_knowledge.liquid" />
|
||||
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\reasoner.hf.liquid" />
|
||||
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\reasoner.naive.liquid" />
|
||||
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\reasoner.one-step-forward.liquid" />
|
||||
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\reasoner.sequential.get_remaining_task.liquid" />
|
||||
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\reasoner.sequential.liquid" />
|
||||
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\agent.json" />
|
||||
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\instructions\instruction.liquid" />
|
||||
<None Remove="data\agents\01dcc3e5-0af7-49e6-ad7a-a760bd12dc4b\agent.json" />
|
||||
|
|
@ -73,10 +78,6 @@
|
|||
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\instructions\instruction.liquid" />
|
||||
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\.welcome.liquid" />
|
||||
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\conversation.summary.liquid" />
|
||||
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\planner_prompt.hf.liquid" />
|
||||
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\planner_prompt.naive.liquid" />
|
||||
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\planner_prompt.sequential.get_remaining_task.liquid" />
|
||||
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\planner_prompt.sequential.liquid" />
|
||||
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\response_with_function.liquid" />
|
||||
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\translation_prompt.liquid" />
|
||||
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\select_file_prompt.liquid" />
|
||||
|
|
@ -120,16 +121,19 @@
|
|||
<Content Include="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\database_knowledge.liquid">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\planner_prompt.sequential.get_remaining_task.liquid">
|
||||
<Content Include="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\reasoner.sequential.get_remaining_task.liquid">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\planner_prompt.sequential.liquid">
|
||||
<Content Include="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\reasoner.sequential.liquid">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\planner_prompt.hf.liquid">
|
||||
<Content Include="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\reasoner.hf.liquid">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\planner_prompt.naive.liquid">
|
||||
<Content Include="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\reasoner.naive.liquid">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\reasoner.one-step-forward.liquid">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\response_with_function.liquid">
|
||||
|
|
|
|||
|
|
@ -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>();
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
using BotSharp.Abstraction.Google.Settings;
|
||||
using BotSharp.Abstraction.Instructs;
|
||||
using BotSharp.Abstraction.Messaging;
|
||||
using BotSharp.Abstraction.Planning;
|
||||
using BotSharp.Abstraction.Plugins.Models;
|
||||
using BotSharp.Abstraction.Routing.Planning;
|
||||
using BotSharp.Abstraction.Settings;
|
||||
using BotSharp.Abstraction.Templating;
|
||||
using BotSharp.Core.Instructs;
|
||||
using BotSharp.Core.Messaging;
|
||||
using BotSharp.Core.Routing.Planning;
|
||||
using BotSharp.Core.Routing.Reasoning;
|
||||
using BotSharp.Core.Templating;
|
||||
using BotSharp.Core.Translation;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
|
@ -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>();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -53,6 +53,11 @@ public partial class FileRepository
|
|||
return Users.FirstOrDefault(x => x.UserName == userName.ToLower());
|
||||
}
|
||||
|
||||
public Dashboard? GetDashboard(string id = null)
|
||||
{
|
||||
return Dashboards.FirstOrDefault();
|
||||
}
|
||||
|
||||
public void CreateUser(User user)
|
||||
{
|
||||
var userId = Guid.NewGuid().ToString();
|
||||
|
|
@ -203,4 +208,68 @@ public partial class FileRepository
|
|||
_users = [];
|
||||
return true;
|
||||
}
|
||||
|
||||
public void AddDashboardConversation(string userId, string conversationId)
|
||||
{
|
||||
var user = GetUserById(userId);
|
||||
if (user == null) return;
|
||||
|
||||
// one user only has one dashboard currently
|
||||
var dash = Dashboards.FirstOrDefault();
|
||||
dash ??= new();
|
||||
var existingConv = dash.ConversationList.FirstOrDefault(x => string.Equals(x.ConversationId, conversationId, StringComparison.OrdinalIgnoreCase));
|
||||
if (existingConv != null) return;
|
||||
|
||||
var dashconv = new DashboardConversation
|
||||
{
|
||||
Id = Guid.NewGuid().ToString(),
|
||||
ConversationId = conversationId
|
||||
};
|
||||
|
||||
dash.ConversationList.Add(dashconv);
|
||||
|
||||
var dir = Path.Combine(_dbSettings.FileRepository, USERS_FOLDER, userId);
|
||||
var path = Path.Combine(dir, DASHBOARD_FILE);
|
||||
File.WriteAllText(path, JsonSerializer.Serialize(dash, _options));
|
||||
}
|
||||
|
||||
public void RemoveDashboardConversation(string userId, string conversationId)
|
||||
{
|
||||
var user = GetUserById(userId);
|
||||
if (user == null) return;
|
||||
|
||||
// one user only has one dashboard currently
|
||||
var dash = Dashboards.FirstOrDefault();
|
||||
if (dash == null) return;
|
||||
|
||||
var dashconv = dash.ConversationList.FirstOrDefault(
|
||||
c => string.Equals(c.ConversationId, conversationId, StringComparison.OrdinalIgnoreCase));
|
||||
if (dashconv == null) return;
|
||||
|
||||
dash.ConversationList.Remove(dashconv);
|
||||
|
||||
var dir = Path.Combine(_dbSettings.FileRepository, USERS_FOLDER, userId);
|
||||
var path = Path.Combine(dir, DASHBOARD_FILE);
|
||||
File.WriteAllText(path, JsonSerializer.Serialize(dash, _options));
|
||||
}
|
||||
|
||||
public void UpdateDashboardConversation(string userId, DashboardConversation dashConv)
|
||||
{
|
||||
var user = GetUserById(userId);
|
||||
if (user == null) return;
|
||||
|
||||
// one user only has one dashboard currently
|
||||
var dash = Dashboards.FirstOrDefault();
|
||||
if (dash == null) return;
|
||||
|
||||
var curIdx = dash.ConversationList.ToList().FindIndex(
|
||||
x => string.Equals(x.ConversationId, dashConv.ConversationId, StringComparison.OrdinalIgnoreCase));
|
||||
if (curIdx < 0) return;
|
||||
|
||||
dash.ConversationList[curIdx] = dashConv;
|
||||
|
||||
var dir = Path.Combine(_dbSettings.FileRepository, USERS_FOLDER, userId);
|
||||
var path = Path.Combine(dir, DASHBOARD_FILE);
|
||||
File.WriteAllText(path, JsonSerializer.Serialize(dash, _options));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ public partial class FileRepository : IBotSharpRepository
|
|||
private const string AGENT_FILE = "agent.json";
|
||||
private const string AGENT_INSTRUCTION_FILE = "instruction";
|
||||
private const string AGENT_SAMPLES_FILE = "samples.txt";
|
||||
private const string DASHBOARD_FILE = "dashboard.json";
|
||||
private const string AGENT_INSTRUCTIONS_FOLDER = "instructions";
|
||||
private const string AGENT_FUNCTIONS_FOLDER = "functions";
|
||||
private const string AGENT_TEMPLATES_FOLDER = "templates";
|
||||
|
|
@ -83,6 +84,7 @@ public partial class FileRepository : IBotSharpRepository
|
|||
|
||||
private List<Role> _roles = new List<Role>();
|
||||
private List<User> _users = new List<User>();
|
||||
private List<Dashboard> _dashboards = [];
|
||||
private List<Agent> _agents = new List<Agent>();
|
||||
private List<RoleAgent> _roleAgents = new List<RoleAgent>();
|
||||
private List<UserAgent> _userAgents = new List<UserAgent>();
|
||||
|
|
@ -170,6 +172,36 @@ public partial class FileRepository : IBotSharpRepository
|
|||
}
|
||||
}
|
||||
|
||||
private IQueryable<Dashboard> Dashboards
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_dashboards.IsNullOrEmpty())
|
||||
{
|
||||
return _dashboards.AsQueryable();
|
||||
}
|
||||
|
||||
var dir = Path.Combine(_dbSettings.FileRepository, USERS_FOLDER);
|
||||
_dashboards = [];
|
||||
if (Directory.Exists(dir))
|
||||
{
|
||||
foreach (var d in Directory.GetDirectories(dir))
|
||||
{
|
||||
var dashboardFile = Path.Combine(d, DASHBOARD_FILE);
|
||||
if (!Directory.Exists(d) || !File.Exists(dashboardFile))
|
||||
continue;
|
||||
|
||||
var json = File.ReadAllText(dashboardFile);
|
||||
var dash = JsonSerializer.Deserialize<Dashboard>(json, _options);
|
||||
|
||||
if (dash == null) continue;
|
||||
_dashboards.Add(dash);
|
||||
}
|
||||
}
|
||||
return _dashboards.AsQueryable();
|
||||
}
|
||||
}
|
||||
|
||||
private IQueryable<Agent> Agents
|
||||
{
|
||||
get
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ using BotSharp.Abstraction.Repositories;
|
|||
using BotSharp.Abstraction.Repositories.Filters;
|
||||
using BotSharp.Abstraction.Routing;
|
||||
using BotSharp.Abstraction.Routing.Settings;
|
||||
using BotSharp.Core.Routing.Planning;
|
||||
using BotSharp.Core.Routing.Reasoning;
|
||||
|
||||
namespace BotSharp.Core.Routing.Handlers;
|
||||
|
||||
|
|
@ -27,7 +27,7 @@ public class ContinueExecuteTaskRoutingHandler : RoutingHandlerBase//, IRoutingH
|
|||
|
||||
public List<string> Planers => new List<string>
|
||||
{
|
||||
nameof(HFPlanner)
|
||||
nameof(HFReasoner)
|
||||
};
|
||||
|
||||
public ContinueExecuteTaskRoutingHandler(IServiceProvider services, ILogger<ContinueExecuteTaskRoutingHandler> logger, RoutingSettings settings)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Abstraction.Routing;
|
||||
using BotSharp.Abstraction.Routing.Settings;
|
||||
using BotSharp.Core.Routing.Planning;
|
||||
using BotSharp.Core.Routing.Reasoning;
|
||||
|
||||
namespace BotSharp.Core.Routing.Handlers;
|
||||
|
||||
|
|
@ -19,7 +19,7 @@ public class InterruptTaskExecutionRoutingHandler : RoutingHandlerBase//, IRouti
|
|||
|
||||
public List<string> Planers => new List<string>
|
||||
{
|
||||
nameof(HFPlanner)
|
||||
nameof(HFReasoner)
|
||||
};
|
||||
|
||||
public InterruptTaskExecutionRoutingHandler(IServiceProvider services, ILogger<InterruptTaskExecutionRoutingHandler> logger, RoutingSettings settings)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
using BotSharp.Abstraction.Routing.Settings;
|
||||
using BotSharp.Core.Routing.Planning;
|
||||
using BotSharp.Core.Routing.Reasoning;
|
||||
|
||||
namespace BotSharp.Core.Routing.Handlers;
|
||||
|
||||
|
|
@ -26,7 +26,7 @@ public class RetrieveDataFromAgentRoutingHandler : RoutingHandlerBase//, IRoutin
|
|||
|
||||
public List<string> Planers => new List<string>
|
||||
{
|
||||
nameof(HFPlanner)
|
||||
nameof(HFReasoner)
|
||||
};
|
||||
|
||||
public RetrieveDataFromAgentRoutingHandler(IServiceProvider services, ILogger<RetrieveDataFromAgentRoutingHandler> logger, RoutingSettings settings)
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
public class FirstStagePlanParameter
|
||||
{
|
||||
[JsonPropertyName("input_args")]
|
||||
public JsonDocument[] Parameters { get; set; } = new JsonDocument[0];
|
||||
|
||||
[JsonPropertyName("output_results")]
|
||||
public string[] Results { get; set; } = new string[0];
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"INPUTS:\r\n{JsonSerializer.Serialize(Parameters)}\r\n\r\nOUTPUTS:\r\n{JsonSerializer.Serialize(Results)}";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace BotSharp.Core.Routing.Planning;
|
||||
|
||||
public class SecondStagePlan
|
||||
{
|
||||
[JsonPropertyName("related_tables")]
|
||||
public string[] Tables { get; set; } = new string[0];
|
||||
|
||||
[JsonPropertyName("description")]
|
||||
public string Description { get; set; } = "";
|
||||
|
||||
[JsonPropertyName("tool_name")]
|
||||
public string Tool { get; set; } = "";
|
||||
|
||||
[JsonPropertyName("input_args")]
|
||||
public JsonDocument[] Parameters { get; set; } = new JsonDocument[0];
|
||||
|
||||
[JsonPropertyName("output_results")]
|
||||
public string[] Results { get; set; } = new string[0];
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
public class SecondStagePlanParameter : FirstStagePlanParameter
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -1,17 +1,33 @@
|
|||
using BotSharp.Abstraction.Routing.Planning;
|
||||
/*****************************************************************************
|
||||
Copyright 2024 Written by Haiping Chen. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
******************************************************************************/
|
||||
|
||||
using BotSharp.Abstraction.Routing.Reasoning;
|
||||
using BotSharp.Abstraction.Templating;
|
||||
|
||||
namespace BotSharp.Core.Routing.Planning;
|
||||
namespace BotSharp.Core.Routing.Reasoning;
|
||||
|
||||
/// <summary>
|
||||
/// Human feedback based planner
|
||||
/// Human feedback based reasoner
|
||||
/// </summary>
|
||||
public class HFPlanner : IRoutingPlaner
|
||||
public class HFReasoner : IRoutingReasoner
|
||||
{
|
||||
private readonly IServiceProvider _services;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public HFPlanner(IServiceProvider services, ILogger<HFPlanner> logger)
|
||||
public HFReasoner(IServiceProvider services, ILogger<HFReasoner> logger)
|
||||
{
|
||||
_services = services;
|
||||
_logger = logger;
|
||||
|
|
@ -37,7 +53,7 @@ public class HFPlanner : IRoutingPlaner
|
|||
{
|
||||
new RoleDialogModel(AgentRole.User, next)
|
||||
{
|
||||
FunctionName = nameof(HFPlanner),
|
||||
FunctionName = nameof(HFReasoner),
|
||||
MessageId = messageId
|
||||
}
|
||||
};
|
||||
|
|
@ -60,7 +76,7 @@ public class HFPlanner : IRoutingPlaner
|
|||
}
|
||||
|
||||
// Fix LLM malformed response
|
||||
PlannerHelper.FixMalformedResponse(_services, inst);
|
||||
ReasonerHelper.FixMalformedResponse(_services, inst);
|
||||
|
||||
return inst;
|
||||
}
|
||||
|
|
@ -87,13 +103,13 @@ public class HFPlanner : IRoutingPlaner
|
|||
public async Task<bool> AgentExecuted(Agent router, FunctionCallFromLlm inst, RoleDialogModel message, List<RoleDialogModel> dialogs)
|
||||
{
|
||||
var context = _services.GetRequiredService<IRoutingContext>();
|
||||
context.Empty(reason: $"Agent queue is cleared by {nameof(HFPlanner)}");
|
||||
context.Empty(reason: $"Agent queue is cleared by {nameof(HFReasoner)}");
|
||||
return true;
|
||||
}
|
||||
|
||||
private string GetNextStepPrompt(Agent router)
|
||||
{
|
||||
var template = router.Templates.First(x => x.Name == "planner_prompt.hf").Content;
|
||||
var template = router.Templates.First(x => x.Name == "reasoner.hf").Content;
|
||||
var render = _services.GetRequiredService<ITemplateRender>();
|
||||
// update states
|
||||
var conv = _services.GetRequiredService<IConversationService>();
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
using BotSharp.Abstraction.Routing.Planning;
|
||||
using BotSharp.Abstraction.Planning;
|
||||
|
||||
namespace BotSharp.Core.Routing.Planning;
|
||||
namespace BotSharp.Core.Routing.Reasoning;
|
||||
|
||||
public class InstructExecutor : IExecutor
|
||||
{
|
||||
|
|
@ -1,16 +1,35 @@
|
|||
/*****************************************************************************
|
||||
Copyright 2024 Written by Haiping Chen. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
******************************************************************************/
|
||||
|
||||
using BotSharp.Abstraction.Infrastructures.Enums;
|
||||
using BotSharp.Abstraction.Routing.Models;
|
||||
using BotSharp.Abstraction.Routing.Planning;
|
||||
using BotSharp.Abstraction.Routing.Reasoning;
|
||||
using BotSharp.Abstraction.Templating;
|
||||
|
||||
namespace BotSharp.Core.Routing.Planning;
|
||||
namespace BotSharp.Core.Routing.Reasoning;
|
||||
|
||||
public class NaivePlanner : IRoutingPlaner
|
||||
/// <summary>
|
||||
/// simple or unsophisticated methods used to decide which specialized model or module in a system to engage for a given task.
|
||||
/// </summary>
|
||||
public class NaiveReasoner : IRoutingReasoner
|
||||
{
|
||||
private readonly IServiceProvider _services;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public NaivePlanner(IServiceProvider services, ILogger<NaivePlanner> logger)
|
||||
public NaiveReasoner(IServiceProvider services, ILogger<NaiveReasoner> logger)
|
||||
{
|
||||
_services = services;
|
||||
_logger = logger;
|
||||
|
|
@ -46,7 +65,7 @@ public class NaivePlanner : IRoutingPlaner
|
|||
{
|
||||
new RoleDialogModel(AgentRole.User, next)
|
||||
{
|
||||
FunctionName = nameof(NaivePlanner),
|
||||
FunctionName = nameof(NaiveReasoner),
|
||||
MessageId = messageId
|
||||
}
|
||||
};
|
||||
|
|
@ -69,7 +88,7 @@ public class NaivePlanner : IRoutingPlaner
|
|||
}
|
||||
|
||||
// Fix LLM malformed response
|
||||
PlannerHelper.FixMalformedResponse(_services, inst);
|
||||
ReasonerHelper.FixMalformedResponse(_services, inst);
|
||||
|
||||
return inst;
|
||||
}
|
||||
|
|
@ -99,7 +118,7 @@ public class NaivePlanner : IRoutingPlaner
|
|||
}
|
||||
else
|
||||
{
|
||||
context.Empty(reason: $"Agent queue is cleared by {nameof(NaivePlanner)}");
|
||||
context.Empty(reason: $"Agent queue is cleared by {nameof(NaiveReasoner)}");
|
||||
// context.Push(inst.OriginalAgent, "Push user goal agent");
|
||||
}
|
||||
return true;
|
||||
|
|
@ -107,7 +126,7 @@ public class NaivePlanner : IRoutingPlaner
|
|||
|
||||
private string GetNextStepPrompt(Agent router)
|
||||
{
|
||||
var template = router.Templates.First(x => x.Name == "planner_prompt.naive").Content;
|
||||
var template = router.Templates.First(x => x.Name == "reasoner.naive").Content;
|
||||
|
||||
var states = _services.GetRequiredService<IConversationStateService>();
|
||||
var render = _services.GetRequiredService<ITemplateRender>();
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
/*****************************************************************************
|
||||
Copyright 2024 Written by Haiping Chen. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
******************************************************************************/
|
||||
|
||||
using BotSharp.Abstraction.Infrastructures.Enums;
|
||||
using BotSharp.Abstraction.Routing.Models;
|
||||
using BotSharp.Abstraction.Routing.Reasoning;
|
||||
using BotSharp.Abstraction.Templating;
|
||||
|
||||
namespace BotSharp.Core.Routing.Reasoning;
|
||||
|
||||
/// <summary>
|
||||
/// One-step forward reasoning is a straightforward reasoning approach where the model or agent evaluates its current state
|
||||
/// and takes the next best logical step toward the solution without extensive lookahead or planning.
|
||||
/// This type of reasoning involves making a decision based on the current situation and immediate context
|
||||
/// rather than considering multiple future steps or possibilities.
|
||||
/// </summary>
|
||||
public class OneStepForwardReasoner : IRoutingReasoner
|
||||
{
|
||||
public string Name => "one-step-forward";
|
||||
|
||||
private readonly IServiceProvider _services;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public OneStepForwardReasoner(IServiceProvider services, ILogger<NaiveReasoner> logger)
|
||||
{
|
||||
_services = services;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<FunctionCallFromLlm> GetNextInstruction(Agent router, string messageId, List<RoleDialogModel> dialogs)
|
||||
{
|
||||
var next = GetNextStepPrompt(router);
|
||||
|
||||
var inst = new FunctionCallFromLlm();
|
||||
|
||||
// chat completion
|
||||
var completion = CompletionProvider.GetChatCompletion(_services,
|
||||
provider: router?.LlmConfig?.Provider,
|
||||
model: router?.LlmConfig?.Model);
|
||||
|
||||
int retryCount = 0;
|
||||
while (retryCount < 3)
|
||||
{
|
||||
string text = string.Empty;
|
||||
try
|
||||
{
|
||||
// text completion
|
||||
// text = await completion.GetCompletion(content, router.Id, messageId);
|
||||
dialogs = new List<RoleDialogModel>
|
||||
{
|
||||
new RoleDialogModel(AgentRole.User, next)
|
||||
{
|
||||
FunctionName = Name,
|
||||
MessageId = messageId
|
||||
}
|
||||
};
|
||||
var response = await completion.GetChatCompletions(router, dialogs);
|
||||
|
||||
inst = response.Content.JsonContent<FunctionCallFromLlm>();
|
||||
break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError($"{ex.Message}: {text}");
|
||||
inst.Function = "response_to_user";
|
||||
inst.Response = ex.Message;
|
||||
inst.AgentName = "Router";
|
||||
}
|
||||
finally
|
||||
{
|
||||
retryCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// Fix LLM malformed response
|
||||
ReasonerHelper.FixMalformedResponse(_services, inst);
|
||||
|
||||
return inst;
|
||||
}
|
||||
|
||||
public async Task<bool> AgentExecuting(Agent router, FunctionCallFromLlm inst, RoleDialogModel message, List<RoleDialogModel> dialogs)
|
||||
{
|
||||
// Set user content as Planner's question
|
||||
message.FunctionName = inst.Function;
|
||||
message.FunctionArgs = inst.Arguments == null ? "{}" : JsonSerializer.Serialize(inst.Arguments);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<bool> AgentExecuted(Agent router, FunctionCallFromLlm inst, RoleDialogModel message, List<RoleDialogModel> dialogs)
|
||||
{
|
||||
var context = _services.GetRequiredService<IRoutingContext>();
|
||||
if (inst.UnmatchedAgent)
|
||||
{
|
||||
var unmatchedAgentId = context.GetCurrentAgentId();
|
||||
|
||||
// Exclude the wrong routed agent
|
||||
var agents = router.TemplateDict["routing_agents"] as RoutableAgent[];
|
||||
router.TemplateDict["routing_agents"] = agents.Where(x => x.AgentId != unmatchedAgentId).ToArray();
|
||||
|
||||
// Handover to Router;
|
||||
context.Pop();
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Empty(reason: $"Agent queue is cleared by {nameof(NaiveReasoner)}");
|
||||
// context.Push(inst.OriginalAgent, "Push user goal agent");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private string GetNextStepPrompt(Agent router)
|
||||
{
|
||||
var template = router.Templates.First(x => x.Name == "reasoner.one-step-forward").Content;
|
||||
|
||||
var states = _services.GetRequiredService<IConversationStateService>();
|
||||
var render = _services.GetRequiredService<ITemplateRender>();
|
||||
return render.Render(template, new Dictionary<string, object>
|
||||
{
|
||||
{ StateConst.EXPECTED_ACTION_AGENT, states.GetState(StateConst.EXPECTED_ACTION_AGENT) },
|
||||
{ StateConst.EXPECTED_GOAL_AGENT, states.GetState(StateConst.EXPECTED_GOAL_AGENT) }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
namespace BotSharp.Core.Routing.Planning;
|
||||
namespace BotSharp.Core.Routing.Reasoning;
|
||||
|
||||
public static class PlannerHelper
|
||||
public static class ReasonerHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Sometimes LLM hallucinates and fails to set function names correctly.
|
||||
|
|
@ -1,11 +1,30 @@
|
|||
/*****************************************************************************
|
||||
Copyright 2024 Written by Haiping Chen. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
******************************************************************************/
|
||||
|
||||
using BotSharp.Abstraction.MLTasks;
|
||||
using BotSharp.Abstraction.Routing.Models;
|
||||
using BotSharp.Abstraction.Routing.Planning;
|
||||
using BotSharp.Abstraction.Routing.Reasoning;
|
||||
using BotSharp.Abstraction.Templating;
|
||||
|
||||
namespace BotSharp.Core.Routing.Planning;
|
||||
namespace BotSharp.Core.Routing.Reasoning;
|
||||
|
||||
public class SequentialPlanner : IRoutingPlaner
|
||||
/// <summary>
|
||||
/// Sequential tasks focused reasoning approach
|
||||
/// </summary>
|
||||
public class SequentialReasoner : IRoutingReasoner
|
||||
{
|
||||
private readonly IServiceProvider _services;
|
||||
private readonly ILogger _logger;
|
||||
|
|
@ -14,7 +33,7 @@ public class SequentialPlanner : IRoutingPlaner
|
|||
public int MaxLoopCount => 100;
|
||||
private FunctionCallFromLlm _lastInst;
|
||||
|
||||
public SequentialPlanner(IServiceProvider services, ILogger<NaivePlanner> logger)
|
||||
public SequentialReasoner(IServiceProvider services, ILogger<NaiveReasoner> logger)
|
||||
{
|
||||
_services = services;
|
||||
_logger = logger;
|
||||
|
|
@ -72,7 +91,7 @@ public class SequentialPlanner : IRoutingPlaner
|
|||
{
|
||||
new RoleDialogModel(AgentRole.User, next)
|
||||
{
|
||||
FunctionName = nameof(SequentialPlanner),
|
||||
FunctionName = nameof(SequentialReasoner),
|
||||
MessageId = messageId
|
||||
}
|
||||
};
|
||||
|
|
@ -139,7 +158,7 @@ public class SequentialPlanner : IRoutingPlaner
|
|||
|
||||
if (message.StopCompletion)
|
||||
{
|
||||
context.Empty(reason: $"Agent queue is cleared by {nameof(SequentialPlanner)}");
|
||||
context.Empty(reason: $"Agent queue is cleared by {nameof(SequentialReasoner)}");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -154,7 +173,7 @@ public class SequentialPlanner : IRoutingPlaner
|
|||
|
||||
private string GetNextStepPrompt(Agent router)
|
||||
{
|
||||
var template = router.Templates.First(x => x.Name == "planner_prompt.sequential").Content;
|
||||
var template = router.Templates.First(x => x.Name == "reasoner.sequential").Content;
|
||||
|
||||
var render = _services.GetRequiredService<ITemplateRender>();
|
||||
return render.Render(template, new Dictionary<string, object>
|
||||
|
|
@ -169,11 +188,11 @@ public class SequentialPlanner : IRoutingPlaner
|
|||
var inst = new DecomposedStep();
|
||||
|
||||
var llmProviderService = _services.GetRequiredService<ILlmProviderService>();
|
||||
var model = llmProviderService.GetProviderModel("azure-openai", "gpt-4");
|
||||
var model = llmProviderService.GetProviderModel("openai", "gpt-4o");
|
||||
|
||||
// chat completion
|
||||
var completion = CompletionProvider.GetChatCompletion(_services,
|
||||
provider: "azure-openai",
|
||||
provider: "openai",
|
||||
model: model.Name);
|
||||
|
||||
int retryCount = 0;
|
||||
|
|
@ -185,7 +204,7 @@ public class SequentialPlanner : IRoutingPlaner
|
|||
var response = await completion.GetChatCompletions(new Agent
|
||||
{
|
||||
Id = router.Id,
|
||||
Name = nameof(SequentialPlanner),
|
||||
Name = nameof(SequentialReasoner),
|
||||
Instruction = systemPrompt
|
||||
}, dialogs);
|
||||
|
||||
|
|
@ -208,16 +227,11 @@ public class SequentialPlanner : IRoutingPlaner
|
|||
|
||||
private string GetDecomposeTaskPrompt(Agent router)
|
||||
{
|
||||
var template = router.Templates.First(x => x.Name == "planner_prompt.sequential.get_remaining_task").Content;
|
||||
var template = router.Templates.First(x => x.Name == "reasoner.sequential.get_remaining_task").Content;
|
||||
|
||||
var render = _services.GetRequiredService<ITemplateRender>();
|
||||
return render.Render(template, new Dictionary<string, object>
|
||||
{
|
||||
});
|
||||
}
|
||||
|
||||
public Task<FunctionCallFromLlm> GetNextInstruction(Agent router, string messageId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
using BotSharp.Abstraction.Routing;
|
||||
using BotSharp.Abstraction.Routing.Models;
|
||||
using BotSharp.Abstraction.Routing.Planning;
|
||||
using BotSharp.Abstraction.Routing.Reasoning;
|
||||
using BotSharp.Abstraction.Routing.Settings;
|
||||
using BotSharp.Abstraction.Settings;
|
||||
using BotSharp.Core.Routing.Hooks;
|
||||
using BotSharp.Core.Routing.Planning;
|
||||
using BotSharp.Core.Routing.Reasoning;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace BotSharp.Core.Routing;
|
||||
|
|
@ -35,8 +33,10 @@ public class RoutingPlugin : IBotSharpPlugin
|
|||
services.AddScoped<IRoutingService, RoutingService>();
|
||||
services.AddScoped<IAgentHook, RoutingAgentHook>();
|
||||
|
||||
services.AddScoped<IRoutingPlaner, NaivePlanner>();
|
||||
services.AddScoped<IRoutingPlaner, HFPlanner>();
|
||||
services.AddScoped<IRoutingPlaner, SequentialPlanner>();
|
||||
services.AddScoped<IRoutingReasoner, NaiveReasoner>();
|
||||
services.AddScoped<IRoutingReasoner, HFReasoner>();
|
||||
services.AddScoped<IRoutingReasoner, SequentialReasoner>();
|
||||
|
||||
services.AddScoped<IRoutingReasoner, OneStepForwardReasoner>();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,24 +0,0 @@
|
|||
using BotSharp.Abstraction.Routing.Enums;
|
||||
using BotSharp.Abstraction.Routing.Planning;
|
||||
using BotSharp.Core.Routing.Planning;
|
||||
|
||||
namespace BotSharp.Core.Routing;
|
||||
|
||||
public partial class RoutingService
|
||||
{
|
||||
public IRoutingPlaner GetPlanner(Agent router)
|
||||
{
|
||||
var rule = router.RoutingRules.FirstOrDefault(x => x.Type == RuleType.Planner);
|
||||
|
||||
var planner = _services.GetServices<IRoutingPlaner>().
|
||||
FirstOrDefault(x => x.GetType().Name.EndsWith(rule.Field));
|
||||
|
||||
if (planner == null)
|
||||
{
|
||||
_logger.LogError($"Can't find specific planner named {rule.Field}");
|
||||
return _services.GetRequiredService<NaivePlanner>();
|
||||
}
|
||||
|
||||
return planner;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
using BotSharp.Abstraction.Conversations.Enums;
|
||||
using BotSharp.Abstraction.Routing.Models;
|
||||
using System.Drawing;
|
||||
|
||||
namespace BotSharp.Core.Routing;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,112 @@
|
|||
using BotSharp.Abstraction.Infrastructures.Enums;
|
||||
using BotSharp.Abstraction.Planning;
|
||||
using BotSharp.Abstraction.Routing.Enums;
|
||||
using BotSharp.Abstraction.Routing.Reasoning;
|
||||
using BotSharp.Core.Routing.Reasoning;
|
||||
|
||||
namespace BotSharp.Core.Routing;
|
||||
|
||||
public partial class RoutingService
|
||||
{
|
||||
public async Task<RoleDialogModel> InstructLoop(RoleDialogModel message, List<RoleDialogModel> dialogs)
|
||||
{
|
||||
RoleDialogModel response = default;
|
||||
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
var convService = _services.GetRequiredService<IConversationService>();
|
||||
var storage = _services.GetRequiredService<IConversationStorage>();
|
||||
|
||||
_router = await agentService.LoadAgent(message.CurrentAgentId);
|
||||
|
||||
var states = _services.GetRequiredService<IConversationStateService>();
|
||||
var executor = _services.GetRequiredService<IExecutor>();
|
||||
|
||||
var planner = GetReasoner(_router);
|
||||
|
||||
_context.Push(_router.Id);
|
||||
|
||||
// Handle multi-language for input
|
||||
var agentSettings = _services.GetRequiredService<AgentSettings>();
|
||||
if (agentSettings.EnableTranslator)
|
||||
{
|
||||
var translator = _services.GetRequiredService<ITranslationService>();
|
||||
|
||||
var language = states.GetState(StateConst.LANGUAGE, LanguageType.ENGLISH);
|
||||
if (language != LanguageType.ENGLISH)
|
||||
{
|
||||
message.SecondaryContent = message.Content;
|
||||
message.Content = await translator.Translate(_router, message.MessageId, message.Content,
|
||||
language: LanguageType.ENGLISH,
|
||||
clone: false);
|
||||
}
|
||||
}
|
||||
|
||||
dialogs.Add(message);
|
||||
storage.Append(convService.ConversationId, message);
|
||||
|
||||
// Get first instruction
|
||||
_router.TemplateDict["conversation"] = await GetConversationContent(dialogs);
|
||||
var inst = await planner.GetNextInstruction(_router, message.MessageId, dialogs);
|
||||
|
||||
int loopCount = 1;
|
||||
while (true)
|
||||
{
|
||||
await HookEmitter.Emit<IRoutingHook>(_services, async hook =>
|
||||
await hook.OnRoutingInstructionReceived(inst, message)
|
||||
);
|
||||
|
||||
// Save states
|
||||
states.SaveStateByArgs(inst.Arguments);
|
||||
|
||||
#if DEBUG
|
||||
Console.WriteLine($"*** Next Instruction *** {inst}");
|
||||
#else
|
||||
_logger.LogInformation($"*** Next Instruction *** {inst}");
|
||||
#endif
|
||||
await planner.AgentExecuting(_router, inst, message, dialogs);
|
||||
|
||||
// Handover to Task Agent
|
||||
if (inst.HandleDialogsByPlanner)
|
||||
{
|
||||
var dialogWithoutContext = planner.BeforeHandleContext(inst, message, dialogs);
|
||||
response = await executor.Execute(this, inst, message, dialogWithoutContext);
|
||||
planner.AfterHandleContext(dialogs, dialogWithoutContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
response = await executor.Execute(this, inst, message, dialogs);
|
||||
}
|
||||
|
||||
await planner.AgentExecuted(_router, inst, response, dialogs);
|
||||
|
||||
if (loopCount >= planner.MaxLoopCount || _context.IsEmpty)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Get next instruction from Planner
|
||||
_router.TemplateDict["conversation"] = await GetConversationContent(dialogs);
|
||||
inst = await planner.GetNextInstruction(_router, message.MessageId, dialogs);
|
||||
loopCount++;
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public IRoutingReasoner GetReasoner(Agent router)
|
||||
{
|
||||
var rule = router.RoutingRules.FirstOrDefault(x => x.Type == RuleType.Reasoner);
|
||||
|
||||
var reasoner = _services.GetServices<IRoutingReasoner>().
|
||||
FirstOrDefault(x => x.GetType().Name.EndsWith(rule.Field));
|
||||
|
||||
if (reasoner == null)
|
||||
{
|
||||
_logger.LogError($"Can't find specific planner named {rule.Field}");
|
||||
// Default use NaiveReasoner
|
||||
return _services.GetRequiredService<NaiveReasoner>();
|
||||
}
|
||||
|
||||
return reasoner;
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
using BotSharp.Abstraction.Infrastructures.Enums;
|
||||
using BotSharp.Abstraction.Routing.Models;
|
||||
using BotSharp.Abstraction.Routing.Planning;
|
||||
using BotSharp.Abstraction.Routing.Settings;
|
||||
|
||||
namespace BotSharp.Core.Routing;
|
||||
|
|
@ -16,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,
|
||||
|
|
@ -75,97 +58,12 @@ public partial class RoutingService : IRoutingService
|
|||
return response;
|
||||
}
|
||||
|
||||
public async Task<RoleDialogModel> InstructLoop(RoleDialogModel message, List<RoleDialogModel> dialogs)
|
||||
{
|
||||
RoleDialogModel response = default;
|
||||
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
var convService = _services.GetRequiredService<IConversationService>();
|
||||
var storage = _services.GetRequiredService<IConversationStorage>();
|
||||
|
||||
_router = await agentService.LoadAgent(message.CurrentAgentId);
|
||||
|
||||
var states = _services.GetRequiredService<IConversationStateService>();
|
||||
var executor = _services.GetRequiredService<IExecutor>();
|
||||
|
||||
var planner = GetPlanner(_router);
|
||||
|
||||
_context.Push(_router.Id);
|
||||
|
||||
// Handle multi-language for input
|
||||
var agentSettings = _services.GetRequiredService<AgentSettings>();
|
||||
if (agentSettings.EnableTranslator)
|
||||
{
|
||||
var translator = _services.GetRequiredService<ITranslationService>();
|
||||
|
||||
var language = states.GetState(StateConst.LANGUAGE, LanguageType.ENGLISH);
|
||||
if (language != LanguageType.ENGLISH)
|
||||
{
|
||||
message.SecondaryContent = message.Content;
|
||||
message.Content = await translator.Translate(_router, message.MessageId, message.Content,
|
||||
language: LanguageType.ENGLISH,
|
||||
clone: false);
|
||||
}
|
||||
}
|
||||
|
||||
dialogs.Add(message);
|
||||
storage.Append(convService.ConversationId, message);
|
||||
|
||||
// Get first instruction
|
||||
_router.TemplateDict["conversation"] = await GetConversationContent(dialogs);
|
||||
var inst = await planner.GetNextInstruction(_router, message.MessageId, dialogs);
|
||||
|
||||
int loopCount = 1;
|
||||
while (true)
|
||||
{
|
||||
await HookEmitter.Emit<IRoutingHook>(_services, async hook =>
|
||||
await hook.OnRoutingInstructionReceived(inst, message)
|
||||
);
|
||||
|
||||
// Save states
|
||||
states.SaveStateByArgs(inst.Arguments);
|
||||
|
||||
#if DEBUG
|
||||
Console.WriteLine($"*** Next Instruction *** {inst}");
|
||||
#else
|
||||
_logger.LogInformation($"*** Next Instruction *** {inst}");
|
||||
#endif
|
||||
await planner.AgentExecuting(_router, inst, message, dialogs);
|
||||
|
||||
// Handover to Task Agent
|
||||
if (inst.HandleDialogsByPlanner)
|
||||
{
|
||||
var dialogWithoutContext = planner.BeforeHandleContext(inst, message, dialogs);
|
||||
response = await executor.Execute(this, inst, message, dialogWithoutContext);
|
||||
planner.AfterHandleContext(dialogs, dialogWithoutContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
response = await executor.Execute(this, inst, message, dialogs);
|
||||
}
|
||||
|
||||
await planner.AgentExecuted(_router, inst, response, dialogs);
|
||||
|
||||
if (loopCount >= planner.MaxLoopCount || _context.IsEmpty)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Get next instruction from Planner
|
||||
_router.TemplateDict["conversation"] = await GetConversationContent(dialogs);
|
||||
inst = await planner.GetNextInstruction(_router, message.MessageId, dialogs);
|
||||
loopCount++;
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public List<RoutingHandlerDef> GetHandlers(Agent router)
|
||||
{
|
||||
var planer = GetPlanner(router);
|
||||
var reasoner = GetReasoner(router);
|
||||
|
||||
return _services.GetServices<IRoutingHandler>()
|
||||
.Where(x => x.Planers == null || x.Planers.Contains(planer.GetType().Name))
|
||||
.Where(x => x.Planers == null || x.Planers.Contains(reasoner.GetType().Name))
|
||||
.Where(x => !string.IsNullOrEmpty(x.Description))
|
||||
.Select((x, i) => new RoutingHandlerDef
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -736,4 +736,42 @@ public class UserService : IUserService
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<bool> AddDashboardConversation(string userId, string conversationId)
|
||||
{
|
||||
var db = _services.GetRequiredService<IBotSharpRepository>();
|
||||
db.AddDashboardConversation(userId, conversationId);
|
||||
|
||||
await Task.CompletedTask;
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<bool> RemoveDashboardConversation(string userId, string conversationId)
|
||||
{
|
||||
var db = _services.GetRequiredService<IBotSharpRepository>();
|
||||
db.RemoveDashboardConversation(userId, conversationId);
|
||||
|
||||
await Task.CompletedTask;
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task UpdateDashboardConversation(string userId, DashboardConversation newDashConv)
|
||||
{
|
||||
var db = _services.GetRequiredService<IBotSharpRepository>();
|
||||
var dashConv = db.GetDashboard(userId)?.ConversationList.FirstOrDefault(x => string.Equals(x.ConversationId, newDashConv.ConversationId));
|
||||
if (dashConv == null) return;
|
||||
dashConv.Name = newDashConv.Name ?? dashConv.Name;
|
||||
dashConv.Instruction = newDashConv.Instruction ?? dashConv.Instruction;
|
||||
db.UpdateDashboardConversation(userId, dashConv);
|
||||
await Task.CompletedTask;
|
||||
return;
|
||||
}
|
||||
|
||||
public async Task<Dashboard?> GetDashboard(string userId)
|
||||
{
|
||||
var db = _services.GetRequiredService<IBotSharpRepository>();
|
||||
var dash = db.GetDashboard();
|
||||
await Task.CompletedTask;
|
||||
return dash;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@
|
|||
"profiles": [ "tool" ],
|
||||
"routingRules": [
|
||||
{
|
||||
"type": "planner",
|
||||
"field": "HFPlanner"
|
||||
"type": "reasoner",
|
||||
"field": "HFReasoner"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
Analyze the user's problem. Which prerequisite task needs to be completed? Output the next step of routing instructions.
|
||||
Check the job responsibilities of the routable Agent and do not transfer to an Agent that exceeds the scope of responsibility.
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -511,6 +511,28 @@ public class ConversationController : ControllerBase
|
|||
}
|
||||
#endregion
|
||||
|
||||
#region miscellaneous
|
||||
[HttpPut("/agent/{agentId}/conversation/{conversationId}/dashboard")]
|
||||
public async Task<bool> PinConversationToDashboard([FromRoute] string agentId, [FromRoute] string conversationId)
|
||||
{
|
||||
var userService = _services.GetRequiredService<IUserService>();
|
||||
|
||||
var user = await userService.GetUser(_user.Id);
|
||||
var pinned = await userService.AddDashboardConversation(user.Id, conversationId);
|
||||
return pinned;
|
||||
}
|
||||
|
||||
[HttpDelete("/agent/{agentId}/conversation/{conversationId}/dashboard")]
|
||||
public async Task<bool> UnpinConversationFromDashboard([FromRoute] string agentId, [FromRoute] string conversationId)
|
||||
{
|
||||
var userService = _services.GetRequiredService<IUserService>();
|
||||
|
||||
var user = await userService.GetUser(_user.Id);
|
||||
var unpinned = await userService.RemoveDashboardConversation(user.Id, conversationId);
|
||||
return unpinned;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Private methods
|
||||
private void SetStates(IConversationService conv, NewMessageModel input)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,73 @@
|
|||
using BotSharp.Abstraction.Options;
|
||||
using BotSharp.Abstraction.Users.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BotSharp.OpenAPI.Controllers;
|
||||
|
||||
[Authorize]
|
||||
[ApiController]
|
||||
public class DashboardController : ControllerBase
|
||||
{
|
||||
private readonly IServiceProvider _services;
|
||||
private readonly IUserIdentity _user;
|
||||
|
||||
public DashboardController(IServiceProvider services,
|
||||
IUserIdentity user,
|
||||
BotSharpOptions options)
|
||||
{
|
||||
_services = services;
|
||||
_user = user;
|
||||
|
||||
}
|
||||
#region User Components
|
||||
[HttpGet("/dashboard/components")]
|
||||
public async Task<UserDashboardModel> GetComponents(string userId)
|
||||
{
|
||||
var userService = _services.GetRequiredService<IUserService>();
|
||||
var dashboardProfile = await userService.GetDashboard(userId);
|
||||
if (dashboardProfile == null) return new UserDashboardModel();
|
||||
var result = new UserDashboardModel
|
||||
{
|
||||
ConversationList = dashboardProfile.ConversationList.Select(
|
||||
x => new UserDashboardConversationModel
|
||||
{
|
||||
Name = x.Name,
|
||||
ConversationId = x.ConversationId,
|
||||
Instruction = x.Instruction
|
||||
}
|
||||
).ToList()
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
[HttpPost("/dashboard/component/conversation")]
|
||||
public async Task UpdateDashboardConversationInstruction(string userId, UserDashboardConversationModel dashConv)
|
||||
{
|
||||
if (string.IsNullOrEmpty(dashConv.Name) && string.IsNullOrEmpty(dashConv.Instruction))
|
||||
{
|
||||
return;
|
||||
}
|
||||
var newDashConv = new DashboardConversation
|
||||
{
|
||||
Id = Guid.Empty.ToString(),
|
||||
ConversationId = dashConv.ConversationId
|
||||
};
|
||||
if (!string.IsNullOrEmpty(dashConv.Name))
|
||||
{
|
||||
newDashConv.Name = dashConv.Name;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(dashConv.Instruction))
|
||||
{
|
||||
newDashConv.Instruction = dashConv.Instruction;
|
||||
}
|
||||
|
||||
var userService = _services.GetRequiredService<IUserService>();
|
||||
await userService.UpdateDashboardConversation(userId, newDashConv);
|
||||
return;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ public class ConversationViewModel
|
|||
[JsonPropertyName("agent_name")]
|
||||
public string AgentName { get; set; }
|
||||
|
||||
[JsonPropertyName("title")]
|
||||
public string Title { get; set; } = string.Empty;
|
||||
|
||||
public UserViewModel User { get; set; } = new UserViewModel();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BotSharp.OpenAPI.ViewModels.Users;
|
||||
public class UserDashboardModel
|
||||
{
|
||||
|
||||
[JsonPropertyName("conversation_list")]
|
||||
public IList<UserDashboardConversationModel> ConversationList { get; set; } = [];
|
||||
}
|
||||
|
||||
public class UserDashboardConversationModel
|
||||
{
|
||||
[JsonPropertyName("name")]
|
||||
public string? Name { get; set; }
|
||||
|
||||
[JsonPropertyName("conversation_id")]
|
||||
public string? ConversationId { get; set; }
|
||||
|
||||
[JsonPropertyName("instruction")]
|
||||
public string? Instruction { get; set; }
|
||||
}
|
||||
|
|
@ -17,7 +17,6 @@ public class AudioHandlerPlugin : IBotSharpPlugin
|
|||
});
|
||||
|
||||
services.AddScoped<IAudioCompletion, NativeWhisperProvider>();
|
||||
services.AddScoped<IAgentHook, AudioHandlerHook>();
|
||||
services.AddScoped<IAgentUtilityHook, AudioHandlerUtilityHook>();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
"updatedDateTime": "2024-11-23T00:00:00Z",
|
||||
"disabled": false,
|
||||
"isPublic": true,
|
||||
"profiles": [ "database" ],
|
||||
"profiles": [ "coding" ],
|
||||
"llmConfig": {
|
||||
"provider": "openai",
|
||||
"model": "gpt-4o",
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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>();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -19,7 +19,6 @@ public class FileHandlerPlugin : IBotSharpPlugin
|
|||
return settingService.Bind<FileHandlerSettings>("FileHandler");
|
||||
});
|
||||
|
||||
services.AddScoped<IAgentHook, FileHandlerHook>();
|
||||
services.AddScoped<IAgentUtilityHook, FileHandlerUtilityHook>();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ public class HttpHandlerPlugin : IBotSharpPlugin
|
|||
return settingService.Bind<HttpHandlerSettings>("HttpHandler");
|
||||
});
|
||||
|
||||
services.AddScoped<IAgentHook, HttpHandlerHook>();
|
||||
services.AddScoped<IAgentUtilityHook, HttpHandlerUtilityHook>();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ public class KnowledgeBasePlugin : IBotSharpPlugin
|
|||
|
||||
services.AddSingleton<IPdf2TextConverter, PigPdf2TextConverter>();
|
||||
services.AddScoped<IAgentUtilityHook, KnowledgeBaseUtilityHook>();
|
||||
services.AddScoped<IAgentHook, KnowledgeBaseAgentHook>();
|
||||
services.AddScoped<IKnowledgeService, KnowledgeService>();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ public class UserDocument : MongoBase
|
|||
public DateTime CreatedTime { get; set; }
|
||||
public DateTime UpdatedTime { get; set; }
|
||||
|
||||
public Dashboard? Dashboard { get; set; }
|
||||
|
||||
public User ToUser()
|
||||
{
|
||||
return new User
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -324,4 +324,51 @@ public partial class MongoRepository
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void AddDashboardConversation(string userId, string conversationId)
|
||||
{
|
||||
var user = _dc.Users.AsQueryable()
|
||||
.FirstOrDefault(x => x.Id == userId || (x.ExternalId != null && x.ExternalId == userId));
|
||||
if (user == null) return;
|
||||
var curDash = user.Dashboard ?? new Dashboard();
|
||||
curDash.ConversationList.Add(new DashboardConversation
|
||||
{
|
||||
Id = Guid.NewGuid().ToString(),
|
||||
ConversationId = conversationId
|
||||
});
|
||||
|
||||
var filter = Builders<UserDocument>.Filter.Eq(x => x.Id, userId);
|
||||
var update = Builders<UserDocument>.Update.Set(x => x.Dashboard, curDash)
|
||||
.Set(x => x.UpdatedTime, DateTime.UtcNow);
|
||||
}
|
||||
|
||||
public void RemoveDashboardConversation(string userId, string conversationId)
|
||||
{
|
||||
var user = _dc.Users.AsQueryable()
|
||||
.FirstOrDefault(x => x.Id == userId || (x.ExternalId != null && x.ExternalId == userId));
|
||||
if (user == null || user.Dashboard == null || user.Dashboard.ConversationList.IsNullOrEmpty()) return;
|
||||
var curDash = user.Dashboard;
|
||||
var unpinConv = user.Dashboard.ConversationList.FirstOrDefault(
|
||||
x => string.Equals(x.ConversationId, conversationId, StringComparison.OrdinalIgnoreCase));
|
||||
if (unpinConv == null) return;
|
||||
curDash.ConversationList.Remove(unpinConv);
|
||||
|
||||
var filter = Builders<UserDocument>.Filter.Eq(x => x.Id, userId);
|
||||
var update = Builders<UserDocument>.Update.Set(x => x.Dashboard, curDash)
|
||||
.Set(x => x.UpdatedTime, DateTime.UtcNow);
|
||||
}
|
||||
|
||||
public void UpdateDashboardConversation(string userId, DashboardConversation dashConv)
|
||||
{
|
||||
var user = _dc.Users.AsQueryable()
|
||||
.FirstOrDefault(x => x.Id == userId || (x.ExternalId != null && x.ExternalId == userId));
|
||||
if (user == null || user.Dashboard == null || user.Dashboard.ConversationList.IsNullOrEmpty()) return;
|
||||
var curIdx = user.Dashboard.ConversationList.ToList().FindIndex(
|
||||
x => string.Equals(x.ConversationId, dashConv.ConversationId, StringComparison.OrdinalIgnoreCase));
|
||||
if (curIdx < 0) return;
|
||||
|
||||
var filter = Builders<UserDocument>.Filter.Eq(x => x.Id, userId);
|
||||
var update = Builders<UserDocument>.Update.Set(x => x.Dashboard.ConversationList[curIdx], dashConv)
|
||||
.Set(x => x.UpdatedTime, DateTime.UtcNow);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using BotSharp.Abstraction.Routing.Planning;
|
||||
using BotSharp.Abstraction.Planning;
|
||||
using BotSharp.Plugin.Planner.TwoStaging;
|
||||
|
||||
namespace BotSharp.Plugin.Planner;
|
||||
|
|
@ -17,7 +17,7 @@ public class PlannerPlugin : IBotSharpPlugin
|
|||
|
||||
public void RegisterDI(IServiceCollection services, IConfiguration config)
|
||||
{
|
||||
services.AddScoped<IRoutingPlaner, TwoStageTaskPlanner>();
|
||||
services.AddScoped<ITaskPlanner, TwoStageTaskPlanner>();
|
||||
services.AddScoped<IAgentHook, PlannerAgentHook>();
|
||||
services.AddScoped<IAgentUtilityHook, PlannerUtilityHook>();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
using BotSharp.Abstraction.Infrastructures.Enums;
|
||||
using BotSharp.Abstraction.Routing.Planning;
|
||||
using BotSharp.Core.Routing.Planning;
|
||||
using BotSharp.Abstraction.Planning;
|
||||
using BotSharp.Core.Routing.Reasoning;
|
||||
|
||||
namespace BotSharp.Plugin.Planner.TwoStaging;
|
||||
|
||||
public partial class TwoStageTaskPlanner : IRoutingPlaner
|
||||
public partial class TwoStageTaskPlanner : ITaskPlanner
|
||||
{
|
||||
private readonly IServiceProvider _services;
|
||||
private readonly ILogger _logger;
|
||||
|
|
@ -40,7 +40,7 @@ public partial class TwoStageTaskPlanner : IRoutingPlaner
|
|||
inst = response.Content.JsonContent<FunctionCallFromLlm>();
|
||||
|
||||
// Fix LLM malformed response
|
||||
PlannerHelper.FixMalformedResponse(_services, inst);
|
||||
ReasonerHelper.FixMalformedResponse(_services, inst);
|
||||
|
||||
return inst;
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue