Support to set multiple routers.
This commit is contained in:
parent
0bacd32ed5
commit
3022cf50cb
|
|
@ -4,5 +4,6 @@
|
||||||
<LangVersion>10.0</LangVersion>
|
<LangVersion>10.0</LangVersion>
|
||||||
<BotSharpVersion>0.21.0</BotSharpVersion>
|
<BotSharpVersion>0.21.0</BotSharpVersion>
|
||||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||||
|
<GenerateDocumentationFile>false</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
using BotSharp.Abstraction.Plugins.Models;
|
||||||
using BotSharp.Abstraction.Repositories.Filters;
|
using BotSharp.Abstraction.Repositories.Filters;
|
||||||
|
|
||||||
namespace BotSharp.Abstraction.Agents;
|
namespace BotSharp.Abstraction.Agents;
|
||||||
|
|
@ -34,4 +35,6 @@ public interface IAgentService
|
||||||
Task UpdateAgentFromFile(string id);
|
Task UpdateAgentFromFile(string id);
|
||||||
string GetDataDir();
|
string GetDataDir();
|
||||||
string GetAgentDataDir(string agentId);
|
string GetAgentDataDir(string agentId);
|
||||||
|
|
||||||
|
PluginDef GetPlugin(string agentId);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using BotSharp.Abstraction.Functions.Models;
|
using BotSharp.Abstraction.Functions.Models;
|
||||||
|
using BotSharp.Abstraction.Plugins.Models;
|
||||||
using BotSharp.Abstraction.Routing.Models;
|
using BotSharp.Abstraction.Routing.Models;
|
||||||
|
|
||||||
namespace BotSharp.Abstraction.Agents.Models;
|
namespace BotSharp.Abstraction.Agents.Models;
|
||||||
|
|
@ -56,6 +57,12 @@ public class Agent
|
||||||
|
|
||||||
public bool IsPublic { get; set; }
|
public bool IsPublic { get; set; }
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public bool IsRouter { get; set; }
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public PluginDef Plugin { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Allow to be routed
|
/// Allow to be routed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -19,18 +19,14 @@ public class RoutingContext
|
||||||
public string IntentName { get; set; }
|
public string IntentName { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Agent that can handl user original goal.
|
/// Agent that can handle user original goal.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string OriginAgentId
|
public string OriginAgentId
|
||||||
=> _stack.Where(x => x != _setting.AgentId).Last();
|
=> _stack.Where(x => !_setting.AgentIds.Contains(x)).Last();
|
||||||
|
|
||||||
public bool IsEmpty => !_stack.Any();
|
public bool IsEmpty => !_stack.Any();
|
||||||
public string GetCurrentAgentId()
|
public string GetCurrentAgentId()
|
||||||
{
|
{
|
||||||
if (_stack.Count == 0)
|
|
||||||
{
|
|
||||||
_stack.Push(_setting.AgentId);
|
|
||||||
}
|
|
||||||
return _stack.Peek();
|
return _stack.Peek();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ public class RoutingSettings
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Router Agent Id
|
/// Router Agent Id
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string AgentId { get; set; } = string.Empty;
|
public string[] AgentIds { get; set; } = new string[0];
|
||||||
|
|
||||||
public string Planner { get; set; } = string.Empty;
|
public string Planner { get; set; } = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using BotSharp.Abstraction.Agents.Models;
|
using BotSharp.Abstraction.Agents.Models;
|
||||||
using BotSharp.Abstraction.Repositories.Filters;
|
using BotSharp.Abstraction.Repositories.Filters;
|
||||||
|
using BotSharp.Abstraction.Routing.Settings;
|
||||||
|
|
||||||
namespace BotSharp.Core.Agents.Services;
|
namespace BotSharp.Core.Agents.Services;
|
||||||
|
|
||||||
|
|
@ -11,6 +12,15 @@ public partial class AgentService
|
||||||
public async Task<List<Agent>> GetAgents(AgentFilter filter)
|
public async Task<List<Agent>> GetAgents(AgentFilter filter)
|
||||||
{
|
{
|
||||||
var agents = _db.GetAgents(filter);
|
var agents = _db.GetAgents(filter);
|
||||||
|
|
||||||
|
// Set IsRouter
|
||||||
|
var routeSetting = _services.GetRequiredService<RoutingSettings>();
|
||||||
|
foreach (var agent in agents)
|
||||||
|
{
|
||||||
|
agent.IsRouter = routeSetting.AgentIds.Contains(agent.Id);
|
||||||
|
agent.Plugin = GetPlugin(agent.Id);
|
||||||
|
}
|
||||||
|
|
||||||
return await Task.FromResult(agents);
|
return await Task.FromResult(agents);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -35,6 +45,11 @@ public partial class AgentService
|
||||||
profile.LlmConfig.IsInherit = true;
|
profile.LlmConfig.IsInherit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set IsRouter
|
||||||
|
var routeSetting = _services.GetRequiredService<RoutingSettings>();
|
||||||
|
profile.IsRouter = routeSetting.AgentIds.Contains(profile.Id);
|
||||||
|
profile.Plugin = GetPlugin(profile.Id);
|
||||||
|
|
||||||
return profile;
|
return profile;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
using BotSharp.Abstraction.Plugins.Models;
|
||||||
|
using BotSharp.Core.Plugins;
|
||||||
|
|
||||||
|
namespace BotSharp.Core.Agents.Services;
|
||||||
|
|
||||||
|
public partial class AgentService
|
||||||
|
{
|
||||||
|
public PluginDef GetPlugin(string agentId)
|
||||||
|
{
|
||||||
|
var loader = _services.GetRequiredService<PluginLoader>();
|
||||||
|
var plugins = loader.GetPlugins(_services);
|
||||||
|
return plugins.FirstOrDefault(x => x.AgentIds.Contains(agentId)) ??
|
||||||
|
new PluginDef
|
||||||
|
{
|
||||||
|
Id = Guid.Empty.ToString(),
|
||||||
|
AgentIds = new[]
|
||||||
|
{
|
||||||
|
agentId
|
||||||
|
},
|
||||||
|
Assembly = typeof(AgentService).Assembly.FullName.Split(',').First(),
|
||||||
|
Name = "BotSharp.Core"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
using BotSharp.Abstraction.Agents.Models;
|
|
||||||
using BotSharp.Abstraction.Repositories;
|
using BotSharp.Abstraction.Repositories;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ public partial class ConversationService
|
||||||
var routing = _services.GetRequiredService<IRoutingService>();
|
var routing = _services.GetRequiredService<IRoutingService>();
|
||||||
var settings = _services.GetRequiredService<RoutingSettings>();
|
var settings = _services.GetRequiredService<RoutingSettings>();
|
||||||
|
|
||||||
response = agentId == settings.AgentId ?
|
response = settings.AgentIds.Contains(agentId) ?
|
||||||
await routing.InstructLoop(message) :
|
await routing.InstructLoop(message) :
|
||||||
await routing.ExecuteDirectly(agent, message);
|
await routing.ExecuteDirectly(agent, message);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,14 @@ public class TokenStatistics : ITokenStatistics
|
||||||
|
|
||||||
public void PrintStatistics()
|
public void PrintStatistics()
|
||||||
{
|
{
|
||||||
|
if (_timer == null)
|
||||||
|
{
|
||||||
|
_timer = Stopwatch.StartNew();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_timer.Start();
|
||||||
|
}
|
||||||
var stats = $"Token Usage: {_promptTokenCount} prompt + {_completionTokenCount} completion = {Total} total tokens ({_timer.ElapsedMilliseconds / 1000f:f2}s). One-Way cost: {Cost:C4}, accumulated cost: {AccumulatedCost:C4}. [{_model}]";
|
var stats = $"Token Usage: {_promptTokenCount} prompt + {_completionTokenCount} completion = {Total} total tokens ({_timer.ElapsedMilliseconds / 1000f:f2}s). One-Way cost: {Cost:C4}, accumulated cost: {AccumulatedCost:C4}. [{_model}]";
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
Console.WriteLine(stats, Color.DarkGray);
|
Console.WriteLine(stats, Color.DarkGray);
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,16 @@ public partial class InstructService : IInstructService
|
||||||
var agentService = _services.GetRequiredService<IAgentService>();
|
var agentService = _services.GetRequiredService<IAgentService>();
|
||||||
Agent agent = await agentService.LoadAgent(agentId);
|
Agent agent = await agentService.LoadAgent(agentId);
|
||||||
|
|
||||||
|
if (agent.Disabled)
|
||||||
|
{
|
||||||
|
var content = $"This agent ({agent.Name}) is disabled, please install the corresponding plugin ({agent.Plugin.Name}) to activate this agent.";
|
||||||
|
return new InstructResult
|
||||||
|
{
|
||||||
|
MessageId = message.MessageId,
|
||||||
|
Text = content
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Trigger before completion hooks
|
// Trigger before completion hooks
|
||||||
var hooks = _services.GetServices<IInstructHook>();
|
var hooks = _services.GetServices<IInstructHook>();
|
||||||
foreach (var hook in hooks)
|
foreach (var hook in hooks)
|
||||||
|
|
|
||||||
|
|
@ -349,8 +349,8 @@ namespace BotSharp.Core.Repository
|
||||||
{
|
{
|
||||||
var route = _services.GetRequiredService<RoutingSettings>();
|
var route = _services.GetRequiredService<RoutingSettings>();
|
||||||
query = filter.IsRouter.Value ?
|
query = filter.IsRouter.Value ?
|
||||||
query.Where(x => x.Id == route.AgentId) :
|
query.Where(x => route.AgentIds.Contains(x.Id)) :
|
||||||
query.Where(x => x.Id != route.AgentId);
|
query.Where(x => !route.AgentIds.Contains(x.Id));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filter.IsEvaluator.HasValue)
|
if (filter.IsEvaluator.HasValue)
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,11 @@ public class RouteToAgentFn : IFunctionCallback
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (targetAgent.Disabled)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
var missingfield = HasMissingRequiredField(message, out var agentId);
|
var missingfield = HasMissingRequiredField(message, out var agentId);
|
||||||
if (missingfield && message.CurrentAgentId != agentId)
|
if (missingfield && message.CurrentAgentId != agentId)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,20 @@ public class RouteToAgentRoutingHandler : RoutingHandlerBase, IRoutingHandler
|
||||||
{
|
{
|
||||||
message.Content = inst.Question;
|
message.Content = inst.Question;
|
||||||
}
|
}
|
||||||
ret = await routing.InvokeAgent(agentId, _dialogs);
|
|
||||||
|
if (agent.Disabled)
|
||||||
|
{
|
||||||
|
var content = $"This agent ({agent.Name}) is disabled, please install the corresponding plugin ({agent.Plugin.Name}) to activate this agent.";
|
||||||
|
|
||||||
|
message = RoleDialogModel.From(message,
|
||||||
|
role: AgentRole.Assistant,
|
||||||
|
content: content);
|
||||||
|
_dialogs.Add(message);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = await routing.InvokeAgent(agentId, _dialogs);
|
||||||
|
}
|
||||||
|
|
||||||
var response = _dialogs.Last();
|
var response = _dialogs.Last();
|
||||||
inst.Response = response.Content;
|
inst.Response = response.Content;
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ namespace BotSharp.Core.Routing.Hooks;
|
||||||
public class RoutingAgentHook : AgentHookBase
|
public class RoutingAgentHook : AgentHookBase
|
||||||
{
|
{
|
||||||
private readonly RoutingSettings _routingSetting;
|
private readonly RoutingSettings _routingSetting;
|
||||||
public override string SelfId => _routingSetting.AgentId;
|
public override string SelfId => string.Empty;
|
||||||
|
|
||||||
public RoutingAgentHook(IServiceProvider services, AgentSettings settings, RoutingSettings routingSetting)
|
public RoutingAgentHook(IServiceProvider services, AgentSettings settings, RoutingSettings routingSetting)
|
||||||
: base(services, settings)
|
: base(services, settings)
|
||||||
|
|
@ -17,6 +17,10 @@ public class RoutingAgentHook : AgentHookBase
|
||||||
|
|
||||||
public override bool OnInstructionLoaded(string template, Dictionary<string, object> dict)
|
public override bool OnInstructionLoaded(string template, Dictionary<string, object> dict)
|
||||||
{
|
{
|
||||||
|
if (!_routingSetting.AgentIds.Contains(_agent.Id))
|
||||||
|
{
|
||||||
|
return base.OnInstructionLoaded(template, dict);
|
||||||
|
}
|
||||||
dict["router"] = _agent;
|
dict["router"] = _agent;
|
||||||
|
|
||||||
var routing = _services.GetRequiredService<IRoutingService>();
|
var routing = _services.GetRequiredService<IRoutingService>();
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ public partial class RoutingService : IRoutingService
|
||||||
public async Task<RoleDialogModel> InstructLoop(RoleDialogModel message)
|
public async Task<RoleDialogModel> InstructLoop(RoleDialogModel message)
|
||||||
{
|
{
|
||||||
var agentService = _services.GetRequiredService<IAgentService>();
|
var agentService = _services.GetRequiredService<IAgentService>();
|
||||||
_router = await agentService.LoadAgent(_settings.AgentId);
|
_router = await agentService.LoadAgent(message.CurrentAgentId);
|
||||||
|
|
||||||
RoleDialogModel response = default;
|
RoleDialogModel response = default;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,8 @@ public class ConversationController : ControllerBase
|
||||||
[FromRoute] string conversationId,
|
[FromRoute] string conversationId,
|
||||||
[FromBody] NewMessageModel input)
|
[FromBody] NewMessageModel input)
|
||||||
{
|
{
|
||||||
|
var inputMsg = new RoleDialogModel(AgentRole.User, input.Text);
|
||||||
|
|
||||||
var conv = _services.GetRequiredService<IConversationService>();
|
var conv = _services.GetRequiredService<IConversationService>();
|
||||||
conv.SetConversationId(conversationId, input.States);
|
conv.SetConversationId(conversationId, input.States);
|
||||||
conv.States.SetState("channel", input.Channel)
|
conv.States.SetState("channel", input.Channel)
|
||||||
|
|
@ -124,7 +126,7 @@ public class ConversationController : ControllerBase
|
||||||
.SetState("sampling_factor", input.SamplingFactor);
|
.SetState("sampling_factor", input.SamplingFactor);
|
||||||
|
|
||||||
var response = new ChatResponseModel();
|
var response = new ChatResponseModel();
|
||||||
var inputMsg = new RoleDialogModel(AgentRole.User, input.Text);
|
|
||||||
await conv.SendMessage(agentId, inputMsg,
|
await conv.SendMessage(agentId, inputMsg,
|
||||||
async msg =>
|
async msg =>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using BotSharp.Abstraction.Agents.Models;
|
using BotSharp.Abstraction.Agents.Models;
|
||||||
using BotSharp.Abstraction.Functions.Models;
|
using BotSharp.Abstraction.Functions.Models;
|
||||||
|
using BotSharp.Abstraction.Plugins.Models;
|
||||||
using BotSharp.Abstraction.Routing.Models;
|
using BotSharp.Abstraction.Routing.Models;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
|
@ -18,6 +19,9 @@ public class AgentViewModel
|
||||||
[JsonPropertyName("is_public")]
|
[JsonPropertyName("is_public")]
|
||||||
public bool IsPublic { get; set; }
|
public bool IsPublic { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("is_router")]
|
||||||
|
public bool IsRouter { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("allow_routing")]
|
[JsonPropertyName("allow_routing")]
|
||||||
public bool AllowRouting { get; set; }
|
public bool AllowRouting { get; set; }
|
||||||
public bool Disabled { get; set; }
|
public bool Disabled { get; set; }
|
||||||
|
|
@ -33,6 +37,8 @@ public class AgentViewModel
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
public AgentLlmConfig? LlmConfig { get; set; }
|
public AgentLlmConfig? LlmConfig { get; set; }
|
||||||
|
|
||||||
|
public PluginDef Plugin { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("created_datetime")]
|
[JsonPropertyName("created_datetime")]
|
||||||
public DateTime CreatedDateTime { get; set; }
|
public DateTime CreatedDateTime { get; set; }
|
||||||
|
|
||||||
|
|
@ -52,12 +58,14 @@ public class AgentViewModel
|
||||||
Responses = agent.Responses,
|
Responses = agent.Responses,
|
||||||
Samples = agent.Samples,
|
Samples = agent.Samples,
|
||||||
IsPublic= agent.IsPublic,
|
IsPublic= agent.IsPublic,
|
||||||
|
IsRouter = agent.IsRouter,
|
||||||
Disabled = agent.Disabled,
|
Disabled = agent.Disabled,
|
||||||
IconUrl = agent.IconUrl,
|
IconUrl = agent.IconUrl,
|
||||||
AllowRouting = agent.AllowRouting,
|
AllowRouting = agent.AllowRouting,
|
||||||
Profiles = agent.Profiles,
|
Profiles = agent.Profiles,
|
||||||
RoutingRules = agent.RoutingRules,
|
RoutingRules = agent.RoutingRules,
|
||||||
LlmConfig = agent.LlmConfig,
|
LlmConfig = agent.LlmConfig,
|
||||||
|
Plugin = agent.Plugin,
|
||||||
CreatedDateTime = agent.CreatedDateTime,
|
CreatedDateTime = agent.CreatedDateTime,
|
||||||
UpdatedDateTime = agent.UpdatedDateTime
|
UpdatedDateTime = agent.UpdatedDateTime
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<VersionPrefix>$(BotSharpVersion)</VersionPrefix>
|
<VersionPrefix>$(BotSharpVersion)</VersionPrefix>
|
||||||
<GeneratePackageOnBuild>$(GeneratePackageOnBuild)</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>$(GeneratePackageOnBuild)</GeneratePackageOnBuild>
|
||||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
<GenerateDocumentationFile>$(GenerateDocumentationFile)</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -304,8 +304,8 @@ public partial class MongoRepository
|
||||||
{
|
{
|
||||||
var route = _services.GetRequiredService<RoutingSettings>();
|
var route = _services.GetRequiredService<RoutingSettings>();
|
||||||
query = filter.IsRouter.Value ?
|
query = filter.IsRouter.Value ?
|
||||||
query.Where(x => x.Id == route.AgentId) :
|
query.Where(x => route.AgentIds.Contains(x.Id)) :
|
||||||
query.Where(x => x.Id != route.AgentId);
|
query.Where(x => !route.AgentIds.Contains(x.Id));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filter.IsEvaluator.HasValue)
|
if (filter.IsEvaluator.HasValue)
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ public class RoutingConversationHook: ConversationHookBase
|
||||||
public override async Task OnResponseGenerated(RoleDialogModel message)
|
public override async Task OnResponseGenerated(RoleDialogModel message)
|
||||||
{
|
{
|
||||||
var routerSettings = _services.GetRequiredService<RoutingSettings>();
|
var routerSettings = _services.GetRequiredService<RoutingSettings>();
|
||||||
bool saveFlag = message.CurrentAgentId != routerSettings.AgentId;
|
bool saveFlag = !routerSettings.AgentIds.Contains(message.CurrentAgentId);
|
||||||
|
|
||||||
if (saveFlag)
|
if (saveFlag)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
using BotSharp.Abstraction.Conversations.Models;
|
||||||
|
using BotSharp.Abstraction.Functions;
|
||||||
|
using BotSharp.Plugin.SqlHero.Models;
|
||||||
|
using BotSharp.Plugin.SqlHero.Settings;
|
||||||
|
using Dapper;
|
||||||
|
using MySqlConnector;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace BotSharp.Plugin.SqlHero.Actions;
|
||||||
|
|
||||||
|
public class ExecuteQueryAction : IFunctionCallback
|
||||||
|
{
|
||||||
|
public string Name => "execute_sql";
|
||||||
|
|
||||||
|
private readonly SqlHeroSetting _setting;
|
||||||
|
|
||||||
|
public ExecuteQueryAction(SqlHeroSetting setting)
|
||||||
|
{
|
||||||
|
_setting = setting;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> Execute(RoleDialogModel message)
|
||||||
|
{
|
||||||
|
var args = JsonSerializer.Deserialize<LlmInputArgs>(message.FunctionArgs);
|
||||||
|
message.Content = "executed successully";
|
||||||
|
/*using var connection = new MySqlConnection(_setting.MySqlConnectionString);
|
||||||
|
message.Content = JsonSerializer.Serialize(connection.Query(args.SqlStatement), new JsonSerializerOptions
|
||||||
|
{
|
||||||
|
WriteIndented = true,
|
||||||
|
});*/
|
||||||
|
// message.StopCompletion = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<RootNamespace>$(MSBuildProjectName.Replace(" ", "_"))</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Dapper" Version="2.1.21" />
|
||||||
|
<PackageReference Include="MySqlConnector" Version="2.3.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Infrastructure\BotSharp.Abstraction\BotSharp.Abstraction.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace BotSharp.Plugin.SqlHero.Models;
|
||||||
|
|
||||||
|
public class LlmInputArgs
|
||||||
|
{
|
||||||
|
[JsonPropertyName("sql_statement")]
|
||||||
|
public string SqlStatement { get; set; }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
namespace BotSharp.Plugin.SqlHero.Settings;
|
||||||
|
|
||||||
|
public class SqlHeroSetting
|
||||||
|
{
|
||||||
|
public string MySqlConnectionString { get; set; }
|
||||||
|
}
|
||||||
26
src/Plugins/BotSharp.Plugin.SqlDriver/SqlHeroPlugin.cs
Normal file
26
src/Plugins/BotSharp.Plugin.SqlDriver/SqlHeroPlugin.cs
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
using BotSharp.Abstraction.Plugins;
|
||||||
|
using BotSharp.Plugin.SqlHero.Settings;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace BotSharp.Plugin.SqlHero;
|
||||||
|
|
||||||
|
public class SqlHeroPlugin : IBotSharpPlugin
|
||||||
|
{
|
||||||
|
public string Name => "SQL Hero";
|
||||||
|
public string Description => "Convert the requirements into corresponding SQL statements and execute if needed";
|
||||||
|
|
||||||
|
public void RegisterDI(IServiceCollection services, IConfiguration config)
|
||||||
|
{
|
||||||
|
var settings = new SqlHeroSetting();
|
||||||
|
config.Bind("SqlHero", settings);
|
||||||
|
services.AddSingleton(x =>
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Loaded SqlHero settings:: {Regex.Replace(settings.MySqlConnectionString, "password=.*?;", "password=******;")}", Color.Yellow);
|
||||||
|
return settings;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"id": "beda4c12-e1ec-4b4b-b328-3df4a6687c4f",
|
||||||
|
"name": "SQL Expert",
|
||||||
|
"description": "Convert the requirements into corresponding SQL statements according to the table structure and execute them if needed.",
|
||||||
|
"createdDateTime": "2023-11-15T13:49:00Z",
|
||||||
|
"updatedDateTime": "2023-11-15T13:49:00Z",
|
||||||
|
"isPublic": false,
|
||||||
|
"allowRouting": false
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
[{
|
||||||
|
"name": "execute_sql",
|
||||||
|
"description": "generate sql statement and execute the query.",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"sql_statement": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "SQL statement"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["sql_statement"]
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
|
@ -0,0 +1,181 @@
|
||||||
|
You are a SQL Expert who knows how to convert business requirements to SQL expressions.
|
||||||
|
|
||||||
|
Follow these steps:
|
||||||
|
1: Look at the table DDL defintions especially for the CONSTRAINT and FOREIGN KEY REFERENCES.
|
||||||
|
2: Translate user requirements into SQL statements step by step.
|
||||||
|
3: Double check, don't miss any requirements, all the parameters must have values.
|
||||||
|
4: Confirm with the user whether to execute the sql statement.
|
||||||
|
If user confirms to run the query, call function execute_sql to execute it.
|
||||||
|
|
||||||
|
|
||||||
|
Table structure guideline:
|
||||||
|
Table with prefix "data_" represents system enum item.
|
||||||
|
Table with prefix "client_" represents client specific configuration or client dataset.
|
||||||
|
|
||||||
|
Below are the table DDL information in JSON format:
|
||||||
|
|
||||||
|
CREATE TABLE `data_ServiceCategory` (
|
||||||
|
`Id` smallint(6) NOT NULL,
|
||||||
|
`Name` varchar(50) NOT NULL,
|
||||||
|
`IsClientVisible` tinyint(1) NOT NULL DEFAULT '1',
|
||||||
|
`IsTurnService` tinyint(1) NOT NULL DEFAULT '0',
|
||||||
|
PRIMARY KEY (`Id`),
|
||||||
|
KEY `ID_data_ServiceCategory_Name` (`Name`)
|
||||||
|
)
|
||||||
|
|
||||||
|
CREATE TABLE `data_ServiceType` (
|
||||||
|
`Id` smallint(6) NOT NULL,
|
||||||
|
`Name` varchar(50) NOT NULL,
|
||||||
|
`ServcieCategoryId` smallint(6) NOT NULL,
|
||||||
|
PRIMARY KEY (`Id`),
|
||||||
|
KEY `FK_data_ServiceType_ServcieCategoryId` (`ServcieCategoryId`),
|
||||||
|
CONSTRAINT `FK_data_ServiceType_ServcieCategoryId` FOREIGN KEY (`ServcieCategoryId`) REFERENCES `data_ServiceCategory` (`Id`)
|
||||||
|
)
|
||||||
|
|
||||||
|
CREATE TABLE `data_ServiceCode` (
|
||||||
|
`Id` smallint(6) NOT NULL,
|
||||||
|
`Name` varchar(100) NOT NULL,
|
||||||
|
`ServiceTypeId` smallint(6) NOT NULL,
|
||||||
|
`AbbrName` varchar(100) DEFAULT NULL,
|
||||||
|
`IsClientVisible` tinyint(1) NOT NULL DEFAULT '1',
|
||||||
|
PRIMARY KEY (`Id`),
|
||||||
|
KEY `FK_data_ServiceCode_ServiceCodeId` (`ServiceTypeId`),
|
||||||
|
KEY `FK_data_ServiceCode_SkillLevelId` (`SkillLevelId`),
|
||||||
|
CONSTRAINT `FK_data_ServiceCode_ServiceCodeId` FOREIGN KEY (`ServiceTypeId`) REFERENCES `data_ServiceType` (`Id`),
|
||||||
|
CONSTRAINT `FK_data_ServiceCode_SkillLevelId` FOREIGN KEY (`SkillLevelId`) REFERENCES `data_SkillLevel` (`Id`)
|
||||||
|
)
|
||||||
|
|
||||||
|
CREATE TABLE `client_ServiceCode` (
|
||||||
|
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`ClientServiceTypeId` int(10) unsigned NOT NULL,
|
||||||
|
`ServiceCodeId` smallint(6) NOT NULL,
|
||||||
|
`IsContract` tinyint(1) DEFAULT '0',
|
||||||
|
`IsHidden` tinyint(1) DEFAULT '0',
|
||||||
|
`IsPersonal` tinyint(1) NOT NULL DEFAULT '0',
|
||||||
|
`IsHiddenForClient` tinyint(1) NOT NULL DEFAULT '0',
|
||||||
|
PRIMARY KEY (`Id`),
|
||||||
|
UNIQUE KEY `UK_client_ServiceCode` (`ClientServiceTypeId`,`ServiceCodeId`,`IsPersonal`),
|
||||||
|
KEY `FK_client_ServiceCode_ServiceCodeId_idx` (`ServiceCodeId`),
|
||||||
|
CONSTRAINT `FK_client_ServiceCode_ClientServiceTypeId` FOREIGN KEY (`ClientServiceTypeId`) REFERENCES `client_ServiceType` (`Id`),
|
||||||
|
CONSTRAINT `FK_client_ServiceCode_ServiceCodeId` FOREIGN KEY (`ServiceCodeId`) REFERENCES `data_ServiceCode` (`Id`)
|
||||||
|
)
|
||||||
|
|
||||||
|
CREATE TABLE `client_ServiceType` (
|
||||||
|
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`ClientServiceCategoryId` int(10) unsigned NOT NULL,
|
||||||
|
`ServiceTypeId` smallint(6) NOT NULL,
|
||||||
|
`IsHidden` tinyint(1) DEFAULT '0',
|
||||||
|
PRIMARY KEY (`Id`),
|
||||||
|
UNIQUE KEY `UK_client_ServiceType` (`ClientServiceCategoryId`,`ServiceTypeId`),
|
||||||
|
KEY `FK_client_ServiceType_ServiceTypeId` (`ServiceTypeId`),
|
||||||
|
CONSTRAINT `FK_client_ServiceType_ClientServiceCategoryId` FOREIGN KEY (`ClientServiceCategoryId`) REFERENCES `client_ServiceCategory` (`Id`),
|
||||||
|
CONSTRAINT `FK_client_ServiceType_ServiceTypeId` FOREIGN KEY (`ServiceTypeId`) REFERENCES `data_ServiceType` (`Id`)
|
||||||
|
)
|
||||||
|
|
||||||
|
CREATE TABLE `client_ServiceCategory` (
|
||||||
|
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`ClientId` int(10) unsigned NOT NULL,
|
||||||
|
`ServiceCategoryId` smallint(6) NOT NULL,
|
||||||
|
`IsHidden` tinyint(1) DEFAULT '0',
|
||||||
|
PRIMARY KEY (`Id`),
|
||||||
|
UNIQUE KEY `UK_client_ServiceCategory` (`ClientId`,`ServiceCategoryId`),
|
||||||
|
KEY `FK_client_ServiceCategory_ServiceCategoryId` (`ServiceCategoryId`),
|
||||||
|
CONSTRAINT `FK_client_ServiceCategory_ClientId` FOREIGN KEY (`ClientId`) REFERENCES `client_Profile` (`Id`),
|
||||||
|
CONSTRAINT `FK_client_ServiceCategory_ServiceCategoryId` FOREIGN KEY (`ServiceCategoryId`) REFERENCES `data_ServiceCategory` (`Id`)
|
||||||
|
)
|
||||||
|
|
||||||
|
CREATE TABLE `client_Profile` (
|
||||||
|
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`Name` varchar(100) NOT NULL,
|
||||||
|
`Active` tinyint(1) NOT NULL DEFAULT '1',
|
||||||
|
`ClientCode` varchar(20) DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`Id`),
|
||||||
|
UNIQUE KEY `UK_client_Profile` (`ClientCode`),
|
||||||
|
KEY `FK_client_Location_CustomerTypeId` (`CustomerTypeId`),
|
||||||
|
KEY `IDX_client_Profile_BusinessTypeId` (`BusinessTypeId`),
|
||||||
|
CONSTRAINT `FK_client_Location_CustomerTypeId` FOREIGN KEY (`CustomerTypeId`) REFERENCES `data_CustomerType` (`Id`)
|
||||||
|
)
|
||||||
|
|
||||||
|
CREATE TABLE `client_WOReactive` (
|
||||||
|
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`WONum` varchar(40) NOT NULL,
|
||||||
|
`LocationId` int(10) unsigned NOT NULL,
|
||||||
|
`AffiliateId` int(10) unsigned DEFAULT NULL,
|
||||||
|
`ServiceCodeId` smallint(6) NOT NULL,
|
||||||
|
`StatusId` smallint(6) NOT NULL,
|
||||||
|
`ClientNTE` decimal(18,2) DEFAULT NULL,
|
||||||
|
`ReferWONum` varchar(512) DEFAULT NULL,
|
||||||
|
`WOCategoryId` smallint(6) DEFAULT NULL,
|
||||||
|
`WOTypeId` smallint(6) DEFAULT NULL,
|
||||||
|
`WOServiceCategoryId` smallint(6) DEFAULT NULL,
|
||||||
|
`WOServiceTypeId` smallint(6) DEFAULT NULL,
|
||||||
|
`WOClientId` int(10) unsigned DEFAULT NULL
|
||||||
|
PRIMARY KEY (`Id`),
|
||||||
|
CONSTRAINT `FK_client_WOReactive_ServiceCodeId` FOREIGN KEY (`ServiceCodeId`) REFERENCES `data_ServiceCode` (`Id`),
|
||||||
|
CONSTRAINT `FK_client_WOReactive_StatusId` FOREIGN KEY (`StatusId`) REFERENCES `data_WOStatus` (`Id`),
|
||||||
|
CONSTRAINT `FK_client_WOReactive_WOCategoryId` FOREIGN KEY (`WOCategoryId`) REFERENCES `data_WOCategory` (`Id`),
|
||||||
|
CONSTRAINT `FK_client_WOReactive_WOTypeId` FOREIGN KEY (`WOTypeId`) REFERENCES `data_WOType` (`Id`)
|
||||||
|
)
|
||||||
|
|
||||||
|
CREATE TABLE `client_ServiceCodeNTE` (
|
||||||
|
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`ClientServiceCodeId` int(10) unsigned NOT NULL,
|
||||||
|
`ClientNTE` decimal(18,2) DEFAULT NULL,
|
||||||
|
`AffiliateNTE` decimal(18,2) DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`Id`),
|
||||||
|
CONSTRAINT `FK_client_ServiceCodeNTE_ClientServiceCodeId` FOREIGN KEY (`ClientServiceCodeId`) REFERENCES `client_ServiceCode` (`Id`)
|
||||||
|
)
|
||||||
|
|
||||||
|
CREATE TABLE `data_Priority` (
|
||||||
|
`Id` smallint(6) NOT NULL,
|
||||||
|
`Name` varchar(50) NOT NULL,
|
||||||
|
`AbbrName` varchar(50) NOT NULL,
|
||||||
|
PRIMARY KEY (`Id`)
|
||||||
|
)
|
||||||
|
|
||||||
|
CREATE TABLE `data_Trade` (
|
||||||
|
`Id` smallint(6) NOT NULL,
|
||||||
|
`Name` varchar(50) NOT NULL,
|
||||||
|
PRIMARY KEY (`Id`),
|
||||||
|
KEY `ID_data_Trade_Name` (`Name`)
|
||||||
|
)
|
||||||
|
|
||||||
|
CREATE TABLE `data_TradeServiceCode` (
|
||||||
|
`Id` int(10) NOT NULL AUTO_INCREMENT,
|
||||||
|
`TradeId` smallint(6) NOT NULL,
|
||||||
|
`ServiceCodeId` smallint(6) NOT NULL,
|
||||||
|
PRIMARY KEY (`Id`),
|
||||||
|
UNIQUE KEY `UK_data_TradeServiceCode` (`ServiceCodeId`,`CustomerTypeId`),
|
||||||
|
KEY `FK_data_TradeServiceCode_TradeId` (`TradeId`),
|
||||||
|
KEY `FK_data_TradeServiceCode_ServiceCodeId` (`ServiceCodeId`),
|
||||||
|
CONSTRAINT `FK_data_TradeServiceCode_ServiceCodeId` FOREIGN KEY (`ServiceCodeId`) REFERENCES `data_ServiceCode` (`Id`),
|
||||||
|
CONSTRAINT `FK_data_TradeServiceCode_TradeId` FOREIGN KEY (`TradeId`) REFERENCES `data_Trade` (`Id`)
|
||||||
|
)
|
||||||
|
|
||||||
|
CREATE TABLE `Client_ServiceCodePriority` (
|
||||||
|
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`ClientServiceCodeId` int(10) unsigned NOT NULL,
|
||||||
|
`PriorityId` smallint(6) NOT NULL,
|
||||||
|
PRIMARY KEY (`Id`),
|
||||||
|
CONSTRAINT `FK_Client_ServiceCodePriority_ClientServiceCodeId` FOREIGN KEY (`ClientServiceCodeId`) REFERENCES `client_ServiceCode` (`Id`),
|
||||||
|
CONSTRAINT `FK_Client_ServiceCodePriority_PriorityId` FOREIGN KEY (`PriorityId`) REFERENCES `data_Priority` (`Id`)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
====
|
||||||
|
User Task:
|
||||||
|
|
||||||
|
Find all the NTE for all the service combination of client 'IH'.
|
||||||
|
Out put the service combination and NTE and priority.
|
||||||
|
|
||||||
|
====
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
user: Create a new service category named 'DSC Equipment' for client 'Signet'.
|
||||||
|
assistant: Steps: 1. Check if the service category is in data_ServiceCategory.
|
||||||
|
2. If exists, get the service category id from data_ServiceCategory.
|
||||||
|
3. If not exists, insert a new record and get the id.
|
||||||
|
4. Insert a new record to client_ServiceCategory based on the FOREIGN KEY and REFERENCES.
|
||||||
|
|
||||||
|
user: Create a new service type and service code.
|
||||||
|
assistant: You can follow the process same as service category creation.
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
using BotSharp.Plugin.Twilio.Settings;
|
||||||
using Twilio.Jwt.AccessToken;
|
using Twilio.Jwt.AccessToken;
|
||||||
using Token = Twilio.Jwt.AccessToken.Token;
|
using Token = Twilio.Jwt.AccessToken.Token;
|
||||||
|
|
||||||
|
|
@ -47,7 +48,7 @@ public class TwilioService
|
||||||
|
|
||||||
public VoiceResponse ReturnInstructions(string message)
|
public VoiceResponse ReturnInstructions(string message)
|
||||||
{
|
{
|
||||||
var routingSetting = _services.GetRequiredService<RoutingSettings>();
|
var twilioSetting = _services.GetRequiredService<TwilioSetting>();
|
||||||
|
|
||||||
var response = new VoiceResponse();
|
var response = new VoiceResponse();
|
||||||
var gather = new Gather()
|
var gather = new Gather()
|
||||||
|
|
@ -56,7 +57,7 @@ public class TwilioService
|
||||||
{
|
{
|
||||||
Gather.InputEnum.Speech
|
Gather.InputEnum.Speech
|
||||||
},
|
},
|
||||||
Action = new Uri($"{_settings.CallbackHost}/twilio/voice/{routingSetting.AgentId}")
|
Action = new Uri($"{_settings.CallbackHost}/twilio/voice/{twilioSetting.AgentId}")
|
||||||
};
|
};
|
||||||
gather.Say(message);
|
gather.Say(message);
|
||||||
response.Append(gather);
|
response.Append(gather);
|
||||||
|
|
@ -76,13 +77,13 @@ public class TwilioService
|
||||||
|
|
||||||
public VoiceResponse HoldOn(int interval, string message = null)
|
public VoiceResponse HoldOn(int interval, string message = null)
|
||||||
{
|
{
|
||||||
var routingSetting = _services.GetRequiredService<RoutingSettings>();
|
var twilioSetting = _services.GetRequiredService<TwilioSetting>();
|
||||||
|
|
||||||
var response = new VoiceResponse();
|
var response = new VoiceResponse();
|
||||||
var gather = new Gather()
|
var gather = new Gather()
|
||||||
{
|
{
|
||||||
Input = new List<Gather.InputEnum>() { Gather.InputEnum.Speech },
|
Input = new List<Gather.InputEnum>() { Gather.InputEnum.Speech },
|
||||||
Action = new Uri($"{_settings.CallbackHost}/twilio/voice/{routingSetting.AgentId}"),
|
Action = new Uri($"{_settings.CallbackHost}/twilio/voice/{twilioSetting.AgentId}"),
|
||||||
ActionOnEmptyResult = true
|
ActionOnEmptyResult = true
|
||||||
};
|
};
|
||||||
if (!string.IsNullOrEmpty(message))
|
if (!string.IsNullOrEmpty(message))
|
||||||
|
|
|
||||||
|
|
@ -9,4 +9,5 @@ public class TwilioSetting
|
||||||
public string ApiKeySID { get; set; }
|
public string ApiKeySID { get; set; }
|
||||||
public string ApiSecret { get; set; }
|
public string ApiSecret { get; set; }
|
||||||
public string CallbackHost { get; set; }
|
public string CallbackHost { get; set; }
|
||||||
|
public string AgentId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,9 @@
|
||||||
],
|
],
|
||||||
|
|
||||||
"Router": {
|
"Router": {
|
||||||
"AgentId": "01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a",
|
"AgentIds": [
|
||||||
|
"01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a"
|
||||||
|
],
|
||||||
"Planner": "NaivePlanner"
|
"Planner": "NaivePlanner"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -107,7 +109,8 @@
|
||||||
"PhoneNumber": "+1",
|
"PhoneNumber": "+1",
|
||||||
"AccountSID": "",
|
"AccountSID": "",
|
||||||
"AuthToken": "",
|
"AuthToken": "",
|
||||||
"CallbackHost": "https://"
|
"CallbackHost": "https://",
|
||||||
|
"AgentId": "01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a"
|
||||||
},
|
},
|
||||||
|
|
||||||
"Database": {
|
"Database": {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue