diff --git a/README.md b/README.md
index 12d0dc68..fc590da4 100644
--- a/README.md
+++ b/README.md
@@ -49,7 +49,7 @@ PS D:\> npm run dev
Access http://localhost:5015/
-[Online Demo with UI](https://botsharp.azurewebsites.net/)
+[Online Demo with UI](https://botsharp.azurewebsites.net/?wt.mc_id=AI-MVP-5005183)
@@ -112,7 +112,7 @@ BotSharp uses component design, the kernel is kept to a minimum, and business fu
### Documents
-Read the docs: https://botsharp.readthedocs.io
+Read the docs: https://botsharp.readthedocs.io?wt.mc_id=AI-MVP-5005183
If you feel that this project is helpful to you, please Star the project, we would be very grateful.
diff --git a/docs/conf.py b/docs/conf.py
index 2b1636ce..f7eb99ff 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -64,9 +64,9 @@ author = 'Haiping Chen'
# built documents.
#
# The short X.Y version.
-version = '0.23'
+version = '1.1'
# The full version, including alpha/beta/rc tags.
-release = '0.23.0'
+release = '1.1.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs
index 73978b98..72f4ac9e 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs
@@ -35,6 +35,4 @@ public interface IConversationService
List GetDialogHistory(int lastCount = 50);
Task CleanHistory(string agentId);
-
- Task CallFunctions(RoleDialogModel msg);
}
diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.CallFunctions.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.CallFunctions.cs
deleted file mode 100644
index 6b1ab6ca..00000000
--- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.CallFunctions.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-using BotSharp.Abstraction.Functions;
-
-namespace BotSharp.Core.Conversations.Services;
-
-public partial class ConversationService
-{
- public async Task CallFunctions(RoleDialogModel msg)
- {
- // Invoke functions
- var functions = _services.GetServices()
- .Where(x => x.Name == msg.FunctionName)
- .ToList();
-
- if (functions.Count == 0)
- {
- msg.Content = $"Can't find function implementation of {msg.FunctionName}.";
- _logger.LogError(msg.Content);
- return;
- }
-
- var hooks = _services.GetServices()
- .OrderBy(x => x.Priority)
- .ToList();
-
- foreach (var fn in functions)
- {
- // Before executing functions
- foreach (var hook in hooks)
- {
- await hook.OnFunctionExecuting(msg);
- }
-
- try
- {
- // Execute function
- await fn.Execute(msg);
-
- if (string.IsNullOrEmpty(msg.Content))
- {
- msg.Content = msg.Content ?? JsonSerializer.Serialize(msg.Data);
- }
- }
- catch (Exception ex)
- {
- msg.Content = ex.Message;
- msg.StopCompletion = true;
- _logger.LogError(msg.Content);
- }
-
- // After functions have been executed
- foreach (var hook in hooks)
- {
- await hook.OnFunctionExecuted(msg);
- }
- }
- }
-}
diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs
index d471fd9f..67c75a5c 100644
--- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs
+++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs
@@ -1,7 +1,3 @@
-using BotSharp.Abstraction.Repositories;
-using BotSharp.Abstraction.Repositories.Filters;
-using BotSharp.Abstraction.Users.Enums;
-
namespace BotSharp.Core.Conversations.Services;
public partial class ConversationService : IConversationService
diff --git a/src/Infrastructure/BotSharp.Core/Instructs/InstructService.CallFunctions.cs b/src/Infrastructure/BotSharp.Core/Instructs/InstructService.CallFunctions.cs
deleted file mode 100644
index 0e558204..00000000
--- a/src/Infrastructure/BotSharp.Core/Instructs/InstructService.CallFunctions.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-using BotSharp.Abstraction.Functions;
-
-namespace BotSharp.Core.Instructs;
-
-public partial class InstructService
-{
- private async Task CallFunctions(RoleDialogModel msg)
- {
- var hooks = _services.GetServices()
- .OrderBy(x => x.Priority).ToList();
-
- // Invoke functions
- var functions = _services.GetServices()
- .Where(x => x.Name == msg.FunctionName)
- .ToList();
-
- if (functions.Count == 0)
- {
- msg.Content = $"Can't find function implementation of {msg.FunctionName}.";
- _logger.LogError(msg.Content);
- return;
- }
-
- foreach (var fn in functions)
- {
- // Before executing functions
- foreach (var hook in hooks)
- {
- await hook.OnFunctionExecuting(msg);
- }
-
- try
- {
- // Execute function
- await fn.Execute(msg);
- }
- catch (Exception ex)
- {
- msg.Content = ex.Message;
- msg.StopCompletion = true;
- _logger.LogError(msg.Content);
- }
-
- // After functions have been executed
- foreach (var hook in hooks)
- {
- await hook.OnFunctionExecuted(msg);
- }
- }
- }
-}
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs b/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs
index 55bcdf82..bca532f0 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs
@@ -29,6 +29,7 @@ public class RouteToAgentFn : IFunctionCallback
{
// Correct user goal agent to keep orignal task
var goalAgentInState = states.GetState("user_goal_agent", string.Empty);
+ bool correctToOriginalAgent = false;
if (goalAgentInState == string.Empty)
{
states.SetState("user_goal_agent", args.OriginalAgent, isNeedVersion: true);
@@ -37,6 +38,7 @@ public class RouteToAgentFn : IFunctionCallback
{
// Correct to original agent
args.OriginalAgent = goalAgentInState;
+ correctToOriginalAgent = true;
}
else if (args.OriginalAgent != args.AgentName && args.OriginalAgent != goalAgentInState)
{
@@ -49,7 +51,7 @@ public class RouteToAgentFn : IFunctionCallback
var originalAgent = db.GetAgents(filter).FirstOrDefault();
if (originalAgent != null)
{
- _context.Push(originalAgent.Id, $"user goal agent");
+ _context.Push(originalAgent.Id, $"user goal agent{(correctToOriginalAgent ? " & is corrected" : "")}");
}
}
@@ -90,8 +92,8 @@ public class RouteToAgentFn : IFunctionCallback
var missingfield = HasMissingRequiredField(message, out var agentId);
if (missingfield && message.CurrentAgentId != agentId)
{
- // Stack original Agent
- _context.Push(agentId, reason: "redirection rule");
+ // Stack redirection agent
+ _context.Push(agentId, reason: $"redirection: {message.Content}");
}
}
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs
index 4aae20db..ae440748 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs
@@ -1,7 +1,3 @@
-using BotSharp.Abstraction.Functions;
-using BotSharp.Abstraction.Functions.Models;
-using BotSharp.Abstraction.Routing;
-using BotSharp.Abstraction.Routing.Models;
using BotSharp.Abstraction.Routing.Settings;
namespace BotSharp.Core.Routing.Handlers;
@@ -39,12 +35,10 @@ public class RouteToAgentRoutingHandler : RoutingHandlerBase, IRoutingHandler
public async Task Handle(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message)
{
- var context = _services.GetRequiredService();
- var function = _services.GetServices().FirstOrDefault(x => x.Name == inst.Function);
message.FunctionArgs = JsonSerializer.Serialize(inst);
- var ret = await function.Execute(message);
+ var ret = await routing.InvokeFunction(message.FunctionName, message);
- var agentId = context.GetCurrentAgentId();
+ var agentId = routing.Context.GetCurrentAgentId();
// Update next action agent's name
var agentService = _services.GetRequiredService();
diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeAgent.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeAgent.cs
index ede6ee42..8518d769 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeAgent.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeAgent.cs
@@ -1,5 +1,3 @@
-using BotSharp.Abstraction.Agents.Models;
-using BotSharp.Abstraction.Routing.Models;
using BotSharp.Abstraction.Templating;
namespace BotSharp.Core.Routing;
@@ -57,15 +55,13 @@ public partial class RoutingService
var states = _services.GetRequiredService();
states.SaveStateByArgs(message.FunctionArgs?.JsonContent());
- var conversationService = _services.GetRequiredService();
+ var routing = _services.GetRequiredService();
// Call functions
- await conversationService.CallFunctions(message);
+ await routing.InvokeFunction(message.FunctionName, message);
// Pass execution result to LLM to get response
if (!message.StopCompletion)
{
- var routing = _services.GetRequiredService();
-
// Find response template
var templateService = _services.GetRequiredService();
var responseTemplate = await templateService.RenderFunctionResponse(message.CurrentAgentId, message);
@@ -83,7 +79,7 @@ public partial class RoutingService
content: message.Content));
// Send to Next LLM
- var agentId = routing.GetCurrentAgentId();
+ var agentId = routing.Context.GetCurrentAgentId();
await InvokeAgent(agentId, dialogs);
}
}
diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeFunction.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeFunction.cs
index d1be4254..6ef40c58 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeFunction.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeFunction.cs
@@ -7,16 +7,56 @@ public partial class RoutingService
public async Task InvokeFunction(string name, RoleDialogModel message)
{
var function = _services.GetServices().FirstOrDefault(x => x.Name == name);
- if (function == null) return false;
+ if (function == null)
+ {
+ message.StopCompletion = true;
+ message.Content = $"Can't find function implementation of {message.FunctionName}.";
+ _logger.LogError(message.Content);
+ return false;
+ }
var originalFunctionName = message.FunctionName;
message.FunctionName = name;
message.Role = AgentRole.Function;
message.FunctionArgs = message.FunctionArgs;
- var result = await function.Execute(message);
+
+ var hooks = _services.GetServices()
+ .OrderBy(x => x.Priority)
+ .ToList();
+
+ // Before executing functions
+ foreach (var hook in hooks)
+ {
+ await hook.OnFunctionExecuting(message);
+ }
+
+ bool result = false;
+
+ try
+ {
+ result = await function.Execute(message);
+ }
+ catch (Exception ex)
+ {
+ message.StopCompletion = true;
+ message.Content = ex.Message;
+ _logger.LogError(ex.ToString());
+ }
+
+ // Make sure content has been populated
+ if (string.IsNullOrEmpty(message.Content) && message.Data != null)
+ {
+ message.Content = JsonSerializer.Serialize(message.Data);
+ }
+
+ // After functions have been executed
+ foreach (var hook in hooks)
+ {
+ await hook.OnFunctionExecuted(message);
+ }
// restore original function name
- if (!message.StopCompletion)
+ if (!message.StopCompletion && message.FunctionName != originalFunctionName)
{
message.FunctionName = originalFunctionName;
}
diff --git a/tests/BotSharp.Plugin.PizzaBot/Functions/GetPizzaTypesFn.cs b/tests/BotSharp.Plugin.PizzaBot/Functions/GetPizzaTypesFn.cs
index 436ea4f9..c1694b73 100644
--- a/tests/BotSharp.Plugin.PizzaBot/Functions/GetPizzaTypesFn.cs
+++ b/tests/BotSharp.Plugin.PizzaBot/Functions/GetPizzaTypesFn.cs
@@ -1,4 +1,9 @@
+using BotSharp.Abstraction.Conversations;
using BotSharp.Abstraction.Conversations.Models;
+using BotSharp.Abstraction.Messaging;
+using BotSharp.Abstraction.Messaging.Models.RichContent;
+using BotSharp.Abstraction.Messaging.Models.RichContent.Template;
+using System.Linq;
namespace BotSharp.Plugin.PizzaBot.Functions;
@@ -6,15 +11,40 @@ public class GetPizzaTypesFn : IFunctionCallback
{
public string Name => "get_pizza_types";
+ private readonly IServiceProvider _services;
+ public GetPizzaTypesFn(IServiceProvider services)
+ {
+ _services = services;
+ }
+
public async Task Execute(RoleDialogModel message)
{
- message.Content = "Pepperoni Pizza, Cheese Pizza, Margherita Pizza";
- message.Data = new List
+ var states = _services.GetRequiredService();
+ var pizzaTypes = new List
{
"Pepperoni Pizza",
"Cheese Pizza",
"Margherita Pizza"
};
+ message.Data = pizzaTypes;
+ message.RichContent = new RichContent
+ {
+ Recipient = new Recipient
+ {
+ Id = states.GetConversationId()
+ },
+ Message = new ButtonTemplateMessage
+ {
+ Text = "Please select a pizza type",
+ Buttons = pizzaTypes.Select(x => new ButtonElement
+ {
+ Type = "text",
+ Title = x,
+ Payload = x
+ }).ToArray()
+ }
+ };
+
return true;
}
}
diff --git a/tests/BotSharp.Plugin.PizzaBot/data/agents/8970b1e5-d260-4e2c-90b1-f1415a257c18/agent.json b/tests/BotSharp.Plugin.PizzaBot/data/agents/8970b1e5-d260-4e2c-90b1-f1415a257c18/agent.json
index 3dc3c2fe..4da6bdd3 100644
--- a/tests/BotSharp.Plugin.PizzaBot/data/agents/8970b1e5-d260-4e2c-90b1-f1415a257c18/agent.json
+++ b/tests/BotSharp.Plugin.PizzaBot/data/agents/8970b1e5-d260-4e2c-90b1-f1415a257c18/agent.json
@@ -7,7 +7,7 @@
"createdDateTime": "2023-08-18T10:39:32.2349685Z",
"updatedDateTime": "2023-08-18T14:39:32.2349686Z",
"iconUrl": "https://cdn-icons-png.flaticon.com/512/6978/6978255.png",
- "disabled": true,
+ "disabled": false,
"isPublic": true,
"profiles": [ "pizza" ],
"routingRules": [
diff --git a/tests/BotSharp.Plugin.PizzaBot/data/agents/b284db86-e9c2-4c25-a59e-4649797dd130/agent.json b/tests/BotSharp.Plugin.PizzaBot/data/agents/b284db86-e9c2-4c25-a59e-4649797dd130/agent.json
index 949e201c..4f606251 100644
--- a/tests/BotSharp.Plugin.PizzaBot/data/agents/b284db86-e9c2-4c25-a59e-4649797dd130/agent.json
+++ b/tests/BotSharp.Plugin.PizzaBot/data/agents/b284db86-e9c2-4c25-a59e-4649797dd130/agent.json
@@ -4,15 +4,7 @@
"createdDateTime": "2023-08-18T14:39:32.2349685Z",
"updatedDateTime": "2023-08-18T14:39:32.2349686Z",
"id": "b284db86-e9c2-4c25-a59e-4649797dd130",
- "disabled": true,
+ "disabled": false,
"isPublic": true,
- "profiles": [ "pizza" ],
- "routingRules": [
- {
- "field": "order_number",
- "description": "order number",
- "type": "string",
- "redirectTo": "c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd"
- }
- ]
+ "profiles": [ "pizza" ]
}
\ No newline at end of file
diff --git a/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/agent.json b/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/agent.json
index 4751fb78..62f069bb 100644
--- a/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/agent.json
+++ b/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/agent.json
@@ -4,7 +4,7 @@
"createdDateTime": "2023-07-26T02:29:25.123224Z",
"updatedDateTime": "2023-07-26T02:29:25.123274Z",
"id": "c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd",
- "disabled": true,
+ "disabled": false,
"isPublic": true,
"profiles": [ "pizza" ]
}
\ No newline at end of file
diff --git a/tests/BotSharp.Plugin.PizzaBot/data/agents/fe8c60aa-b114-4ef3-93cb-a8efeac80f75/agent.json b/tests/BotSharp.Plugin.PizzaBot/data/agents/fe8c60aa-b114-4ef3-93cb-a8efeac80f75/agent.json
index af5d6cd9..1dab7257 100644
--- a/tests/BotSharp.Plugin.PizzaBot/data/agents/fe8c60aa-b114-4ef3-93cb-a8efeac80f75/agent.json
+++ b/tests/BotSharp.Plugin.PizzaBot/data/agents/fe8c60aa-b114-4ef3-93cb-a8efeac80f75/agent.json
@@ -4,7 +4,7 @@
"createdDateTime": "2023-07-26T02:29:25.123224Z",
"updatedDateTime": "2023-07-26T02:29:25.123274Z",
"id": "fe8c60aa-b114-4ef3-93cb-a8efeac80f75",
- "disabled": true,
+ "disabled": false,
"isPublic": true,
"profiles": [ "pizza" ],
"routingRules": [
@@ -13,7 +13,7 @@
"description": "order number",
"type": "string",
"required": true,
- "redirectTo": "c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd"
+ "redirectTo": "b284db86-e9c2-4c25-a59e-4649797dd130"
}
]
}
\ No newline at end of file