diff --git a/src/Infrastructure/BotSharp.Abstraction/Users/Enums/UserRole.cs b/src/Infrastructure/BotSharp.Abstraction/Users/Enums/UserRole.cs
index 02c095bc..620a696e 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Users/Enums/UserRole.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Users/Enums/UserRole.cs
@@ -17,6 +17,18 @@ public class UserRole
///
public const string Client = "client";
+ ///
+ /// Back office operations
+ ///
+ public const string Operation = "operation";
+
+ public const string Technician = "technician";
+
+ ///
+ /// Software Developers, Data Engineer, Business Analyst
+ ///
+ public const string Engineer = "engineer";
+
///
/// AI Assistant
///
diff --git a/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Extensions/VectorStorageExtension.cs b/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Extensions/VectorStorageExtension.cs
index ec519f04..8c977cfb 100644
--- a/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Extensions/VectorStorageExtension.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Extensions/VectorStorageExtension.cs
@@ -9,7 +9,11 @@ public static class VectorStorageExtension
{
if (data?.Data == null) return string.Empty;
- return $"Question: {data.Data[KnowledgePayloadName.Text]}\r\nAnswer: {data.Data[KnowledgePayloadName.Answer]}";
+ if (data.Data.TryGetValue(KnowledgePayloadName.Text, out var question)) { }
+
+ if (data.Data.TryGetValue(KnowledgePayloadName.Answer, out var answer)) { }
+
+ return $"Question: {question}\r\nAnswer: {answer}";
}
public static string ToPayloadPair(this VectorSearchResult data, IList payloads)
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.cs
index 40b80e50..b69f7529 100644
--- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.cs
+++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.cs
@@ -41,7 +41,7 @@ public partial class AgentService : IAgentService
public string GetAgentDataDir(string agentId)
{
var dbSettings = _services.GetRequiredService();
- var dir = Path.Combine(dbSettings.FileRepository, _agentSettings.DataDir, agentId);
+ var dir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, dbSettings.FileRepository, _agentSettings.DataDir, agentId);
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
diff --git a/src/Infrastructure/BotSharp.Core/Conversations/ConversationPlugin.cs b/src/Infrastructure/BotSharp.Core/Conversations/ConversationPlugin.cs
index 70c91d9f..f06e2ba2 100644
--- a/src/Infrastructure/BotSharp.Core/Conversations/ConversationPlugin.cs
+++ b/src/Infrastructure/BotSharp.Core/Conversations/ConversationPlugin.cs
@@ -6,7 +6,6 @@ using BotSharp.Abstraction.Routing.Planning;
using BotSharp.Abstraction.Settings;
using BotSharp.Abstraction.Templating;
using BotSharp.Core.Instructs;
-using BotSharp.Core.Knowledges.Services;
using BotSharp.Core.Messaging;
using BotSharp.Core.Routing.Planning;
using BotSharp.Core.Templating;
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs
index 94539b9b..adc1a1c3 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs
@@ -64,7 +64,7 @@ public class RouteToAgentRoutingHandler : RoutingHandlerBase, IRoutingHandler
if (message.FunctionName != null)
{
var msg = RoleDialogModel.From(message, role: AgentRole.Function);
- var ret = await routing.InvokeFunction(message.FunctionName, msg);
+ await routing.InvokeFunction(message.FunctionName, msg);
}
var agentId = routing.Context.GetCurrentAgentId();
@@ -83,9 +83,7 @@ public class RouteToAgentRoutingHandler : RoutingHandlerBase, IRoutingHandler
{
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);
+ message = RoleDialogModel.From(message, role: AgentRole.Assistant, content: content);
_dialogs.Add(message);
}
else
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/TwoStagePlanner.FirstStage.cs b/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/TwoStagePlanner.FirstStage.cs
deleted file mode 100644
index 98efbacc..00000000
--- a/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/TwoStagePlanner.FirstStage.cs
+++ /dev/null
@@ -1,82 +0,0 @@
-using BotSharp.Abstraction.MLTasks;
-using BotSharp.Abstraction.Templating;
-
-namespace BotSharp.Core.Routing.Planning;
-
-public partial class TwoStagePlanner
-{
- private async Task GetFirstStagePlanAsync(Agent router, string messageId, List dialogs)
- {
- var firstStagePlanPrompt = await GetFirstStagePlanPrompt(router);
-
- var plan = new FirstStagePlan[0];
-
- var llmProviderService = _services.GetRequiredService();
- var provider = router.LlmConfig.Provider ?? "openai";
- var model = llmProviderService.GetProviderModel(provider, router.LlmConfig.Model ?? "gpt-4o");
-
- // chat completion
- var completion = CompletionProvider.GetChatCompletion(_services,
- provider: provider,
- model: model.Name);
-
- string text = string.Empty;
-
- try
- {
- var response = await completion.GetChatCompletions(new Agent
- {
- Id = router.Id,
- Name = nameof(TwoStagePlanner),
- Instruction = firstStagePlanPrompt
- }, dialogs);
-
- text = response.Content;
- plan = response.Content.JsonArrayContent();
- }
- catch (Exception ex)
- {
- _logger.LogError($"{ex.Message}: {text}");
- }
-
- return plan;
- }
-
- private async Task GetFirstStagePlanPrompt(Agent router)
- {
- var template = router.Templates.First(x => x.Name == "two_stage.1st.plan").Content;
- var responseFormat = JsonSerializer.Serialize(new FirstStagePlan
- {
- Parameters = new JsonDocument[]{ JsonDocument.Parse("{}") },
- Results = new string[] { "" }
- });
-
- var relevantKnowledges = new List();
- var hooks = _services.GetServices();
- foreach (var hook in hooks)
- {
- var k = await hook.GetRelevantKnowledges();
- relevantKnowledges.AddRange(k);
- }
-
- var render = _services.GetRequiredService();
- return render.Render(template, new Dictionary
- {
- { "response_format", responseFormat },
- { "relevant_knowledges", relevantKnowledges.ToArray() }
- });
- }
-
- private string GetFirstStageNextPrompt(Agent router)
- {
- var template = router.Templates.First(x => x.Name == "first_stage.next").Content;
- var responseFormat = JsonSerializer.Serialize(new FirstStagePlan
- {
- });
- var render = _services.GetRequiredService();
- return render.Render(template, new Dictionary
- {
- { "response_format", responseFormat },
- });
- }
-}
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/TwoStagePlanner.GetContext.cs b/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/TwoStagePlanner.GetContext.cs
deleted file mode 100644
index 998bcd91..00000000
--- a/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/TwoStagePlanner.GetContext.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-namespace BotSharp.Core.Routing.Planning;
-
-public partial class TwoStagePlanner
-{
- public string GetContext()
- {
- var content = "";
- foreach (var c in _executionContext)
- {
- content += $"* {c}\r\n";
- }
- return content;
- }
-}
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/TwoStagePlanner.SecondStage.cs b/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/TwoStagePlanner.SecondStage.cs
deleted file mode 100644
index 31ad6608..00000000
--- a/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/TwoStagePlanner.SecondStage.cs
+++ /dev/null
@@ -1,83 +0,0 @@
-using BotSharp.Abstraction.Agents.Models;
-using BotSharp.Abstraction.MLTasks;
-using BotSharp.Abstraction.Templating;
-
-namespace BotSharp.Core.Routing.Planning;
-
-public partial class TwoStagePlanner
-{
- private async Task GetSecondStagePlanAsync(Agent router, string messageId, FirstStagePlan plan1st, List dialogs)
- {
- var secondStagePrompt = GetSecondStagePlanPrompt(router, plan1st);
- var firstStageSystemPrompt = await GetFirstStagePlanPrompt(router);
-
- var plan = new SecondStagePlan[0];
-
- var llmProviderService = _services.GetRequiredService();
- var model = llmProviderService.GetProviderModel("azure-openai", "gpt-4");
-
- // chat completion
- var completion = CompletionProvider.GetChatCompletion(_services,
- provider: "azure-openai",
- model: model.Name);
-
- string text = string.Empty;
-
- var conversations = dialogs.Where(x => x.Role != AgentRole.Function).ToList();
- conversations.Add(new RoleDialogModel(AgentRole.User, secondStagePrompt)
- {
- CurrentAgentId = router.Id,
- MessageId = messageId,
- });
-
- try
- {
- var response = await completion.GetChatCompletions(new Agent
- {
- Id = router.Id,
- Name = nameof(TwoStagePlanner),
- Instruction = firstStageSystemPrompt
- }, conversations);
-
- text = response.Content;
- plan = response.Content.JsonArrayContent();
- }
- catch (Exception ex)
- {
- _logger.LogError($"{ex.Message}: {text}");
- }
-
- return plan;
- }
-
- private string GetSecondStageTaskPrompt(Agent router, SecondStagePlan plan)
- {
- var template = router.Templates.First(x => x.Name == "planner_prompt.two_stage.2nd.task").Content;
- var render = _services.GetRequiredService();
- return render.Render(template, new Dictionary
- {
- { "task_description", plan.Description },
- { "related_tables", plan.Tables },
- { "input_arguments", JsonSerializer.Serialize(plan.Parameters) },
- { "output_results", JsonSerializer.Serialize(plan.Results) },
- });
- }
-
- private string GetSecondStagePlanPrompt(Agent router, FirstStagePlan plan)
- {
- var template = router.Templates.First(x => x.Name == "planner_prompt.two_stage.2nd.plan").Content;
- var responseFormat = JsonSerializer.Serialize(new SecondStagePlan
- {
- Tool = "tool name if task solution provided",
- Parameters = new JsonDocument[] { JsonDocument.Parse("{}") },
- Results = new string[] { "" }
- });
- var context = GetContext();
- var render = _services.GetRequiredService();
- return render.Render(template, new Dictionary
- {
- { "task_description", plan.Task },
- { "response_format", responseFormat }
- });
- }
-}
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/TwoStagePlanner.cs b/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/TwoStagePlanner.cs
deleted file mode 100644
index 8d65f566..00000000
--- a/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/TwoStagePlanner.cs
+++ /dev/null
@@ -1,136 +0,0 @@
-using BotSharp.Abstraction.Routing.Planning;
-
-namespace BotSharp.Core.Routing.Planning;
-
-public partial class TwoStagePlanner : IRoutingPlaner
-{
- private readonly IServiceProvider _services;
- private readonly ILogger _logger;
- public int MaxLoopCount => 100;
- private bool _isTaskCompleted;
- private string _md5;
-
- private Queue _plan1st = new Queue();
- private Queue _plan2nd = new Queue();
-
- private List _executionContext = new List();
-
- public TwoStagePlanner(IServiceProvider services, ILogger logger)
- {
- _services = services;
- _logger = logger;
- }
-
- public async Task GetNextInstruction(Agent router, string messageId, List dialogs)
- {
- if (_plan1st.IsNullOrEmpty() && _plan2nd.IsNullOrEmpty())
- {
- FirstStagePlan[] items = await GetFirstStagePlanAsync(router, messageId, dialogs);
-
- foreach (var item in items)
- {
- _plan1st.Enqueue(item);
- };
- }
-
- // Get Second Stage Plan
- if (_plan2nd.IsNullOrEmpty())
- {
- var plan1 = _plan1st.Dequeue();
-
- if (plan1.ContainMultipleSteps)
- {
- SecondStagePlan[] items = await GetSecondStagePlanAsync(router, messageId, plan1, dialogs);
-
- foreach (var item in items)
- {
- _plan2nd.Enqueue(item);
- }
- }
- else
- {
- _plan2nd.Enqueue(new SecondStagePlan
- {
- Description = plan1.Task,
- Tables = plan1.Tables,
- Parameters = plan1.Parameters,
- Results = plan1.Results,
- });
- }
- }
-
- var plan2 = _plan2nd.Dequeue();
-
- var secondStagePrompt = GetSecondStageTaskPrompt(router, plan2);
- var inst = new FunctionCallFromLlm
- {
- AgentName = "SQL Driver",
- Response = secondStagePrompt,
- Function = "route_to_agent"
- };
-
- inst.HandleDialogsByPlanner = true;
- _isTaskCompleted = _plan1st.IsNullOrEmpty() && _plan2nd.IsNullOrEmpty();
-
- return inst;
- }
-
- public List BeforeHandleContext(FunctionCallFromLlm inst, RoleDialogModel message, List dialogs)
- {
- var question = inst.Response;
- if (_executionContext.Count > 0)
- {
- var content = GetContext();
- question = $"CONTEXT:\r\n{content}\r\n" + inst.Response;
- }
- else
- {
- question = $"CONTEXT:\r\n{question}";
- }
-
- var taskAgentDialogs = new List
- {
- new RoleDialogModel(AgentRole.User, question)
- {
- MessageId = message.MessageId,
- }
- };
-
- return taskAgentDialogs;
- }
-
- public bool AfterHandleContext(List dialogs, List taskAgentDialogs)
- {
- dialogs.AddRange(taskAgentDialogs.Skip(1));
-
- // Keep execution context
- _executionContext.Add(taskAgentDialogs.Last().Content);
-
- return true;
- }
-
- public async Task AgentExecuting(Agent router, FunctionCallFromLlm inst, RoleDialogModel message, List dialogs)
- {
- dialogs.Add(new RoleDialogModel(AgentRole.User, inst.Response)
- {
- MessageId = message.MessageId,
- CurrentAgentId = router.Id
- });
- return true;
- }
-
- public async Task AgentExecuted(Agent router, FunctionCallFromLlm inst, RoleDialogModel message, List dialogs)
- {
- var context = _services.GetRequiredService();
-
- if (message.StopCompletion || _isTaskCompleted)
- {
- context.Empty(reason: $"Agent queue is cleared by {nameof(TwoStagePlanner)}");
- return false;
- }
-
- var routing = _services.GetRequiredService();
- routing.ResetRecursiveCounter();
- return true;
- }
-}
diff --git a/src/Infrastructure/BotSharp.Core/Knowledges/Helpers/KnowledgeSettingHelper.cs b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Helpers/KnowledgeSettingHelper.cs
similarity index 89%
rename from src/Infrastructure/BotSharp.Core/Knowledges/Helpers/KnowledgeSettingHelper.cs
rename to src/Plugins/BotSharp.Plugin.KnowledgeBase/Helpers/KnowledgeSettingHelper.cs
index a278d7bf..48033c91 100644
--- a/src/Infrastructure/BotSharp.Core/Knowledges/Helpers/KnowledgeSettingHelper.cs
+++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Helpers/KnowledgeSettingHelper.cs
@@ -1,7 +1,4 @@
-using BotSharp.Abstraction.Knowledges.Settings;
-using BotSharp.Abstraction.MLTasks;
-
-namespace BotSharp.Core.Knowledges.Helpers;
+namespace BotSharp.Plugin.KnowledgeBase.Helpers;
public static class KnowledgeSettingHelper
{
diff --git a/src/Infrastructure/BotSharp.Core/Knowledges/Helpers/TextChopper.cs b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Helpers/TextChopper.cs
similarity index 94%
rename from src/Infrastructure/BotSharp.Core/Knowledges/Helpers/TextChopper.cs
rename to src/Plugins/BotSharp.Plugin.KnowledgeBase/Helpers/TextChopper.cs
index 68b58539..9e9b5f9d 100644
--- a/src/Infrastructure/BotSharp.Core/Knowledges/Helpers/TextChopper.cs
+++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Helpers/TextChopper.cs
@@ -1,7 +1,6 @@
-using BotSharp.Abstraction.Knowledges.Models;
using System.Text.RegularExpressions;
-namespace BotSharp.Core.Knowledges.Helpers;
+namespace BotSharp.Plugin.KnowledgeBase.Helpers;
public static class TextChopper
{
diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/KnowledgeBasePlugin.cs b/src/Plugins/BotSharp.Plugin.KnowledgeBase/KnowledgeBasePlugin.cs
index 0e7bcc63..0f28aa5e 100644
--- a/src/Plugins/BotSharp.Plugin.KnowledgeBase/KnowledgeBasePlugin.cs
+++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/KnowledgeBasePlugin.cs
@@ -1,8 +1,8 @@
using BotSharp.Abstraction.Plugins.Models;
using BotSharp.Abstraction.Settings;
-using BotSharp.Core.Knowledges.Services;
using BotSharp.Plugin.KnowledgeBase.Converters;
using BotSharp.Plugin.KnowledgeBase.Hooks;
+using BotSharp.Plugin.KnowledgeBase.Services;
using Microsoft.Extensions.Configuration;
namespace BotSharp.Plugin.KnowledgeBase;
diff --git a/src/Infrastructure/BotSharp.Core/Knowledges/Services/KnowledgeService.Create.cs b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Create.cs
similarity index 92%
rename from src/Infrastructure/BotSharp.Core/Knowledges/Services/KnowledgeService.Create.cs
rename to src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Create.cs
index d8b82fb5..2c4004fc 100644
--- a/src/Infrastructure/BotSharp.Core/Knowledges/Services/KnowledgeService.Create.cs
+++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Create.cs
@@ -1,8 +1,4 @@
-using BotSharp.Abstraction.Knowledges.Models;
-using BotSharp.Abstraction.VectorStorage.Models;
-using BotSharp.Core.Knowledges.Helpers;
-
-namespace BotSharp.Core.Knowledges.Services;
+namespace BotSharp.Plugin.KnowledgeBase.Services;
public partial class KnowledgeService
{
diff --git a/src/Infrastructure/BotSharp.Core/Knowledges/Services/KnowledgeService.Delete.cs b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Delete.cs
similarity index 95%
rename from src/Infrastructure/BotSharp.Core/Knowledges/Services/KnowledgeService.Delete.cs
rename to src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Delete.cs
index 404b4e2c..b0973a99 100644
--- a/src/Infrastructure/BotSharp.Core/Knowledges/Services/KnowledgeService.Delete.cs
+++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Delete.cs
@@ -1,4 +1,4 @@
-namespace BotSharp.Core.Knowledges.Services;
+namespace BotSharp.Plugin.KnowledgeBase.Services;
public partial class KnowledgeService
{
diff --git a/src/Infrastructure/BotSharp.Core/Knowledges/Services/KnowledgeService.Get.cs b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Get.cs
similarity index 95%
rename from src/Infrastructure/BotSharp.Core/Knowledges/Services/KnowledgeService.Get.cs
rename to src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Get.cs
index 69093659..dcffa944 100644
--- a/src/Infrastructure/BotSharp.Core/Knowledges/Services/KnowledgeService.Get.cs
+++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Get.cs
@@ -1,8 +1,4 @@
-using BotSharp.Abstraction.Graph.Models;
-using BotSharp.Abstraction.Knowledges.Models;
-using BotSharp.Abstraction.VectorStorage.Models;
-
-namespace BotSharp.Core.Knowledges.Services;
+namespace BotSharp.Plugin.KnowledgeBase.Services;
public partial class KnowledgeService
{
diff --git a/src/Infrastructure/BotSharp.Core/Knowledges/Services/KnowledgeService.Update.cs b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Update.cs
similarity index 91%
rename from src/Infrastructure/BotSharp.Core/Knowledges/Services/KnowledgeService.Update.cs
rename to src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Update.cs
index b9652f61..0fa1f5cd 100644
--- a/src/Infrastructure/BotSharp.Core/Knowledges/Services/KnowledgeService.Update.cs
+++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Update.cs
@@ -1,6 +1,4 @@
-using BotSharp.Abstraction.VectorStorage.Models;
-
-namespace BotSharp.Core.Knowledges.Services;
+namespace BotSharp.Plugin.KnowledgeBase.Services;
public partial class KnowledgeService
{
diff --git a/src/Infrastructure/BotSharp.Core/Knowledges/Services/KnowledgeService.cs b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.cs
similarity index 80%
rename from src/Infrastructure/BotSharp.Core/Knowledges/Services/KnowledgeService.cs
rename to src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.cs
index 2c0853d0..c668e07e 100644
--- a/src/Infrastructure/BotSharp.Core/Knowledges/Services/KnowledgeService.cs
+++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.cs
@@ -1,10 +1,4 @@
-using BotSharp.Abstraction.Graph;
-using BotSharp.Abstraction.Knowledges.Settings;
-using BotSharp.Abstraction.MLTasks;
-using BotSharp.Abstraction.VectorStorage;
-using BotSharp.Core.Knowledges.Helpers;
-
-namespace BotSharp.Core.Knowledges.Services;
+namespace BotSharp.Plugin.KnowledgeBase.Services;
public partial class KnowledgeService : IKnowledgeService
{
diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Using.cs b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Using.cs
index 1437f41e..53ed55a2 100644
--- a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Using.cs
+++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Using.cs
@@ -20,6 +20,7 @@ global using BotSharp.Abstraction.Knowledges.Settings;
global using BotSharp.Abstraction.Knowledges.Enums;
global using BotSharp.Abstraction.VectorStorage;
global using BotSharp.Abstraction.VectorStorage.Models;
+global using BotSharp.Abstraction.Graph.Models;
global using BotSharp.Abstraction.Knowledges.Models;
global using BotSharp.Abstraction.MLTasks;
global using BotSharp.Abstraction.Functions;
diff --git a/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/TwoStageTaskPlanner.cs b/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/TwoStageTaskPlanner.cs
index c6f819e5..55543230 100644
--- a/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/TwoStageTaskPlanner.cs
+++ b/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/TwoStageTaskPlanner.cs
@@ -1,6 +1,7 @@
using BotSharp.Abstraction.MLTasks;
using BotSharp.Abstraction.Routing.Planning;
using BotSharp.Core.Routing.Planning;
+using Microsoft.EntityFrameworkCore;
namespace BotSharp.Plugin.Planner.TwoStaging;
@@ -8,7 +9,7 @@ public partial class TwoStageTaskPlanner : IRoutingPlaner
{
private readonly IServiceProvider _services;
private readonly ILogger _logger;
- public int MaxLoopCount => 100;
+ public int MaxLoopCount => 10;
private bool _isTaskCompleted;
private Queue _plan1st = new Queue();
@@ -16,7 +17,7 @@ public partial class TwoStageTaskPlanner : IRoutingPlaner
private List _executionContext = new List();
- public TwoStageTaskPlanner(IServiceProvider services, ILogger logger)
+ public TwoStageTaskPlanner(IServiceProvider services, ILogger logger)
{
_services = services;
_logger = logger;
@@ -27,15 +28,14 @@ public partial class TwoStageTaskPlanner : IRoutingPlaner
// push agent to routing context
var routing = _services.GetRequiredService();
routing.Context.Push(BuiltInAgentId.Planner, "Make plan in TwoStage planner");
-
return new FunctionCallFromLlm
{
- AgentName = "Planner",
- UserGoal = "",
- Response = "",
+ AgentName = router.Name,
+ Response = dialogs.Last().Content,
Function = "route_to_agent"
};
+
/*FirstStagePlan[] items = await GetFirstStagePlanAsync(router, messageId, dialogs);
foreach (var item in items)
@@ -130,7 +130,13 @@ public partial class TwoStageTaskPlanner : IRoutingPlaner
if (message.StopCompletion || _isTaskCompleted)
{
- context.Empty(reason: $"Agent queue is cleared by {nameof(TwoStagePlanner)}");
+ context.Empty(reason: $"Agent queue is cleared by {nameof(TwoStageTaskPlanner)}");
+ return false;
+ }
+
+ if (dialogs.Last().Role == AgentRole.Assistant)
+ {
+ context.Empty();
return false;
}
@@ -149,47 +155,6 @@ public partial class TwoStageTaskPlanner : IRoutingPlaner
return content;
}
- private async Task GetFirstStagePlanAsync(Agent router, string messageId, List dialogs)
- {
- /*var fn = _services.GetRequiredService();
- await fn.InvokeFunction("plan_primary_stage", message);
- var items = message.Content.JsonArrayContent();*/
-
- var firstStagePlanPrompt = await GetFirstStagePlanPrompt(router);
-
- var plan = new FirstStagePlan[0];
-
- var llmProviderService = _services.GetRequiredService();
- var provider = router.LlmConfig.Provider ?? "openai";
- var model = llmProviderService.GetProviderModel(provider, router.LlmConfig.Model ?? "gpt-4o");
-
- // chat completion
- var completion = CompletionProvider.GetChatCompletion(_services,
- provider: provider,
- model: model.Name);
-
- string text = string.Empty;
-
- try
- {
- var response = await completion.GetChatCompletions(new Agent
- {
- Id = router.Id,
- Name = nameof(TwoStagePlanner),
- Instruction = firstStagePlanPrompt
- }, dialogs);
-
- text = response.Content;
- plan = response.Content.JsonArrayContent();
- }
- catch (Exception ex)
- {
- _logger.LogError($"{ex.Message}: {text}");
- }
-
- return plan;
- }
-
private async Task GetFirstStagePlanPrompt(Agent router)
{
var template = router.Templates.First(x => x.Name == "two_stage.1st.plan").Content;
@@ -257,7 +222,7 @@ public partial class TwoStageTaskPlanner : IRoutingPlaner
var response = await completion.GetChatCompletions(new Agent
{
Id = router.Id,
- Name = nameof(TwoStagePlanner),
+ Name = nameof(TwoStageTaskPlanner),
Instruction = firstStageSystemPrompt
}, conversations);
diff --git a/src/Plugins/BotSharp.Plugin.Planner/data/agents/282a7128-69a1-44b0-878c-a9159b88f3b9/agent.json b/src/Plugins/BotSharp.Plugin.Planner/data/agents/282a7128-69a1-44b0-878c-a9159b88f3b9/agent.json
index f689f24f..aeabfb9a 100644
--- a/src/Plugins/BotSharp.Plugin.Planner/data/agents/282a7128-69a1-44b0-878c-a9159b88f3b9/agent.json
+++ b/src/Plugins/BotSharp.Plugin.Planner/data/agents/282a7128-69a1-44b0-878c-a9159b88f3b9/agent.json
@@ -8,7 +8,7 @@
"iconUrl": "https://e7.pngegg.com/pngimages/775/350/png-clipart-action-plan-computer-icons-plan-miscellaneous-text-thumbnail.png",
"disabled": false,
"isPublic": true,
- "profiles": [ "tool" ],
+ "profiles": [ "planning" ],
"utilities": [ "two-stage-planner" ],
"llmConfig": {
"provider": "openai",
diff --git a/src/Plugins/BotSharp.Plugin.Planner/data/agents/282a7128-69a1-44b0-878c-a9159b88f3b9/instructions/instruction.liquid b/src/Plugins/BotSharp.Plugin.Planner/data/agents/282a7128-69a1-44b0-878c-a9159b88f3b9/instructions/instruction.liquid
index f6571d18..e5013463 100644
--- a/src/Plugins/BotSharp.Plugin.Planner/data/agents/282a7128-69a1-44b0-878c-a9159b88f3b9/instructions/instruction.liquid
+++ b/src/Plugins/BotSharp.Plugin.Planner/data/agents/282a7128-69a1-44b0-878c-a9159b88f3b9/instructions/instruction.liquid
@@ -8,4 +8,5 @@ Global Knowledge:
{% for k in global_knowledges %}
{{ k }}
{% endfor %}
+=====
{%- endif %}
\ No newline at end of file
diff --git a/src/Plugins/BotSharp.Plugin.SqlDriver/Functions/GetTableDefinitionFn.cs b/src/Plugins/BotSharp.Plugin.SqlDriver/Functions/GetTableDefinitionFn.cs
index 31c3a31e..a9fb5005 100644
--- a/src/Plugins/BotSharp.Plugin.SqlDriver/Functions/GetTableDefinitionFn.cs
+++ b/src/Plugins/BotSharp.Plugin.SqlDriver/Functions/GetTableDefinitionFn.cs
@@ -36,22 +36,14 @@ public class GetTableDefinitionFn : IFunctionCallback
{
try
{
- var sql = $"select * from information_schema.tables where table_name = @tableName";
var escapedTableName = MySqlHelper.EscapeString(table);
+ var sql = $"SHOW CREATE TABLE `{escapedTableName}`";
- var result = connection.QueryFirstOrDefault(sql, new
- {
- tableName = escapedTableName
- });
-
- if (result == null) continue;
-
- sql = $"SHOW CREATE TABLE `{escapedTableName}`";
using var command = new MySqlCommand(sql, connection);
using var reader = command.ExecuteReader();
if (reader.Read())
{
- result = reader.GetString(1);
+ var result = reader.GetString(1);
tableDdls.Add(result);
}
diff --git a/src/Plugins/BotSharp.Plugin.SqlDriver/Services/DbKnowledgeService.cs b/src/Plugins/BotSharp.Plugin.SqlDriver/Services/DbKnowledgeService.cs
index 746798c9..129da04c 100644
--- a/src/Plugins/BotSharp.Plugin.SqlDriver/Services/DbKnowledgeService.cs
+++ b/src/Plugins/BotSharp.Plugin.SqlDriver/Services/DbKnowledgeService.cs
@@ -91,13 +91,13 @@ public class DbKnowledgeService
private string GetTableStructure(string table)
{
var settings = _services.GetRequiredService();
- using var connection = new MySqlConnection(settings.MySqlConnectionString);
- connection.Open();
-
+
var ddl = string.Empty;
var escapedTableName = MySqlHelper.EscapeString(table);
var sql = $"SHOW CREATE TABLE `{escapedTableName}`";
+ using var connection = new MySqlConnection(settings.MySqlConnectionString);
+ connection.Open();
using var command = new MySqlCommand(sql, connection);
using var reader = command.ExecuteReader();
if (reader.Read())
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
index 4f19d591..e75c4709 100644
--- 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
@@ -7,7 +7,7 @@
"updatedDateTime": "2023-11-15T13:49:00Z",
"disabled": false,
"isPublic": true,
- "profiles": [ "tool", "sql" ],
+ "profiles": [ "database" ],
"llmConfig": {
"model": "gpt-4-0125",
"model3": "gpt-35-turbo-1106",
diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioVoiceController.cs b/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioVoiceController.cs
index 8304e3b2..4e37ac78 100644
--- a/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioVoiceController.cs
+++ b/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioVoiceController.cs
@@ -40,7 +40,7 @@ public class TwilioVoiceController : TwilioController
string conversationId = $"TwilioVoice_{request.CallSid}";
var twilio = _services.GetRequiredService();
var url = $"twilio/voice/{conversationId}/receive/0?states={states}";
- var response = twilio.ReturnNoninterruptedInstructions(new List { "twilio/welcome.mp3" }, url, true);
+ var response = twilio.ReturnNoninterruptedInstructions(new List { "twilio/welcome.mp3" }, url, true, timeout: 2);
return TwiML(response);
}
@@ -82,13 +82,16 @@ public class TwilioVoiceController : TwilioController
}
}
+ await messageQueue.EnqueueAsync(callerMessage);
+
response = new VoiceResponse().Redirect(new Uri($"{_settings.CallbackHost}/twilio/voice/{conversationId}/reply/{seqNum}?states={states}"), HttpMethod.Post);
}
else
{
- if (attempts >= 3)
+ if (attempts >= 2)
{
var speechPaths = new List();
+
if (seqNum == 0)
{
speechPaths.Add("twilio/welcome.mp3");
@@ -96,6 +99,7 @@ public class TwilioVoiceController : TwilioController
else
{
var lastRepy = await sessionManager.GetAssistantReplyAsync(conversationId, seqNum - 1);
+ speechPaths.Add($"twilio/say-it-again-{Random.Shared.Next(1, 5)}.mp3");
speechPaths.Add($"twilio/voice/speeches/{conversationId}/{lastRepy.SpeechFileName}");
}
response = twilio.ReturnInstructions(speechPaths, $"twilio/voice/{conversationId}/receive/{seqNum}?states={states}", true);
@@ -103,14 +107,14 @@ public class TwilioVoiceController : TwilioController
else
{
response = twilio.ReturnInstructions(null, $"twilio/voice/{conversationId}/receive/{seqNum}?states={states}&attempts={++attempts}", true);
- }
+ }
}
return TwiML(response);
}
[ValidateRequest]
[HttpPost("twilio/voice/{conversationId}/reply/{seqNum}")]
- public async Task ReplyCallerMessage([FromRoute] string conversationId, [FromRoute] int seqNum,
+ public async Task ReplyCallerMessage([FromRoute] string conversationId, [FromRoute] int seqNum,
[FromQuery] string states, VoiceRequest request)
{
var nextSeqNum = seqNum + 1;
@@ -148,6 +152,8 @@ public class TwilioVoiceController : TwilioController
var fileName = $"indication_{seqNum}_{segIndex}.mp3";
fileStorage.SaveSpeechFile(conversationId, fileName, data);
speechPaths.Add($"twilio/voice/speeches/{conversationId}/{fileName}");
+ // add typing
+ speechPaths.Add($"twilio/typing-{Random.Shared.Next(1, 4)}.mp3");
segIndex++;
}
}
@@ -156,16 +162,20 @@ public class TwilioVoiceController : TwilioController
}
else
{
- response = twilio.ReturnInstructions(new List
+ response = twilio.ReturnInstructions(new List
{
- $"twilio/hold-on-{Random.Shared.Next(1, 5)}.mp3",
- $"twilio/typing-{Random.Shared.Next(2, 4)}.mp3"
+ $"twilio/hold-on-{Random.Shared.Next(1, 6)}.mp3",
+ $"twilio/typing-{Random.Shared.Next(1, 4)}.mp3"
}, $"twilio/voice/{conversationId}/reply/{seqNum}?states={states}", true);
}
}
else
{
- if (reply.ConversationEnd)
+ if (reply.HumanIntervationNeeded)
+ {
+ response = twilio.DialCsrAgent($"twilio/voice/speeches/{conversationId}/{reply.SpeechFileName}");
+ }
+ else if (reply.ConversationEnd)
{
response = twilio.HangUp($"twilio/voice/speeches/{conversationId}/{reply.SpeechFileName}");
}
diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Models/AssistantMessage.cs b/src/Plugins/BotSharp.Plugin.Twilio/Models/AssistantMessage.cs
index d53a9b0b..521dba43 100644
--- a/src/Plugins/BotSharp.Plugin.Twilio/Models/AssistantMessage.cs
+++ b/src/Plugins/BotSharp.Plugin.Twilio/Models/AssistantMessage.cs
@@ -3,6 +3,7 @@ namespace BotSharp.Plugin.Twilio.Models
public class AssistantMessage
{
public bool ConversationEnd { get; set; }
+ public bool HumanIntervationNeeded { get; set; }
public string Content { get; set; }
public string MessageId { get; set; }
public string SpeechFileName { get; set; }
diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioMessageQueueService.cs b/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioMessageQueueService.cs
index 39eac1cf..4679c653 100644
--- a/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioMessageQueueService.cs
+++ b/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioMessageQueueService.cs
@@ -86,6 +86,7 @@ namespace BotSharp.Plugin.Twilio.Services
reply = new AssistantMessage()
{
ConversationEnd = msg.Instruction?.ConversationEnd ?? false,
+ HumanIntervationNeeded = string.Equals("human_intervention_needed", msg.FunctionName),
Content = msg.Content,
MessageId = msg.MessageId
};
diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioService.cs b/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioService.cs
index cecbd3c8..d72f549b 100644
--- a/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioService.cs
+++ b/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioService.cs
@@ -80,7 +80,8 @@ public class TwilioService
SpeechModel = Gather.SpeechModelEnum.PhoneCall,
SpeechTimeout = "auto", // timeout > 0 ? timeout.ToString() : "3",
Timeout = timeout > 0 ? timeout : 3,
- ActionOnEmptyResult = actionOnEmptyResult
+ ActionOnEmptyResult = actionOnEmptyResult,
+ Hints = "Yes, No, Correct"
};
if (!speechPaths.IsNullOrEmpty())
@@ -113,7 +114,7 @@ public class TwilioService
},
Action = new Uri($"{_settings.CallbackHost}/{callbackPath}"),
SpeechModel = Gather.SpeechModelEnum.PhoneCall,
- SpeechTimeout = "auto", // timeout > 0 ? timeout.ToString() : "3",
+ SpeechTimeout = timeout > 0 ? timeout.ToString() : "3",
Timeout = timeout > 0 ? timeout : 3,
ActionOnEmptyResult = actionOnEmptyResult
};
@@ -132,6 +133,17 @@ public class TwilioService
return response;
}
+ public VoiceResponse DialCsrAgent(string speechPath)
+ {
+ var response = new VoiceResponse();
+ if (!string.IsNullOrEmpty(speechPath))
+ {
+ response.Play(new Uri($"{_settings.CallbackHost}/{speechPath}"));
+ }
+ response.Dial(_settings.CsrAgentNumber);
+ return response;
+ }
+
public VoiceResponse HoldOn(int interval, string message = null)
{
var twilioSetting = _services.GetRequiredService();
diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Settings/TwilioSetting.cs b/src/Plugins/BotSharp.Plugin.Twilio/Settings/TwilioSetting.cs
index c7170ee2..bbf4bab3 100644
--- a/src/Plugins/BotSharp.Plugin.Twilio/Settings/TwilioSetting.cs
+++ b/src/Plugins/BotSharp.Plugin.Twilio/Settings/TwilioSetting.cs
@@ -10,4 +10,5 @@ public class TwilioSetting
public string ApiSecret { get; set; }
public string CallbackHost { get; set; }
public string AgentId { get; set; }
+ public string CsrAgentNumber { get; set; }
}