diff --git a/Directory.Build.props b/Directory.Build.props
index 69c26286..064983e6 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -4,5 +4,6 @@
10.0
0.21.0
false
+ false
\ No newline at end of file
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs
index 2b22d0da..76019e47 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs
@@ -1,3 +1,4 @@
+using BotSharp.Abstraction.Plugins.Models;
using BotSharp.Abstraction.Repositories.Filters;
namespace BotSharp.Abstraction.Agents;
@@ -34,4 +35,6 @@ public interface IAgentService
Task UpdateAgentFromFile(string id);
string GetDataDir();
string GetAgentDataDir(string agentId);
+
+ PluginDef GetPlugin(string agentId);
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs
index 02294c49..624f8ca8 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs
@@ -1,4 +1,5 @@
using BotSharp.Abstraction.Functions.Models;
+using BotSharp.Abstraction.Plugins.Models;
using BotSharp.Abstraction.Routing.Models;
namespace BotSharp.Abstraction.Agents.Models;
@@ -56,6 +57,12 @@ public class Agent
public bool IsPublic { get; set; }
+ [JsonIgnore]
+ public bool IsRouter { get; set; }
+
+ [JsonIgnore]
+ public PluginDef Plugin { get; set; }
+
///
/// Allow to be routed
///
diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingContext.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingContext.cs
index 18a20713..9168b23f 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingContext.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingContext.cs
@@ -19,18 +19,14 @@ public class RoutingContext
public string IntentName { get; set; }
///
- /// Agent that can handl user original goal.
+ /// Agent that can handle user original goal.
///
public string OriginAgentId
- => _stack.Where(x => x != _setting.AgentId).Last();
+ => _stack.Where(x => !_setting.AgentIds.Contains(x)).Last();
public bool IsEmpty => !_stack.Any();
public string GetCurrentAgentId()
{
- if (_stack.Count == 0)
- {
- _stack.Push(_setting.AgentId);
- }
return _stack.Peek();
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/Settings/RoutingSettings.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/Settings/RoutingSettings.cs
index 8428ac99..eb7f099a 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Routing/Settings/RoutingSettings.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Routing/Settings/RoutingSettings.cs
@@ -5,7 +5,7 @@ public class RoutingSettings
///
/// Router Agent Id
///
- public string AgentId { get; set; } = string.Empty;
+ public string[] AgentIds { get; set; } = new string[0];
public string Planner { get; set; } = string.Empty;
}
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs
index 17b4f75d..128afc24 100644
--- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs
+++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs
@@ -1,5 +1,6 @@
using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Repositories.Filters;
+using BotSharp.Abstraction.Routing.Settings;
namespace BotSharp.Core.Agents.Services;
@@ -11,6 +12,15 @@ public partial class AgentService
public async Task> GetAgents(AgentFilter filter)
{
var agents = _db.GetAgents(filter);
+
+ // Set IsRouter
+ var routeSetting = _services.GetRequiredService();
+ foreach (var agent in agents)
+ {
+ agent.IsRouter = routeSetting.AgentIds.Contains(agent.Id);
+ agent.Plugin = GetPlugin(agent.Id);
+ }
+
return await Task.FromResult(agents);
}
@@ -35,6 +45,11 @@ public partial class AgentService
profile.LlmConfig.IsInherit = true;
}
+ // Set IsRouter
+ var routeSetting = _services.GetRequiredService();
+ profile.IsRouter = routeSetting.AgentIds.Contains(profile.Id);
+ profile.Plugin = GetPlugin(profile.Id);
+
return profile;
}
}
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetPlugin.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetPlugin.cs
new file mode 100644
index 00000000..ea2029f8
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetPlugin.cs
@@ -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();
+ 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"
+ };
+ }
+}
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.cs
index 090059cd..28f9bdd2 100644
--- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.cs
+++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.cs
@@ -1,4 +1,3 @@
-using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Repositories;
using System.IO;
diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs
index eebf4c00..fd427562 100644
--- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs
+++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs
@@ -59,7 +59,7 @@ public partial class ConversationService
var routing = _services.GetRequiredService();
var settings = _services.GetRequiredService();
- response = agentId == settings.AgentId ?
+ response = settings.AgentIds.Contains(agentId) ?
await routing.InstructLoop(message) :
await routing.ExecuteDirectly(agent, message);
diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/TokenStatistics.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/TokenStatistics.cs
index 1f824dd8..25ee82f5 100644
--- a/src/Infrastructure/BotSharp.Core/Conversations/Services/TokenStatistics.cs
+++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/TokenStatistics.cs
@@ -59,6 +59,14 @@ public class TokenStatistics : ITokenStatistics
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}]";
#if DEBUG
Console.WriteLine(stats, Color.DarkGray);
diff --git a/src/Infrastructure/BotSharp.Core/Instructs/InstructService.cs b/src/Infrastructure/BotSharp.Core/Instructs/InstructService.cs
index e3b0df9f..05e54f28 100644
--- a/src/Infrastructure/BotSharp.Core/Instructs/InstructService.cs
+++ b/src/Infrastructure/BotSharp.Core/Instructs/InstructService.cs
@@ -21,6 +21,16 @@ public partial class InstructService : IInstructService
var agentService = _services.GetRequiredService();
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
var hooks = _services.GetServices();
foreach (var hook in hooks)
diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs
index ba979e84..8d3302ec 100644
--- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs
+++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs
@@ -349,8 +349,8 @@ namespace BotSharp.Core.Repository
{
var route = _services.GetRequiredService();
query = filter.IsRouter.Value ?
- query.Where(x => x.Id == route.AgentId) :
- query.Where(x => x.Id != route.AgentId);
+ query.Where(x => route.AgentIds.Contains(x.Id)) :
+ query.Where(x => !route.AgentIds.Contains(x.Id));
}
if (filter.IsEvaluator.HasValue)
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs b/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs
index c58ce3b3..a197b9ba 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs
@@ -58,6 +58,11 @@ public class RouteToAgentFn : IFunctionCallback
return false;
}
+ if (targetAgent.Disabled)
+ {
+ return false;
+ }
+
var missingfield = HasMissingRequiredField(message, out var agentId);
if (missingfield && message.CurrentAgentId != agentId)
{
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs
index d42d1349..984df62c 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs
@@ -46,7 +46,20 @@ public class RouteToAgentRoutingHandler : RoutingHandlerBase, IRoutingHandler
{
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();
inst.Response = response.Content;
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Hooks/RoutingAgentHook.cs b/src/Infrastructure/BotSharp.Core/Routing/Hooks/RoutingAgentHook.cs
index 2d3d3ab2..47cfcc38 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/Hooks/RoutingAgentHook.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/Hooks/RoutingAgentHook.cs
@@ -7,7 +7,7 @@ namespace BotSharp.Core.Routing.Hooks;
public class RoutingAgentHook : AgentHookBase
{
private readonly RoutingSettings _routingSetting;
- public override string SelfId => _routingSetting.AgentId;
+ public override string SelfId => string.Empty;
public RoutingAgentHook(IServiceProvider services, AgentSettings settings, RoutingSettings routingSetting)
: base(services, settings)
@@ -17,6 +17,10 @@ public class RoutingAgentHook : AgentHookBase
public override bool OnInstructionLoaded(string template, Dictionary dict)
{
+ if (!_routingSetting.AgentIds.Contains(_agent.Id))
+ {
+ return base.OnInstructionLoaded(template, dict);
+ }
dict["router"] = _agent;
var routing = _services.GetRequiredService();
diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs
index ee8c50f1..d70cc15f 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs
@@ -64,7 +64,7 @@ public partial class RoutingService : IRoutingService
public async Task InstructLoop(RoleDialogModel message)
{
var agentService = _services.GetRequiredService();
- _router = await agentService.LoadAgent(_settings.AgentId);
+ _router = await agentService.LoadAgent(message.CurrentAgentId);
RoleDialogModel response = default;
diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs
index 505f794f..58378ba5 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs
@@ -115,6 +115,8 @@ public class ConversationController : ControllerBase
[FromRoute] string conversationId,
[FromBody] NewMessageModel input)
{
+ var inputMsg = new RoleDialogModel(AgentRole.User, input.Text);
+
var conv = _services.GetRequiredService();
conv.SetConversationId(conversationId, input.States);
conv.States.SetState("channel", input.Channel)
@@ -124,7 +126,7 @@ public class ConversationController : ControllerBase
.SetState("sampling_factor", input.SamplingFactor);
var response = new ChatResponseModel();
- var inputMsg = new RoleDialogModel(AgentRole.User, input.Text);
+
await conv.SendMessage(agentId, inputMsg,
async msg =>
{
diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs
index 49d7d095..663dfd4a 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs
@@ -1,5 +1,6 @@
using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Functions.Models;
+using BotSharp.Abstraction.Plugins.Models;
using BotSharp.Abstraction.Routing.Models;
using System.Text.Json.Serialization;
@@ -18,6 +19,9 @@ public class AgentViewModel
[JsonPropertyName("is_public")]
public bool IsPublic { get; set; }
+ [JsonPropertyName("is_router")]
+ public bool IsRouter { get; set; }
+
[JsonPropertyName("allow_routing")]
public bool AllowRouting { get; set; }
public bool Disabled { get; set; }
@@ -33,6 +37,8 @@ public class AgentViewModel
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public AgentLlmConfig? LlmConfig { get; set; }
+ public PluginDef Plugin { get; set; }
+
[JsonPropertyName("created_datetime")]
public DateTime CreatedDateTime { get; set; }
@@ -52,12 +58,14 @@ public class AgentViewModel
Responses = agent.Responses,
Samples = agent.Samples,
IsPublic= agent.IsPublic,
+ IsRouter = agent.IsRouter,
Disabled = agent.Disabled,
IconUrl = agent.IconUrl,
AllowRouting = agent.AllowRouting,
Profiles = agent.Profiles,
RoutingRules = agent.RoutingRules,
LlmConfig = agent.LlmConfig,
+ Plugin = agent.Plugin,
CreatedDateTime = agent.CreatedDateTime,
UpdatedDateTime = agent.UpdatedDateTime
};
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/BotSharp.Plugin.MongoStorage.csproj b/src/Plugins/BotSharp.Plugin.MongoStorage/BotSharp.Plugin.MongoStorage.csproj
index ac122c52..67b97096 100644
--- a/src/Plugins/BotSharp.Plugin.MongoStorage/BotSharp.Plugin.MongoStorage.csproj
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/BotSharp.Plugin.MongoStorage.csproj
@@ -6,7 +6,7 @@
enable
$(BotSharpVersion)
$(GeneratePackageOnBuild)
- True
+ $(GenerateDocumentationFile)
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs
index 8f9e4ce8..8116d0eb 100644
--- a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs
@@ -304,8 +304,8 @@ public partial class MongoRepository
{
var route = _services.GetRequiredService();
query = filter.IsRouter.Value ?
- query.Where(x => x.Id == route.AgentId) :
- query.Where(x => x.Id != route.AgentId);
+ query.Where(x => route.AgentIds.Contains(x.Id)) :
+ query.Where(x => !route.AgentIds.Contains(x.Id));
}
if (filter.IsEvaluator.HasValue)
diff --git a/src/Plugins/BotSharp.Plugin.RoutingSpeeder/RoutingConversationHook.cs b/src/Plugins/BotSharp.Plugin.RoutingSpeeder/RoutingConversationHook.cs
index 11744d0d..d3ed4bdf 100644
--- a/src/Plugins/BotSharp.Plugin.RoutingSpeeder/RoutingConversationHook.cs
+++ b/src/Plugins/BotSharp.Plugin.RoutingSpeeder/RoutingConversationHook.cs
@@ -53,7 +53,7 @@ public class RoutingConversationHook: ConversationHookBase
public override async Task OnResponseGenerated(RoleDialogModel message)
{
var routerSettings = _services.GetRequiredService();
- bool saveFlag = message.CurrentAgentId != routerSettings.AgentId;
+ bool saveFlag = !routerSettings.AgentIds.Contains(message.CurrentAgentId);
if (saveFlag)
{
diff --git a/src/Plugins/BotSharp.Plugin.SqlDriver/Actions/ExecuteQueryAction.cs b/src/Plugins/BotSharp.Plugin.SqlDriver/Actions/ExecuteQueryAction.cs
new file mode 100644
index 00000000..df9181af
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.SqlDriver/Actions/ExecuteQueryAction.cs
@@ -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 Execute(RoleDialogModel message)
+ {
+ var args = JsonSerializer.Deserialize(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;
+ }
+}
diff --git a/src/Plugins/BotSharp.Plugin.SqlDriver/BotSharp.Plugin.SqlHero.csproj b/src/Plugins/BotSharp.Plugin.SqlDriver/BotSharp.Plugin.SqlHero.csproj
new file mode 100644
index 00000000..ba521fa9
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.SqlDriver/BotSharp.Plugin.SqlHero.csproj
@@ -0,0 +1,18 @@
+
+
+
+ netstandard2.1
+ enable
+ $(MSBuildProjectName.Replace(" ", "_"))
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Plugins/BotSharp.Plugin.SqlDriver/Models/LlmInputArgs.cs b/src/Plugins/BotSharp.Plugin.SqlDriver/Models/LlmInputArgs.cs
new file mode 100644
index 00000000..0d12b7af
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.SqlDriver/Models/LlmInputArgs.cs
@@ -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; }
+}
diff --git a/src/Plugins/BotSharp.Plugin.SqlDriver/Settings/SqlHeroSetting.cs b/src/Plugins/BotSharp.Plugin.SqlDriver/Settings/SqlHeroSetting.cs
new file mode 100644
index 00000000..4ffe9aab
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.SqlDriver/Settings/SqlHeroSetting.cs
@@ -0,0 +1,6 @@
+namespace BotSharp.Plugin.SqlHero.Settings;
+
+public class SqlHeroSetting
+{
+ public string MySqlConnectionString { get; set; }
+}
diff --git a/src/Plugins/BotSharp.Plugin.SqlDriver/SqlHeroPlugin.cs b/src/Plugins/BotSharp.Plugin.SqlDriver/SqlHeroPlugin.cs
new file mode 100644
index 00000000..b5cdd2a0
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.SqlDriver/SqlHeroPlugin.cs
@@ -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;
+ });
+ }
+}
diff --git a/src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/beda4c12-e1ec-4b4b-b328-3df4a6687c4f/agent.json b/src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/beda4c12-e1ec-4b4b-b328-3df4a6687c4f/agent.json
new file mode 100644
index 00000000..60e200aa
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/beda4c12-e1ec-4b4b-b328-3df4a6687c4f/agent.json
@@ -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
+}
\ No newline at end of file
diff --git a/src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/beda4c12-e1ec-4b4b-b328-3df4a6687c4f/functions.json b/src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/beda4c12-e1ec-4b4b-b328-3df4a6687c4f/functions.json
new file mode 100644
index 00000000..e09e23a1
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/beda4c12-e1ec-4b4b-b328-3df4a6687c4f/functions.json
@@ -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"]
+ }
+}]
\ No newline at end of file
diff --git a/src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/beda4c12-e1ec-4b4b-b328-3df4a6687c4f/instruction.liquid b/src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/beda4c12-e1ec-4b4b-b328-3df4a6687c4f/instruction.liquid
new file mode 100644
index 00000000..24966b0e
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/beda4c12-e1ec-4b4b-b328-3df4a6687c4f/instruction.liquid
@@ -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.
\ No newline at end of file
diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioService.cs b/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioService.cs
index 374a00ad..f01a7e29 100644
--- a/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioService.cs
+++ b/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioService.cs
@@ -1,3 +1,4 @@
+using BotSharp.Plugin.Twilio.Settings;
using Twilio.Jwt.AccessToken;
using Token = Twilio.Jwt.AccessToken.Token;
@@ -47,7 +48,7 @@ public class TwilioService
public VoiceResponse ReturnInstructions(string message)
{
- var routingSetting = _services.GetRequiredService();
+ var twilioSetting = _services.GetRequiredService();
var response = new VoiceResponse();
var gather = new Gather()
@@ -56,7 +57,7 @@ public class TwilioService
{
Gather.InputEnum.Speech
},
- Action = new Uri($"{_settings.CallbackHost}/twilio/voice/{routingSetting.AgentId}")
+ Action = new Uri($"{_settings.CallbackHost}/twilio/voice/{twilioSetting.AgentId}")
};
gather.Say(message);
response.Append(gather);
@@ -76,13 +77,13 @@ public class TwilioService
public VoiceResponse HoldOn(int interval, string message = null)
{
- var routingSetting = _services.GetRequiredService();
+ var twilioSetting = _services.GetRequiredService();
var response = new VoiceResponse();
var gather = new Gather()
{
Input = new List() { Gather.InputEnum.Speech },
- Action = new Uri($"{_settings.CallbackHost}/twilio/voice/{routingSetting.AgentId}"),
+ Action = new Uri($"{_settings.CallbackHost}/twilio/voice/{twilioSetting.AgentId}"),
ActionOnEmptyResult = true
};
if (!string.IsNullOrEmpty(message))
diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Settings/TwilioSetting.cs b/src/Plugins/BotSharp.Plugin.Twilio/Settings/TwilioSetting.cs
index 3da775cf..c7170ee2 100644
--- a/src/Plugins/BotSharp.Plugin.Twilio/Settings/TwilioSetting.cs
+++ b/src/Plugins/BotSharp.Plugin.Twilio/Settings/TwilioSetting.cs
@@ -9,4 +9,5 @@ public class TwilioSetting
public string ApiKeySID { get; set; }
public string ApiSecret { get; set; }
public string CallbackHost { get; set; }
+ public string AgentId { get; set; }
}
diff --git a/src/WebStarter/appsettings.json b/src/WebStarter/appsettings.json
index 2cb7389a..c500511a 100644
--- a/src/WebStarter/appsettings.json
+++ b/src/WebStarter/appsettings.json
@@ -38,7 +38,9 @@
],
"Router": {
- "AgentId": "01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a",
+ "AgentIds": [
+ "01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a"
+ ],
"Planner": "NaivePlanner"
},
@@ -107,7 +109,8 @@
"PhoneNumber": "+1",
"AccountSID": "",
"AuthToken": "",
- "CallbackHost": "https://"
+ "CallbackHost": "https://",
+ "AgentId": "01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a"
},
"Database": {