diff --git a/docs/channels/components.md b/docs/channels/components.md index 3754a1c3..89ab8cb4 100644 --- a/docs/channels/components.md +++ b/docs/channels/components.md @@ -1,6 +1,6 @@ # Messaging Components -Conversations are a lot more than simple text messages when you are building a AI chatbot. In addition to text, the `BotSharp`` allows you to send rich-media, like audio, video, and images, and provides a set of structured messaging options in the form of message templates, quick replies, buttons and more. The UI rendering program can render components according to the returned data format. +Conversations are a lot more than simple text messages when you are building a AI chatbot. In addition to text, the `BotSharp` allows you to send rich-media, like audio, video, and images, and provides a set of structured messaging options in the form of message templates, quick replies, buttons and more. The UI rendering program can render components according to the returned data format. ## Text Messages @@ -75,7 +75,7 @@ Message templates are structured message formats used for various purposes to pr ... } ] - } + } } } } diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/IncomingMessageModel.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/IncomingMessageModel.cs index 98381559..903e5d0b 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/IncomingMessageModel.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/IncomingMessageModel.cs @@ -1,36 +1,9 @@ +using BotSharp.Abstraction.Models; + namespace BotSharp.Abstraction.Conversations.Models; -public class IncomingMessageModel +public class IncomingMessageModel : MessageConfig { public string Text { get; set; } = string.Empty; - - public virtual string Channel { get; set; } = string.Empty; - - /// - /// Completion Provider - /// - [JsonPropertyName("provider")] - public virtual string? Provider { get; set; } = null; - - /// - /// Model name - /// - [JsonPropertyName("model")] - public virtual string? Model { get; set; } = null; - - /// - /// The sampling temperature to use that controls the apparent creativity of generated completions. - /// - public float Temperature { get; set; } = 0.5f; - - /// - /// An alternative value to Temperature, called nucleus sampling, that causes - /// the model to consider the results of the tokens with probability mass. - /// - public float SamplingFactor { get; set; } = 0.5f; - - /// - /// Conversation states from input - /// - public List States { get; set; } = new List(); + public virtual string Channel { get; set; } } diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs index fcfada99..0aa0cd04 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs @@ -1,7 +1,12 @@ +using BotSharp.Abstraction.Functions.Models; +using BotSharp.Abstraction.Models; + namespace BotSharp.Abstraction.Conversations.Models; -public class RoleDialogModel +public class RoleDialogModel : ITrackableMessage { + public string MessageId { get; set; } + /// /// user, system, assistant, function /// @@ -36,10 +41,17 @@ public class RoleDialogModel [JsonIgnore(Condition = JsonIgnoreCondition.Always)] public bool StopCompletion { get; set; } + public FunctionCallFromLlm Instruction { get; set; } + + private RoleDialogModel() + { + } + public RoleDialogModel(string role, string text) { Role = role; Content = text; + MessageId = Guid.NewGuid().ToString(); } public override string ToString() diff --git a/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionDef.cs b/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionDef.cs index 153fb473..d89620a9 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionDef.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionDef.cs @@ -4,6 +4,7 @@ public class FunctionDef { public string Name { get; set; } public string Description { get; set; } + public string? Impact { get; set; } public FunctionParametersDef Parameters { get; set; } = new FunctionParametersDef(); public override string ToString() diff --git a/src/Infrastructure/BotSharp.Abstraction/Instructs/Models/InstructResult.cs b/src/Infrastructure/BotSharp.Abstraction/Instructs/Models/InstructResult.cs index 10635152..67bd2039 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Instructs/Models/InstructResult.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Instructs/Models/InstructResult.cs @@ -1,7 +1,10 @@ +using BotSharp.Abstraction.Models; + namespace BotSharp.Abstraction.Instructs.Models; -public class InstructResult +public class InstructResult : ITrackableMessage { + public string MessageId { get; set; } public string Text { get; set; } public object Data { get; set; } public ConversationState States { get; set; } diff --git a/src/Infrastructure/BotSharp.Abstraction/Models/ITrackableMessage.cs b/src/Infrastructure/BotSharp.Abstraction/Models/ITrackableMessage.cs new file mode 100644 index 00000000..5756cfd6 --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Models/ITrackableMessage.cs @@ -0,0 +1,9 @@ +namespace BotSharp.Abstraction.Models; + +/// +/// Define a message ID to extend message-level applications, such as model fees, token usage, and data collection +/// +public interface ITrackableMessage +{ + string MessageId { get; set; } +} diff --git a/src/Infrastructure/BotSharp.Abstraction/Models/MessageConfig.cs b/src/Infrastructure/BotSharp.Abstraction/Models/MessageConfig.cs new file mode 100644 index 00000000..95d72492 --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Models/MessageConfig.cs @@ -0,0 +1,32 @@ +namespace BotSharp.Abstraction.Models; + +public class MessageConfig +{ + /// + /// Completion Provider + /// + [JsonPropertyName("provider")] + public virtual string? Provider { get; set; } = null; + + /// + /// Model name + /// + [JsonPropertyName("model")] + public virtual string? Model { get; set; } = null; + + /// + /// The sampling temperature to use that controls the apparent creativity of generated completions. + /// + public float Temperature { get; set; } = 0.5f; + + /// + /// An alternative value to Temperature, called nucleus sampling, that causes + /// the model to consider the results of the tokens with probability mass. + /// + public float SamplingFactor { get; set; } = 0.5f; + + /// + /// Conversation states from input + /// + public List States { get; set; } = new List(); +} diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingHandler.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingHandler.cs index d86c6298..6c8ae94e 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingHandler.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingHandler.cs @@ -1,5 +1,4 @@ using BotSharp.Abstraction.Functions.Models; -using BotSharp.Abstraction.Models; namespace BotSharp.Abstraction.Routing; @@ -19,5 +18,5 @@ public interface IRoutingHandler void SetDialogs(List dialogs) { } - Task Handle(IRoutingService routing, FunctionCallFromLlm inst); + Task Handle(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message); } diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs index 802f8f73..47744957 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs @@ -8,7 +8,7 @@ public interface IRoutingService void ResetRecursiveCounter(); void RefreshDialogs(); Task GetNextInstruction(); - Task InvokeAgent(string agentId); - Task InstructLoop(); - Task ExecuteOnce(Agent agent); + Task InvokeAgent(string agentId, RoleDialogModel message); + Task InstructLoop(RoleDialogModel message); + Task ExecuteOnce(Agent agent, RoleDialogModel message); } diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingContext.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingContext.cs index 49b38274..b24c7941 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingContext.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingContext.cs @@ -18,8 +18,11 @@ public class RoutingContext /// public string IntentName { get; set; } + /// + /// Agent that can handl user original goal. + /// public string OriginAgentId - => _stack.Last(); + => _stack.Where(x => x != _setting.RouterId).Last(); public string GetCurrentAgentId() { diff --git a/src/Infrastructure/BotSharp.Abstraction/Using.cs b/src/Infrastructure/BotSharp.Abstraction/Using.cs index 87d42791..39ececfe 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Using.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Using.cs @@ -7,4 +7,5 @@ global using System.ComponentModel.DataAnnotations; global using System.Text.Json.Serialization; global using BotSharp.Abstraction.Agents.Models; global using BotSharp.Abstraction.Conversations.Models; -global using BotSharp.Abstraction.Agents.Enums; \ No newline at end of file +global using BotSharp.Abstraction.Agents.Enums; +global using BotSharp.Abstraction.Models; \ No newline at end of file diff --git a/src/Infrastructure/BotSharp.Abstraction/Utilities/StringExtensions.cs b/src/Infrastructure/BotSharp.Abstraction/Utilities/StringExtensions.cs index d62b9ec0..17232920 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Utilities/StringExtensions.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Utilities/StringExtensions.cs @@ -1,3 +1,4 @@ +using System.Text.Json; using System.Text.RegularExpressions; namespace BotSharp.Abstraction.Utilities; @@ -27,4 +28,16 @@ public static class StringExtensions { return str1.Equals(str2, option); } + + public static string JsonContent(this string text) + { + var m = Regex.Match(text, @"\{(?:[^{}]|(?\{)|(?<-open>\}))+(?(open)(?!))\}"); + return m.Success ? m.Value : "{}"; + } + + public static T? JsonContent(this string text) + { + text = JsonContent(text); + return JsonSerializer.Deserialize(text); + } } diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs index 6b749b3b..5912b1e0 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs @@ -4,18 +4,14 @@ namespace BotSharp.Core.Agents.Services; public partial class AgentService { -#if !DEBUG - [MemoryCache(10 * 60)] -#endif + [MemoryCache(10 * 60, PerInstanceCache = true)] public async Task> GetAgents(bool? allowRouting = null) { var agents = _db.GetAgents(allowRouting: allowRouting); return await Task.FromResult(agents); } -#if !DEBUG - [MemoryCache(10 * 60)] -#endif + [MemoryCache(10 * 60, PerInstanceCache = true)] public async Task GetAgent(string id) { var profile = _db.GetAgent(id); diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs index e80b5b1e..387a18e7 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs @@ -8,7 +8,7 @@ namespace BotSharp.Core.Conversations.Services; public partial class ConversationService { public async Task SendMessage(string agentId, - RoleDialogModel incoming, + RoleDialogModel message, Func onMessageReceived, Func onFunctionExecuting, Func onFunctionExecuted) @@ -18,16 +18,16 @@ public partial class ConversationService var agentService = _services.GetRequiredService(); Agent agent = await agentService.LoadAgent(agentId); - var message = $"Received [{agent.Name}] {incoming.Role}: {incoming.Content}"; + var content = $"Received [{agent.Name}] {message.Role}: {message.Content}"; #if DEBUG - Console.WriteLine(message, Color.OrangeRed); + Console.WriteLine(content, Color.OrangeRed); #else - _logger.LogInformation(message); + _logger.LogInformation(content); #endif - incoming.CurrentAgentId = agent.Id; + message.CurrentAgentId = agent.Id; - _storage.Append(_conversationId, incoming); + _storage.Append(_conversationId, message); var hooks = _services.GetServices().ToList(); @@ -37,13 +37,13 @@ public partial class ConversationService hook.SetAgent(agent) .SetConversation(conversation); - await hook.OnMessageReceived(incoming); + await hook.OnMessageReceived(message); // Interrupted by hook - if (incoming.StopCompletion) + if (message.StopCompletion) { - await onMessageReceived(incoming); - _storage.Append(_conversationId, incoming); + await onMessageReceived(message); + _storage.Append(_conversationId, message); return true; } } @@ -52,11 +52,11 @@ public partial class ConversationService var routing = _services.GetRequiredService(); var settings = _services.GetRequiredService(); - var response = agentId == settings.RouterId ? - await routing.InstructLoop() : - await routing.ExecuteOnce(agent); + var ret = agentId == settings.RouterId ? + await routing.InstructLoop(message) : + await routing.ExecuteOnce(agent, message); - await HandleAssistantMessage(response, onMessageReceived); + await HandleAssistantMessage(message, onMessageReceived); var statistics = _services.GetRequiredService(); statistics.PrintStatistics(); @@ -64,7 +64,7 @@ public partial class ConversationService routing.ResetRecursiveCounter(); routing.RefreshDialogs(); - return true; + return ret; } private async Task GetConversationRecord(string agentId) diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs index 8f3a865e..db6fc90a 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs @@ -54,8 +54,6 @@ public partial class ConversationService : IConversationService public async Task NewConversation(Conversation sess) { var db = _services.GetRequiredService(); - var dbSettings = _services.GetRequiredService(); - var conversationSettings = _services.GetRequiredService(); var user = db.GetUserByExternalId(_user.Id); var foundUserId = user?.Id ?? string.Empty; @@ -80,11 +78,11 @@ public partial class ConversationService : IConversationService throw new NotImplementedException(); } - public List GetDialogHistory(int lastCount = 20) + public List GetDialogHistory(int lastCount = 50) { var dialogs = _storage.GetDialogs(_conversationId); return dialogs - .Where(x => x.CreatedAt > DateTime.UtcNow.AddHours(-8)) + .Where(x => x.CreatedAt > DateTime.UtcNow.AddHours(-24)) .TakeLast(lastCount) .ToList(); } diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs index 2d8af0ad..3d8b3085 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs @@ -6,19 +6,13 @@ namespace BotSharp.Core.Conversations.Services; public class ConversationStorage : IConversationStorage { private readonly BotSharpDatabaseSettings _dbSettings; - private readonly AgentSettings _agentSettings; private readonly IServiceProvider _services; - private readonly IUserIdentity _user; public ConversationStorage( BotSharpDatabaseSettings dbSettings, - AgentSettings agentSettings, - IServiceProvider services, - IUserIdentity user) + IServiceProvider services) { _dbSettings = dbSettings; - _agentSettings = agentSettings; _services = services; - _user = user; } public void Append(string conversationId, RoleDialogModel dialog) @@ -32,7 +26,7 @@ public class ConversationStorage : IConversationStorage { var args = dialog.FunctionArgs.Replace("\r", " ").Replace("\n", " ").Trim(); - sb.AppendLine($"{dialog.CreatedAt}|{dialog.Role}|{agentId}|{dialog.FunctionName}|{args}"); + sb.AppendLine($"{dialog.CreatedAt}|{dialog.Role}|{agentId}|{dialog.MessageId}"); var content = dialog.Content; content = content.Replace("\r", " ").Replace("\n", " ").Trim(); @@ -44,9 +38,7 @@ public class ConversationStorage : IConversationStorage } else { - var agentName = db.GetAgent(agentId)?.Name; - - sb.AppendLine($"{dialog.CreatedAt}|{dialog.Role}|{agentId}|{agentName}|"); + sb.AppendLine($"{dialog.CreatedAt}|{dialog.Role}|{agentId}|{dialog.MessageId}"); var content = dialog.Content.Replace("\r", " ").Replace("\n", " ").Trim(); if (string.IsNullOrEmpty(content)) { @@ -73,15 +65,13 @@ public class ConversationStorage : IConversationStorage var createdAt = DateTime.Parse(meta.Split('|')[0]); var role = meta.Split('|')[1]; var currentAgentId = meta.Split('|')[2]; - var funcName = meta.Split('|')[3]; - var funcArgs= meta.Split('|')[4]; + var messageId = meta.Split('|')[3]; var text = dialog.Substring(4); results.Add(new RoleDialogModel(role, text) { CurrentAgentId = currentAgentId, - FunctionName = funcName, - FunctionArgs = funcArgs, + MessageId = messageId, Content = text, CreatedAt = createdAt }); diff --git a/src/Infrastructure/BotSharp.Core/Instructs/InstructService.cs b/src/Infrastructure/BotSharp.Core/Instructs/InstructService.cs index bb328753..8ee49eac 100644 --- a/src/Infrastructure/BotSharp.Core/Instructs/InstructService.cs +++ b/src/Infrastructure/BotSharp.Core/Instructs/InstructService.cs @@ -33,6 +33,7 @@ public partial class InstructService : IInstructService { return new InstructResult { + MessageId = message.MessageId, Text = message.Content }; } @@ -42,6 +43,7 @@ public partial class InstructService : IInstructService var result = await completer.GetCompletion(agent.Instruction); var response = new InstructResult { + MessageId = message.MessageId, Text = result }; diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository.cs index 4d862e7a..8aed5989 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository.cs @@ -5,7 +5,6 @@ using BotSharp.Abstraction.Users.Models; using BotSharp.Abstraction.Agents.Models; using MongoDB.Driver; using BotSharp.Abstraction.Routing.Models; -using Amazon.Util; namespace BotSharp.Core.Repository; @@ -373,13 +372,7 @@ public class FileRepository : IBotSharpRepository var functionFile = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId, "functions.json"); - var functions = new List(); - foreach (var function in inputFunctions) - { - functions.Add(JsonSerializer.Serialize(function, _options)); - } - - var functionText = JsonSerializer.Serialize(functions, _options); + var functionText = JsonSerializer.Serialize(inputFunctions, _options); File.WriteAllText(functionFile, functionText); } @@ -493,9 +486,6 @@ public class FileRepository : IBotSharpRepository return responses; } -#if !DEBUG - [MemoryCache(10 * 60)] -#endif public Agent? GetAgent(string agentId) { var agentDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir); diff --git a/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs b/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs index dcfe47e4..fd916b12 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs @@ -66,14 +66,11 @@ public class RouteToAgentFn : IFunctionCallback else { message.CurrentAgentId = targetAgent.Id; - message.Content = $"Routing to {args.AgentName}"; } } _context.Push(message.CurrentAgentId); - // Set default execution data - message.Data = JsonSerializer.Deserialize(message.FunctionArgs); return true; } diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/ContinueExecuteTaskRoutingHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/ContinueExecuteTaskRoutingHandler.cs index 984651f0..1c809ef4 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/ContinueExecuteTaskRoutingHandler.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Handlers/ContinueExecuteTaskRoutingHandler.cs @@ -26,18 +26,15 @@ public class ContinueExecuteTaskRoutingHandler : RoutingHandlerBase, IRoutingHan { } - public async Task Handle(IRoutingService routing, FunctionCallFromLlm inst) + public async Task Handle(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message) { var db = _services.GetRequiredService(); var record = db.GetAgents(inst.AgentName).FirstOrDefault(); - var result = new RoleDialogModel(AgentRole.Function, inst.Question) - { - FunctionName = inst.Function, - FunctionArgs = JsonSerializer.Serialize(inst.Arguments), - CurrentAgentId = record.Id - }; + message.FunctionName = inst.Function; + message.CurrentAgentId = record.Id; + message.FunctionArgs = JsonSerializer.Serialize(inst.Arguments); - return result; + return true; } } diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/ConversationEndRoutingHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/ConversationEndRoutingHandler.cs index 44563f42..97eafa46 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/ConversationEndRoutingHandler.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Handlers/ConversationEndRoutingHandler.cs @@ -24,14 +24,11 @@ public class ConversationEndRoutingHandler : RoutingHandlerBase, IRoutingHandler { } - public async Task Handle(IRoutingService routing, FunctionCallFromLlm inst) + + public async Task Handle(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message) { - var result = new RoleDialogModel(AgentRole.Assistant, inst.Response) - { - CurrentAgentId = _settings.RouterId, - FunctionName = inst.Function, - Data = inst - }; + message.Content = inst.Response; + message.FunctionName = inst.Function; var hooks = _services.GetServices() .OrderBy(x => x.Priority) @@ -39,9 +36,9 @@ public class ConversationEndRoutingHandler : RoutingHandlerBase, IRoutingHandler foreach (var hook in hooks) { - await hook.OnConversationEnding(result); + await hook.OnConversationEnding(message); } - return result; + return true; } } diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/HumanInterventionNeededHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/HumanInterventionNeededHandler.cs index 3df04f69..671dc644 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/HumanInterventionNeededHandler.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Handlers/HumanInterventionNeededHandler.cs @@ -9,30 +9,24 @@ public class HumanInterventionNeededHandler : RoutingHandlerBase, IRoutingHandle { public string Name => "human_intervention_needed"; - public string Description => "Reach out to a real human or customer representative."; - - private readonly RoutingSettings _settings; + public string Description => "Reach out to human being, customer service or customer representative."; public List Parameters => new List { - new NameDesc("reason", "why need customer service representative (human being)"), + new NameDesc("reason", "why need customer service"), new NameDesc("response", "response content to user") }; public HumanInterventionNeededHandler(IServiceProvider services, ILogger logger, RoutingSettings settings) : base(services, logger, settings) { - _settings = settings; + } - public async Task Handle(IRoutingService routing, FunctionCallFromLlm inst) + public async Task Handle(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message) { - var result = new RoleDialogModel(AgentRole.Assistant, inst.Response) - { - CurrentAgentId = _settings.RouterId, - FunctionName = inst.Function, - Data = inst - }; + message.Role = AgentRole.Assistant; + message.Content = inst.Response; var hooks = _services.GetServices() .OrderBy(x => x.Priority) @@ -40,9 +34,9 @@ public class HumanInterventionNeededHandler : RoutingHandlerBase, IRoutingHandle foreach (var hook in hooks) { - await hook.OnHumanInterventionNeeded(result); + await hook.OnHumanInterventionNeeded(message); } - return result; + return true; } } diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/InterruptTaskExecutionRoutingHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/InterruptTaskExecutionRoutingHandler.cs index 096f9d61..76d18be3 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/InterruptTaskExecutionRoutingHandler.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Handlers/InterruptTaskExecutionRoutingHandler.cs @@ -24,14 +24,11 @@ public class InterruptTaskExecutionRoutingHandler : RoutingHandlerBase, IRouting { } - public async Task Handle(IRoutingService routing, FunctionCallFromLlm inst) + public async Task Handle(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message) { - var result = new RoleDialogModel(AgentRole.User, inst.Reason) - { - FunctionName = inst.Function, - StopCompletion = true - }; + message.FunctionName = inst.Function; + message.StopCompletion = true; - return result; + return true; } } diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/ResponseToUserRoutingHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/ResponseToUserRoutingHandler.cs index ec1c5bcf..cb480e56 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/ResponseToUserRoutingHandler.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Handlers/ResponseToUserRoutingHandler.cs @@ -24,15 +24,11 @@ public class ResponseToUserRoutingHandler : RoutingHandlerBase, IRoutingHandler { } - public async Task Handle(IRoutingService routing, FunctionCallFromLlm inst) + public async Task Handle(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message) { - var result = new RoleDialogModel(AgentRole.Assistant, inst.Response) - { - CurrentAgentId = _settings.RouterId, - FunctionName = inst.Function, - Data = inst, - StopCompletion = true - }; - return result; + message.Content = inst.Response; + message.StopCompletion = true; + message.Role = AgentRole.Assistant; + return true; } } diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/RetrieveDataFromAgentRoutingHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/RetrieveDataFromAgentRoutingHandler.cs index d4492d2b..3b30c19d 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/RetrieveDataFromAgentRoutingHandler.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Handlers/RetrieveDataFromAgentRoutingHandler.cs @@ -27,14 +27,12 @@ public class RetrieveDataFromAgentRoutingHandler : RoutingHandlerBase, IRoutingH { } - public async Task Handle(IRoutingService routing, FunctionCallFromLlm inst) + public async Task Handle(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message) { // Retrieve information from specific agent var db = _services.GetRequiredService(); var record = db.GetAgents(inst.AgentName).FirstOrDefault(); - var response = await routing.InvokeAgent(record.Id); - - inst.Response = response.Content; + var ret = await routing.InvokeAgent(record.Id, message); /*_dialogs.Add(new RoleDialogModel(AgentRole.Assistant, inst.Parameters.Question) { @@ -45,6 +43,7 @@ public class RetrieveDataFromAgentRoutingHandler : RoutingHandlerBase, IRoutingH /*_dialogs.Add(new RoleDialogModel(AgentRole.Function, inst.Parameters.Answer) { + MessageId = inst.MessageId, FunctionName = inst.Function, FunctionArgs = JsonSerializer.Serialize(inst.Parameters.Arguments), ExecutionResult = inst.Parameters.Answer, @@ -52,11 +51,11 @@ public class RetrieveDataFromAgentRoutingHandler : RoutingHandlerBase, IRoutingH CurrentAgentId = record.Id });*/ - _router.Instruction += $"\r\n{AgentRole.Function}: {response.Content}"; + _router.Instruction += $"\r\n{AgentRole.Function}: {message.Content}"; // Got the response from agent, then send to reasoner again to make the decision // inst = await GetNextInstructionFromReasoner($"What's the next step based on user's original goal and function result?"); - return null; + return true; } } diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs index d4fba5ff..daa4e734 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs @@ -28,24 +28,15 @@ public class RouteToAgentRoutingHandler : RoutingHandlerBase, IRoutingHandler { } - public async Task Handle(IRoutingService routing, FunctionCallFromLlm inst) + public async Task Handle(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message) { var context = _services.GetRequiredService(); - var function = _services.GetServices().FirstOrDefault(x => x.Name == inst.Function); - var message = new RoleDialogModel(AgentRole.Function, inst.Question) - { - FunctionName = inst.Function, - FunctionArgs = JsonSerializer.Serialize(inst), - CurrentAgentId = context.GetCurrentAgentId(), - }; - + message.FunctionArgs = JsonSerializer.Serialize(inst); var ret = await function.Execute(message); - var result = await routing.InvokeAgent(context.GetCurrentAgentId()); - // Keep last message data for debug - result.Data = result.Data ?? message.Data; - result.FunctionName = result.FunctionName ?? message.FunctionName; - return result; + ret = await routing.InvokeAgent(context.GetCurrentAgentId(), message); + + return true; } } diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/TaskEndRoutingHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/TaskEndRoutingHandler.cs index 9190bba5..edb2cfc9 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/TaskEndRoutingHandler.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Handlers/TaskEndRoutingHandler.cs @@ -23,24 +23,17 @@ public class TaskEndRoutingHandler : RoutingHandlerBase, IRoutingHandler { } - public async Task Handle(IRoutingService routing, FunctionCallFromLlm inst) + public async Task Handle(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message) { - var result = new RoleDialogModel(AgentRole.Assistant, inst.Response) - { - CurrentAgentId = _settings.RouterId, - FunctionName = inst.Function, - Data = inst - }; - var hooks = _services.GetServices() .OrderBy(x => x.Priority) .ToList(); foreach (var hook in hooks) { - await hook.OnCurrentTaskEnding(result); + await hook.OnCurrentTaskEnding(message); } - return result; + return true; } } diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.GetNextInstruction.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.GetNextInstruction.cs index c08230ad..e217dd89 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.GetNextInstruction.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.GetNextInstruction.cs @@ -56,15 +56,25 @@ public partial class RoutingService model: _settings.Model); int retryCount = 0; + var agentService = _services.GetRequiredService(); + var dialogs = Dialogs; while (retryCount < 3) { try { var conversation = ""; - foreach (var dialog in _dialogs.TakeLast(20)) + + foreach (var dialog in dialogs.TakeLast(50)) { - conversation += $"{dialog.Role}: {dialog.Content}\r\n"; + var role = dialog.Role; + if (role != AgentRole.User) + { + var agent = await agentService.GetAgent(dialog.CurrentAgentId); + role = agent.Name; + } + + conversation += $"{role}: {dialog.Content}\r\n"; } content = $"{conversation}\r\n###\r\n{content}"; @@ -73,9 +83,7 @@ public partial class RoutingService new RoleDialogModel(AgentRole.User, content) }); - var pattern = @"\{(?:[^{}]|(?\{)|(?<-open>\}))+(?(open)(?!))\}"; - response.Content = Regex.Match(response.Content, pattern).Value; - args = JsonSerializer.Deserialize(response.Content); + args = response.Content.JsonContent(); break; } catch (Exception ex) @@ -113,9 +121,6 @@ public partial class RoutingService return args; } -#if !DEBUG - [MemoryCache(10 * 60)] -#endif private string GetNextStepPrompt() { var template = _routerInstance.Router.Templates.First(x => x.Name == "next_step_prompt").Content; diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeAgent.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeAgent.cs index 8147f437..f19bee3f 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeAgent.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeAgent.cs @@ -8,13 +8,13 @@ public partial class RoutingService { const int MAXIMUM_RECURSION_DEPTH = 3; private int _currentRecursionDepth = 0; - public async Task InvokeAgent(string agentId) + public async Task InvokeAgent(string agentId, RoleDialogModel message) { _currentRecursionDepth++; if (_currentRecursionDepth > MAXIMUM_RECURSION_DEPTH) { _logger.LogWarning($"Current recursive call depth greater than {MAXIMUM_RECURSION_DEPTH}, which will cause unexpected result."); - return Dialogs.Last(); + return false; } var agentService = _services.GetRequiredService(); @@ -23,50 +23,56 @@ public partial class RoutingService var settings = _services.GetRequiredService(); var chatCompletion = CompletionProvider.GetChatCompletion(_services, provider: settings.Provider, model: settings.Model); RoleDialogModel response = chatCompletion.GetChatCompletions(agent, Dialogs); + message.Role = response.Role; if (response.Role == AgentRole.Function) { - return await InvokeFunction(agent, response); + message.FunctionName = response.FunctionName; + message.FunctionArgs = response.FunctionArgs; + + await InvokeFunction(agent, message); } else { - return response; + message.Content = response.Content; } + + return true; } - private async Task InvokeFunction(Agent agent, RoleDialogModel response) + private async Task InvokeFunction(Agent agent, RoleDialogModel message) { // execute function // Save states - SaveStateByArgs(JsonSerializer.Deserialize(response.FunctionArgs)); + SaveStateByArgs(JsonSerializer.Deserialize(message.FunctionArgs)); var conversationService = _services.GetRequiredService(); // Call functions - await conversationService.CallFunctions(response); + await conversationService.CallFunctions(message); - Dialogs.Add(response); + Dialogs.Add(message); // Pass execution result to LLM to get response - if (!response.StopCompletion) + if (!message.StopCompletion) { // Find response template var templateService = _services.GetRequiredService(); - var responseTemplate = await templateService.RenderFunctionResponse(agent.Id, response); + var responseTemplate = await templateService.RenderFunctionResponse(agent.Id, message); if (!string.IsNullOrEmpty(responseTemplate)) { - response.Role = AgentRole.Assistant; - response.Content = responseTemplate.Trim(); + message.Role = AgentRole.Assistant; + message.Content = responseTemplate.Trim(); } else { - response = await InvokeAgent(response.CurrentAgentId); + await InvokeAgent(message.CurrentAgentId, message); } } else { - response.Role = AgentRole.Assistant; + message.Role = AgentRole.Assistant; } - return response; + return message; } } diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs index 9159434d..b7073f04 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs @@ -46,38 +46,29 @@ public partial class RoutingService : IRoutingService _routerInstance = routerInstance; } - - public async Task ExecuteOnce(Agent agent) + public async Task ExecuteOnce(Agent agent, RoleDialogModel message) { - var message = Dialogs.Last().Content; - var handlers = _services.GetServices(); var handler = handlers.FirstOrDefault(x => x.Name == "route_to_agent"); handler.SetDialogs(Dialogs); + var result = await handler.Handle(this, new FunctionCallFromLlm { Function = "route_to_agent", - Question = message, - Reason = message, + Question = message.Content, + Reason = message.Content, AgentName = agent.Name - }); + }, message); return result; } - public async Task InstructLoop() + public async Task InstructLoop(RoleDialogModel message) { _routerInstance.Load(); var router = _routerInstance.Router; - var result = new RoleDialogModel(AgentRole.Assistant, "Can you repeat your request again?") - { - CurrentAgentId = router.Id - }; - - var message = Dialogs.Last().Content; - var handlers = _services.GetServices(); int loopCount = 0; @@ -87,7 +78,8 @@ public partial class RoutingService : IRoutingService loopCount++; var inst = await GetNextInstruction(); - inst.Question = inst.Question ?? message; + message.Instruction = inst; + inst.Question = message.Content; var handler = handlers.FirstOrDefault(x => x.Name == inst.Function); if (handler == null) @@ -98,12 +90,18 @@ public partial class RoutingService : IRoutingService handler.SetRouter(router); handler.SetDialogs(Dialogs); - result = await handler.Handle(this, inst); + message.FunctionName = inst.Function; + message.Role = AgentRole.Function; + message.FunctionArgs = inst.Arguments == null ? "{}" : JsonSerializer.Serialize(inst.Arguments); + + await handler.Handle(this, inst, message); + + inst.Response = message.Content; stop = !_settings.EnableReasoning; } - return result; + return true; } protected void SaveStateByArgs(JsonDocument args) diff --git a/src/Infrastructure/BotSharp.Core/Templating/ResponseTemplateService.cs b/src/Infrastructure/BotSharp.Core/Templating/ResponseTemplateService.cs index cb536e0e..6bde9ce6 100644 --- a/src/Infrastructure/BotSharp.Core/Templating/ResponseTemplateService.cs +++ b/src/Infrastructure/BotSharp.Core/Templating/ResponseTemplateService.cs @@ -35,6 +35,10 @@ public class ResponseTemplateService : IResponseTemplateService // Convert args and execute data to dictionary var dict = new Dictionary(); + // Populate states + var state = _services.GetRequiredService(); + state.GetStates().Select(x => dict[x.Key] = x.Value).ToList(); + if (message.FunctionArgs != null) { ExtractArgs(JsonSerializer.Deserialize(message.FunctionArgs), dict); diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs index fb73fdf6..5fb5cd7c 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs @@ -1,5 +1,6 @@ using BotSharp.Abstraction.ApiAdapters; using BotSharp.Abstraction.Conversations.Models; +using BotSharp.Abstraction.Models; using BotSharp.OpenAPI.ViewModels.Conversations; namespace BotSharp.OpenAPI.Controllers; @@ -19,15 +20,17 @@ public class ConversationController : ControllerBase, IApiAdapter } [HttpPost("/conversation/{agentId}")] - public async Task NewConversation([FromRoute] string agentId) + public async Task NewConversation([FromRoute] string agentId, [FromBody] MessageConfig config) { var service = _services.GetRequiredService(); - var sess = new Conversation + var conv = new Conversation { AgentId = agentId }; - sess = await service.NewConversation(sess); - return ConversationViewModel.FromSession(sess); + conv = await service.NewConversation(conv); + config.States.ForEach(x => conv.States[x.Split('=')[0]] = x.Split('=')[1]); + + return ConversationViewModel.FromSession(conv); } [HttpDelete("/conversation/{agentId}/{conversationId}")] @@ -50,13 +53,11 @@ public class ConversationController : ControllerBase, IApiAdapter .SetState("sampling_factor", input.SamplingFactor); var response = new MessageResponseModel(); - var stackMsg = new List(); - - await conv.SendMessage(agentId, - new RoleDialogModel("user", input.Text), + var inputMsg = new RoleDialogModel("user", input.Text); + await conv.SendMessage(agentId, inputMsg, async msg => { - stackMsg.Add(msg); + }, async fnExecuting => { @@ -64,15 +65,14 @@ public class ConversationController : ControllerBase, IApiAdapter }, async fnExecuted => { - response.Function = fnExecuted.FunctionName; - response.Data = fnExecuted.Data; - response.RichContent = fnExecuted.RichContent; + }); - response.Text = string.Join("\r\n", stackMsg.Select(x => x.Content)); - response.Data = response.Data ?? stackMsg.Last().Data; - response.Function = stackMsg.Last().FunctionName; - response.RichContent = response.RichContent ?? stackMsg.Last().RichContent; + response.MessageId = inputMsg.MessageId; + response.Text = inputMsg.Content; + response.Data = inputMsg.Data; + response.Function = inputMsg.FunctionName; + response.Instruction = inputMsg.Instruction; return response; } diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/MessageResponseModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/MessageResponseModel.cs index f5045ed1..4dcf0c58 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/MessageResponseModel.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/MessageResponseModel.cs @@ -1,9 +1,14 @@ +using BotSharp.Abstraction.Functions.Models; +using BotSharp.Abstraction.Models; +using BotSharp.Abstraction.Routing.Models; + namespace BotSharp.OpenAPI.ViewModels.Conversations; -public class MessageResponseModel +public class MessageResponseModel : ITrackableMessage { + public string MessageId { get; set; } public string Text { get; set; } public string Function { get; set; } public object Data { get; set; } - public object? RichContent { get; set; } + public FunctionCallFromLlm Instruction { get; set; } } diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Models/AgentResponseMongoElement.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/AgentResponseMongoElement.cs index ee556549..26ddebbc 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Models/AgentResponseMongoElement.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/AgentResponseMongoElement.cs @@ -2,6 +2,7 @@ using BotSharp.Abstraction.Agents.Models; namespace BotSharp.Plugin.MongoStorage.Models; +[BsonIgnoreExtraElements] public class AgentResponseMongoElement { public string Prefix { get; set; } diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Models/AgentTemplateMongoElement.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/AgentTemplateMongoElement.cs index 719a11d9..847ec5c9 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Models/AgentTemplateMongoElement.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/AgentTemplateMongoElement.cs @@ -2,6 +2,7 @@ using BotSharp.Abstraction.Agents.Models; namespace BotSharp.Plugin.MongoStorage.Models; +[BsonIgnoreExtraElements] public class AgentTemplateMongoElement { public string Name { get; set; } diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Models/FunctionDefMongoElement.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/FunctionDefMongoElement.cs index ec9699c0..5910661f 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Models/FunctionDefMongoElement.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/FunctionDefMongoElement.cs @@ -3,10 +3,12 @@ using System.Text.Json; namespace BotSharp.Plugin.MongoStorage.Models; +[BsonIgnoreExtraElements] public class FunctionDefMongoElement { public string Name { get; set; } public string Description { get; set; } + public string? Impact { get; set; } public FunctionParametersDefMongoElement Parameters { get; set; } = new FunctionParametersDefMongoElement(); public FunctionDefMongoElement() @@ -20,6 +22,7 @@ public class FunctionDefMongoElement { Name = function.Name, Description = function.Description, + Impact = function.Impact, Parameters = new FunctionParametersDefMongoElement { Type = function.Parameters.Type, @@ -35,6 +38,7 @@ public class FunctionDefMongoElement { Name = mongoFunction.Name, Description = mongoFunction.Description, + Impact = mongoFunction.Impact, Parameters = new FunctionParametersDef { Type = mongoFunction.Parameters.Type, diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Models/RoutingRuleMongoElement.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/RoutingRuleMongoElement.cs index 9f644c68..1a40b0f7 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Models/RoutingRuleMongoElement.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/RoutingRuleMongoElement.cs @@ -2,6 +2,7 @@ using BotSharp.Abstraction.Routing.Models; namespace BotSharp.Plugin.MongoStorage.Models; +[BsonIgnoreExtraElements] public class RoutingRuleMongoElement { public string Field { get; set; } diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Using.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Using.cs index 5debd75f..ca13f204 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Using.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Using.cs @@ -10,4 +10,5 @@ global using BotSharp.Abstraction.Plugins; global using Microsoft.Extensions.Configuration; global using Microsoft.Extensions.DependencyInjection; global using MongoDB.Bson; -global using MongoDB.Driver; \ No newline at end of file +global using MongoDB.Driver; +global using MongoDB.Bson.Serialization.Attributes; \ No newline at end of file diff --git a/src/WebStarter/WebStarter.csproj b/src/WebStarter/WebStarter.csproj index b05729a7..6723a4da 100644 --- a/src/WebStarter/WebStarter.csproj +++ b/src/WebStarter/WebStarter.csproj @@ -5,6 +5,7 @@ enable enable 4fb8c9df-7975-4926-ba73-46c8ca440691 + False diff --git a/src/WebStarter/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/instruction.liquid b/src/WebStarter/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/instruction.liquid index 1543518d..67cd6d1a 100644 --- a/src/WebStarter/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/instruction.liquid +++ b/src/WebStarter/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/instruction.liquid @@ -2,8 +2,8 @@ You're {{router.name}} ({{router.description}}). Follow these steps to handle us 1. Read the [CONVERSATION] content. 2. Select a appropriate function from [FUNCTIONS]. 3. Determine which agent is suitable to handle this conversation. -4. Re-think about the selected function or agent is the best choice. -5. For agent required arguments, leave it blank if user doesn't provide it. +4. Re-think on whether the function you chose matches the reason. +5. For agent required arguments, leave it as blank object if user doesn't provide it. [FUNCTIONS] {% for handler in routing_handlers %} diff --git a/src/WebStarter/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/next_step_prompt.liquid b/src/WebStarter/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/next_step_prompt.liquid index 24132c96..12de3ffd 100644 --- a/src/WebStarter/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/next_step_prompt.liquid +++ b/src/WebStarter/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/next_step_prompt.liquid @@ -1 +1,4 @@ -What is the next step based on the CONVERSATION? Response must be in appropriate JSON format. \ No newline at end of file +What is the next step based on the CONVERSATION? +Response must be in appropriate JSON format. +Route to the Agent that last handled the conversation if necessary. +If user wants to speak to customer service, use function human_intervention_needed. \ No newline at end of file diff --git a/tests/BotSharp.Plugin.PizzaBot/Functions/GetPizzaPricesFn.cs b/tests/BotSharp.Plugin.PizzaBot/Functions/GetPizzaPricesFn.cs index 9e39a155..4fa39c7c 100644 --- a/tests/BotSharp.Plugin.PizzaBot/Functions/GetPizzaPricesFn.cs +++ b/tests/BotSharp.Plugin.PizzaBot/Functions/GetPizzaPricesFn.cs @@ -1,4 +1,5 @@ using BotSharp.Abstraction.Conversations.Models; +using System.Text.Json; namespace BotSharp.Plugin.PizzaBot.Functions; @@ -14,6 +15,7 @@ public class GetPizzaPricesFn : IFunctionCallback cheese_unit_price = 3.5, margherita_unit_price = 3.8, }; + message.Content = JsonSerializer.Serialize(message.Data); return true; } }