From 6fa6aa180dbd3fb8b596483df51585a900c1bf1f Mon Sep 17 00:00:00 2001 From: Haiping Chen Date: Sat, 26 Apr 2025 13:05:15 -0500 Subject: [PATCH] Deprecate routing handler. --- .../Conversations/IConversationHook.cs | 15 --- .../Functions/Models/FunctionCallFromLlm.cs | 9 +- .../Routing/IRoutingHandler.cs | 20 ---- .../Routing/IRoutingService.cs | 2 - .../Routing/Models/ResponseUserArgs.cs | 7 ++ .../Routing/Models/RoutingArgs.cs | 24 +---- .../BotSharp.Core/BotSharpCoreExtensions.cs | 11 --- .../ConversationService.SendMessage.cs | 8 -- .../Routing/Functions/ResponseToUserFn.cs | 4 +- .../ContinueExecuteTaskRoutingHandler.cs | 50 ---------- .../InterruptTaskExecutionRoutingHandler.cs | 37 ------- .../RetrieveDataFromAgentRoutingHandler.cs | 59 ----------- .../Handlers/RouteToAgentRoutingHandler.cs | 99 ------------------- .../Routing/Hooks/RoutingAgentHook.cs | 1 - .../Routing/Reasoning/HFReasoner.cs | 38 ++----- .../Routing/Reasoning/InstructExecutor.cs | 48 +++++++-- .../Routing/Reasoning/NaiveReasoner.cs | 47 ++------- .../Reasoning/OneStepForwardReasoner.cs | 44 +++------ .../Routing/RoutingService.InstructLoop.cs | 9 +- .../BotSharp.Core/Routing/RoutingService.cs | 23 +---- .../functions/response_to_user.json | 7 +- .../functions/route_to_agent.json | 1 - .../instructions/instruction.liquid | 15 --- .../Sequential/SequentialPlanner.cs | 53 ++++------ .../SqlGeneration/SqlGenerationPlanner.cs | 6 +- .../TwoStaging/TwoStageTaskPlanner.cs | 6 +- src/WebStarter/appsettings.json | 4 +- .../BotSharp.Plugin.PizzaBot.csproj | 7 +- .../Functions/PlaceOrderFn.cs | 6 +- .../agent.json | 6 +- .../agent.json | 2 +- .../functions/get_order_status.json | 2 +- .../agent.json | 2 +- .../{place_an_order.json => place_order.json} | 2 +- .../instructions/instruction.liquid | 13 ++- .../responses/func.get_pizza_price.0.liquid | 13 --- 36 files changed, 136 insertions(+), 564 deletions(-) delete mode 100644 src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingHandler.cs create mode 100644 src/Infrastructure/BotSharp.Abstraction/Routing/Models/ResponseUserArgs.cs delete mode 100644 src/Infrastructure/BotSharp.Core/Routing/Handlers/ContinueExecuteTaskRoutingHandler.cs delete mode 100644 src/Infrastructure/BotSharp.Core/Routing/Handlers/InterruptTaskExecutionRoutingHandler.cs delete mode 100644 src/Infrastructure/BotSharp.Core/Routing/Handlers/RetrieveDataFromAgentRoutingHandler.cs delete mode 100644 src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs rename tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/functions/{place_an_order.json => place_order.json} (94%) delete mode 100644 tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/responses/func.get_pizza_price.0.liquid diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationHook.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationHook.cs index c764f391..b722d3fa 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationHook.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationHook.cs @@ -69,21 +69,6 @@ public interface IConversationHook Task OnResponseGenerated(RoleDialogModel message); - /// - /// LLM detected user requested a new task different from previous topic. - /// - /// - /// - Task OnNewTaskDetected(RoleDialogModel message, string reason); - - /// - /// LLM detected the current task is completed. - /// It's useful for the situation of multiple tasks in the same conversation. - /// - /// - /// - Task OnTaskCompleted(RoleDialogModel message); - /// /// LLM detected the whole conversation is going to be end. /// diff --git a/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionCallFromLlm.cs b/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionCallFromLlm.cs index 661a1437..0bb248f4 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionCallFromLlm.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionCallFromLlm.cs @@ -36,13 +36,6 @@ public class FunctionCallFromLlm : RoutingArgs { var route = string.IsNullOrEmpty(AgentName) ? "" : $""; - if (string.IsNullOrEmpty(Response)) - { - return $"[{Function} {route} {JsonSerializer.Serialize(Arguments)}]: {Question}"; - } - else - { - return $"[{Function} {route} {JsonSerializer.Serialize(Arguments)}]: {Question} => {Response}"; - } + return $"[{Function} {route} {JsonSerializer.Serialize(Arguments)}]: {Question}"; } } diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingHandler.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingHandler.cs deleted file mode 100644 index 95cddf2e..00000000 --- a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingHandler.cs +++ /dev/null @@ -1,20 +0,0 @@ -using BotSharp.Abstraction.Functions.Models; - -namespace BotSharp.Abstraction.Routing; - -/// -/// The routing handler will be injected to Router's FUNCTIONS section of the system prompt -/// So the handler will be invoked by LLM autonomously. -/// -public interface IRoutingHandler -{ - string Name { get; } - string Description { get; } - List Planers => null; - bool Enabled => true; - List Parameters => new List(); - - void SetDialogs(List dialogs); - - 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 c0f7c81c..d98dd495 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs @@ -26,8 +26,6 @@ public interface IRoutingService /// RoutingRule[] GetRulesByAgentId(string id); - List GetHandlers(Agent router); - //void ResetRecursiveCounter(); //int GetRecursiveCounter(); //void SetRecursiveCounter(int counter); diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/ResponseUserArgs.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/ResponseUserArgs.cs new file mode 100644 index 00000000..4a3a027b --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/ResponseUserArgs.cs @@ -0,0 +1,7 @@ +namespace BotSharp.Abstraction.Routing.Models; + +public class ResponseUserArgs +{ + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; +} diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingArgs.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingArgs.cs index bc9a6fa8..44d41f31 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingArgs.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingArgs.cs @@ -15,19 +15,6 @@ public class RoutingArgs [JsonPropertyName("conversation_end")] public bool ConversationEnd { get; set; } - [JsonPropertyName("task_completed")] - public bool TaskCompleted { get; set; } - - [JsonPropertyName("is_new_task")] - public bool IsNewTask { get; set; } - - /// - /// The content of replying to user - /// - [JsonPropertyName("response")] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public string Response { get; set; } = string.Empty; - /// /// Agent for next action based on user latest response /// @@ -38,10 +25,12 @@ public class RoutingArgs /// /// Agent who can achieve user original goal /// + [Obsolete("Will be replaced by dedicate Reasoner")] [JsonPropertyName("user_goal_agent")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string OriginalAgent { get; set; } = string.Empty; + [Obsolete("Will be replaced by dedicate Reasoner")] [JsonPropertyName("user_goal_description")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string UserGoal { get; set; } = string.Empty; @@ -50,13 +39,6 @@ public class RoutingArgs { var route = string.IsNullOrEmpty(AgentName) ? "" : $""; - if (string.IsNullOrEmpty(Response)) - { - return $"[{Function} {route}]"; - } - else - { - return $"[{Function} {route}] => {Response}"; - } + return $"[{Function} {route}]"; } } diff --git a/src/Infrastructure/BotSharp.Core/BotSharpCoreExtensions.cs b/src/Infrastructure/BotSharp.Core/BotSharpCoreExtensions.cs index cd85e358..19b6df53 100644 --- a/src/Infrastructure/BotSharp.Core/BotSharpCoreExtensions.cs +++ b/src/Infrastructure/BotSharp.Core/BotSharpCoreExtensions.cs @@ -150,17 +150,6 @@ public static class BotSharpCoreExtensions var loader = new PluginLoader(services, config, pluginSettings); loader.Load(assembly => { - // Register routing handlers - var handlers = assembly.GetTypes() - .Where(x => x.IsClass) - .Where(x => x.GetInterface(nameof(IRoutingHandler)) != null) - .ToArray(); - - foreach (var handler in handlers) - { - services.AddScoped(typeof(IRoutingHandler), handler); - } - // Register function callback var functions = assembly.GetTypes() .Where(x => x.IsClass diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs index 3967aaaa..6a844c41 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs @@ -155,14 +155,6 @@ public partial class ConversationService var conversation = _services.GetRequiredService(); var updatedConversation = await conversation.UpdateConversationTitle(_conversationId, response.Instruction.NextActionReason); - // Emit conversation task completed hook - if (response.Instruction.TaskCompleted) - { - await HookEmitter.Emit(_services, async hook => - await hook.OnTaskCompleted(response) - ); - } - // Emit conversation ending hook if (response.Instruction.ConversationEnd) { diff --git a/src/Infrastructure/BotSharp.Core/Routing/Functions/ResponseToUserFn.cs b/src/Infrastructure/BotSharp.Core/Routing/Functions/ResponseToUserFn.cs index 0ee3e585..fe322f31 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Functions/ResponseToUserFn.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Functions/ResponseToUserFn.cs @@ -20,8 +20,8 @@ public class ResponseToUserFn : IFunctionCallback public Task Execute(RoleDialogModel message) { - var args = JsonSerializer.Deserialize(message.FunctionArgs); - message.Content = args.Response; + var args = JsonSerializer.Deserialize(message.FunctionArgs); + message.Content = args.Content; message.Handled = true; message.StopCompletion = true; return Task.FromResult(true); diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/ContinueExecuteTaskRoutingHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/ContinueExecuteTaskRoutingHandler.cs deleted file mode 100644 index ea50ef72..00000000 --- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/ContinueExecuteTaskRoutingHandler.cs +++ /dev/null @@ -1,50 +0,0 @@ -using BotSharp.Abstraction.Functions.Models; -using BotSharp.Abstraction.Models; -using BotSharp.Abstraction.Repositories; -using BotSharp.Abstraction.Repositories.Filters; -using BotSharp.Abstraction.Routing; -using BotSharp.Abstraction.Routing.Settings; -using BotSharp.Core.Routing.Reasoning; - -namespace BotSharp.Core.Routing.Handlers; - -public class ContinueExecuteTaskRoutingHandler : RoutingHandlerBase//, IRoutingHandler -{ - public string Name => "continue_execute_task"; - - public string Description => "Continue to execute user's request without further information retrival."; - - public List Parameters => new List - { - new ParameterPropertyDef("next_action_agent", "agent for next action based on user latest response"), - new ParameterPropertyDef("user_goal_agent", "agent who can achieve user original goal"), - new ParameterPropertyDef("reason", "why continue to execute current task"), - new ParameterPropertyDef("args", "required parameters extracted from question") - { - Type = "object" - } - }; - - public List Planers => new List - { - nameof(HFReasoner) - }; - - public ContinueExecuteTaskRoutingHandler(IServiceProvider services, ILogger logger, RoutingSettings settings) - : base(services, logger, settings) - { - } - - public async Task Handle(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message) - { - var db = _services.GetRequiredService(); - var filter = new AgentFilter { AgentNames = [inst.AgentName] }; - var record = db.GetAgents(filter).FirstOrDefault(); - - message.FunctionName = inst.Function; - message.CurrentAgentId = record.Id; - message.FunctionArgs = JsonSerializer.Serialize(inst.Arguments); - - return true; - } -} diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/InterruptTaskExecutionRoutingHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/InterruptTaskExecutionRoutingHandler.cs deleted file mode 100644 index 0d11f296..00000000 --- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/InterruptTaskExecutionRoutingHandler.cs +++ /dev/null @@ -1,37 +0,0 @@ -using BotSharp.Abstraction.Functions.Models; -using BotSharp.Abstraction.Routing; -using BotSharp.Abstraction.Routing.Settings; -using BotSharp.Core.Routing.Reasoning; - -namespace BotSharp.Core.Routing.Handlers; - -public class InterruptTaskExecutionRoutingHandler : RoutingHandlerBase//, IRoutingHandler -{ - public string Name => "interrupt_task_execution"; - - public string Description => "Can't continue user's request becauase the requirements are not met."; - - public List Parameters => new List - { - new ParameterPropertyDef("reason", "the reason why the request is interrupted"), - new ParameterPropertyDef("answer", "the content response to user") - }; - - public List Planers => new List - { - nameof(HFReasoner) - }; - - public InterruptTaskExecutionRoutingHandler(IServiceProvider services, ILogger logger, RoutingSettings settings) - : base(services, logger, settings) - { - } - - public async Task Handle(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message) - { - message.FunctionName = inst.Function; - message.StopCompletion = true; - - return true; - } -} diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/RetrieveDataFromAgentRoutingHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/RetrieveDataFromAgentRoutingHandler.cs deleted file mode 100644 index 038488eb..00000000 --- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/RetrieveDataFromAgentRoutingHandler.cs +++ /dev/null @@ -1,59 +0,0 @@ -using BotSharp.Abstraction.Routing.Settings; -using BotSharp.Core.Routing.Reasoning; - -namespace BotSharp.Core.Routing.Handlers; - -/// -/// Retrieve information from specific agent -/// -public class RetrieveDataFromAgentRoutingHandler : RoutingHandlerBase//, IRoutingHandler -{ - public string Name => "retrieve_data_from_agent"; - - public string Description => "Retrieve data from appropriate agent."; - - public List Parameters => new List - { - new ParameterPropertyDef("reason", "why choose this function"), - new ParameterPropertyDef("question", "the question you will ask the next action agent to get the necessary information"), - new ParameterPropertyDef("next_action_agent", "agent that can handle the question"), - new ParameterPropertyDef("user_goal_agent", "agent that can achieve user original goal"), - new ParameterPropertyDef("args", "required parameters extracted from question and hand over to the next agent") - { - Type = "object" - } - }; - - public List Planers => new List - { - nameof(HFReasoner) - }; - - public RetrieveDataFromAgentRoutingHandler(IServiceProvider services, ILogger logger, RoutingSettings settings) - : base(services, logger, settings) - { - } - - public async Task Handle(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message) - { - var context = _services.GetRequiredService(); - var agentId = context.GetCurrentAgentId(); - var dialogs = new List - { - new RoleDialogModel(AgentRole.User, inst.Question) - { - CurrentAgentId = agentId, - MessageId = message.MessageId - } - }; - - var ret = await routing.InvokeAgent(agentId, dialogs); - var response = dialogs.Last(); - inst.Response = response.Content; - - // Add final response to parent dialog - _dialogs.Add(response); - - return ret; - } -} diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs deleted file mode 100644 index 1dc808a0..00000000 --- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs +++ /dev/null @@ -1,99 +0,0 @@ -using BotSharp.Abstraction.Infrastructures.Enums; -using BotSharp.Abstraction.Routing.Settings; - -namespace BotSharp.Core.Routing.Handlers; - -public class RouteToAgentRoutingHandler : RoutingHandlerBase, IRoutingHandler -{ - public string Name => "route_to_agent"; - - public string Description => "Route request to appropriate virtual agent."; - - public List Parameters => new List - { - new ParameterPropertyDef("next_action_reason", - "the reason why route to this virtual agent.", - required: true), - new ParameterPropertyDef("next_action_agent", - "agent for next action based on user latest response, if user is replying last agent's question, you must route to this agent.", - required: true), - new ParameterPropertyDef("args", - "useful parameters of next action agent, format: { }", - type: "object"), - new ParameterPropertyDef("user_goal_description", - "user goal based on user initial task.", - required: true), - new ParameterPropertyDef("user_goal_agent", - "agent who can acheive user initial task.", - required: true), - new ParameterPropertyDef("conversation_end", - "user is ending the conversation.", - type: "boolean", - required: true), - new ParameterPropertyDef("is_new_task", - "whether the user is requesting a new task that is different from the previous topic. Set the first round of conversation to false.", - type: "boolean") - }; - - public RouteToAgentRoutingHandler(IServiceProvider services, ILogger logger, RoutingSettings settings) - : base(services, logger, settings) - { - } - - public async Task Handle(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message) - { - var states = _services.GetRequiredService(); - var goalAgent = states.GetState(StateConst.EXPECTED_GOAL_AGENT); - if (!string.IsNullOrEmpty(goalAgent) && inst.OriginalAgent != goalAgent) - { - inst.OriginalAgent = goalAgent; - // Emit hook - await HookEmitter.Emit(_services, async hook => - await hook.OnRoutingInstructionRevised(inst, message) - ); - } - - if (inst.IsNewTask) - { - await HookEmitter.Emit(_services, async hook => - await hook.OnNewTaskDetected(message, inst.NextActionReason) - ); - } - - message.FunctionArgs = JsonSerializer.Serialize(inst); - if (message.FunctionName != null) - { - var msg = RoleDialogModel.From(message, role: AgentRole.Function); - await routing.InvokeFunction(message.FunctionName, msg); - } - - var agentId = routing.Context.GetCurrentAgentId(); - - // Update next action agent's name - var agentService = _services.GetRequiredService(); - var agent = await agentService.GetAgent(agentId); - inst.AgentName = agent.Name; - - if (inst.ExecutingDirectly) - { - message.Content = inst.Question; - } - - if (agent.Disabled) - { - var content = $"This agent ({agent.Name}) is disabled, please install the corresponding plugin ({agent.Plugin.Name}) to activate this agent."; - - message = RoleDialogModel.From(message, role: AgentRole.Assistant, content: content); - _dialogs.Add(message); - } - else - { - var ret = await routing.InvokeAgent(agentId, _dialogs); - } - - var response = _dialogs.Last(); - inst.Response = response.Content; - - return true; - } -} diff --git a/src/Infrastructure/BotSharp.Core/Routing/Hooks/RoutingAgentHook.cs b/src/Infrastructure/BotSharp.Core/Routing/Hooks/RoutingAgentHook.cs index f83afedf..53a54669 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Hooks/RoutingAgentHook.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Hooks/RoutingAgentHook.cs @@ -59,7 +59,6 @@ public class RoutingAgentHook : AgentHookBase } dict["routing_agents"] = agents; - dict["routing_handlers"] = routing.GetHandlers(_agent); return base.OnInstructionLoaded(template, dict); } diff --git a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/HFReasoner.cs b/src/Infrastructure/BotSharp.Core/Routing/Reasoning/HFReasoner.cs index fc7c1009..55867e00 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/HFReasoner.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Reasoning/HFReasoner.cs @@ -38,43 +38,21 @@ public class HFReasoner : IRoutingReasoner { var next = GetNextStepPrompt(router); - RoleDialogModel response = default; - var inst = new FunctionCallFromLlm(); - var completion = CompletionProvider.GetChatCompletion(_services, provider: router?.LlmConfig?.Provider, model: router?.LlmConfig?.Model); - int retryCount = 0; - while (retryCount < 3) + dialogs = new List { - try + new RoleDialogModel(AgentRole.User, next) { - dialogs = new List - { - new RoleDialogModel(AgentRole.User, next) - { - FunctionName = nameof(HFReasoner), - MessageId = messageId - } - }; - response = await completion.GetChatCompletions(router, dialogs); + FunctionName = nameof(HFReasoner), + MessageId = messageId + } + }; + var response = await completion.GetChatCompletions(router, dialogs); - inst = response.Content.JsonContent(); - break; - } - catch (Exception ex) - { - _logger.LogError($"{ex.Message}: {response.Content}"); - inst.Function = "response_to_user"; - inst.Response = ex.Message; - inst.AgentName = "Router"; - } - finally - { - retryCount++; - } - } + var inst = response.Content.JsonContent(); // Fix LLM malformed response ReasonerHelper.FixMalformedResponse(_services, inst); diff --git a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/InstructExecutor.cs b/src/Infrastructure/BotSharp.Core/Routing/Reasoning/InstructExecutor.cs index 6bb23e97..e911437d 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/InstructExecutor.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Reasoning/InstructExecutor.cs @@ -1,3 +1,4 @@ +using BotSharp.Abstraction.Infrastructures.Enums; using BotSharp.Abstraction.Planning; namespace BotSharp.Core.Routing.Reasoning; @@ -18,17 +19,50 @@ public class InstructExecutor : IExecutor RoleDialogModel message, List dialogs) { - message.Instruction = inst; + var states = _services.GetRequiredService(); + var goalAgent = states.GetState(StateConst.EXPECTED_GOAL_AGENT); + if (!string.IsNullOrEmpty(goalAgent) && inst.OriginalAgent != goalAgent) + { + inst.OriginalAgent = goalAgent; + // Emit hook + await HookEmitter.Emit(_services, async hook => + await hook.OnRoutingInstructionRevised(inst, message) + ); + } - var handlers = _services.GetServices(); - var handler = handlers.FirstOrDefault(x => x.Name == inst.Function); - handler.SetDialogs(dialogs); + message.FunctionArgs = JsonSerializer.Serialize(inst); + if (message.FunctionName != null) + { + var msg = RoleDialogModel.From(message, role: AgentRole.Function); + await routing.InvokeFunction(message.FunctionName, msg); + } - var handled = await handler.Handle(routing, inst, message); + var agentId = routing.Context.GetCurrentAgentId(); + + // Update next action agent's name + var agentService = _services.GetRequiredService(); + var agent = await agentService.GetAgent(agentId); + inst.AgentName = agent.Name; + + if (inst.ExecutingDirectly) + { + message.Content = inst.Question; + } + + if (agent.Disabled) + { + var content = $"This agent ({agent.Name}) is disabled, please install the corresponding plugin ({agent.Plugin.Name}) to activate this agent."; + + message = RoleDialogModel.From(message, role: AgentRole.Assistant, content: content); + dialogs.Add(message); + } + else + { + var ret = await routing.InvokeAgent(agentId, dialogs); + } - // For client display purpose var response = dialogs.Last(); - response.MessageId = message.MessageId; + response.Instruction = inst; return response; diff --git a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/NaiveReasoner.cs b/src/Infrastructure/BotSharp.Core/Routing/Reasoning/NaiveReasoner.cs index 8980246e..6adc9bc5 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/NaiveReasoner.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Reasoning/NaiveReasoner.cs @@ -41,53 +41,22 @@ public class NaiveReasoner : IRoutingReasoner { var next = GetNextStepPrompt(router); - var inst = new FunctionCallFromLlm(); - - // text completion - /*var agentService = _services.GetRequiredService(); - var instruction = agentService.RenderedInstruction(router); - var content = $"{instruction}\r\n###\r\n{next}"; - content = content + "\r\nResponse: "; - var completion = CompletionProvider.GetTextCompletion(_services);*/ - // chat completion var completion = CompletionProvider.GetChatCompletion(_services, provider: router?.LlmConfig?.Provider, model: router?.LlmConfig?.Model); - int retryCount = 0; - while (retryCount < 3) + dialogs = new List { - string text = string.Empty; - try + new RoleDialogModel(AgentRole.User, next) { - // text completion - // text = await completion.GetCompletion(content, router.Id, messageId); - dialogs = new List - { - new RoleDialogModel(AgentRole.User, next) - { - FunctionName = nameof(NaiveReasoner), - MessageId = messageId - } - }; - var response = await completion.GetChatCompletions(router, dialogs); + FunctionName = nameof(NaiveReasoner), + MessageId = messageId + } + }; + var response = await completion.GetChatCompletions(router, dialogs); - inst = (response.FunctionArgs ?? response.Content).JsonContent(); - break; - } - catch (Exception ex) - { - _logger.LogError($"{ex.Message}: {text}"); - inst.Function = "response_to_user"; - inst.Response = ex.Message; - inst.AgentName = "Router"; - } - finally - { - retryCount++; - } - } + var inst = (response.FunctionArgs ?? response.Content).JsonContent(); // Fix LLM malformed response ReasonerHelper.FixMalformedResponse(_services, inst); diff --git a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/OneStepForwardReasoner.cs b/src/Infrastructure/BotSharp.Core/Routing/Reasoning/OneStepForwardReasoner.cs index 7e6d2624..800b2457 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/OneStepForwardReasoner.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Reasoning/OneStepForwardReasoner.cs @@ -44,46 +44,26 @@ public class OneStepForwardReasoner : IRoutingReasoner { var next = GetNextStepPrompt(router); - var inst = new FunctionCallFromLlm(); - // chat completion var completion = CompletionProvider.GetChatCompletion(_services, provider: router?.LlmConfig?.Provider, model: router?.LlmConfig?.Model); - int retryCount = 0; - while (retryCount < 3) - { - string text = string.Empty; - try - { - // text completion - // text = await completion.GetCompletion(content, router.Id, messageId); - dialogs = new List - { - new RoleDialogModel(AgentRole.User, next) - { - FunctionName = Name, - MessageId = messageId - } - }; - var response = await completion.GetChatCompletions(router, dialogs); + string text = string.Empty; - inst = response.Content.JsonContent(); - break; - } - catch (Exception ex) + // text completion + // text = await completion.GetCompletion(content, router.Id, messageId); + dialogs = new List + { + new RoleDialogModel(AgentRole.User, next) { - _logger.LogError($"{ex.Message}: {text}"); - inst.Function = "response_to_user"; - inst.Response = ex.Message; - inst.AgentName = "Router"; + FunctionName = Name, + MessageId = messageId } - finally - { - retryCount++; - } - } + }; + var response = await completion.GetChatCompletions(router, dialogs); + + var inst = response.Content.JsonContent(); // Fix LLM malformed response ReasonerHelper.FixMalformedResponse(_services, inst); diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InstructLoop.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InstructLoop.cs index 07b2f6fa..20aa16b6 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InstructLoop.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InstructLoop.cs @@ -58,11 +58,8 @@ public partial class RoutingService // Save states states.SaveStateByArgs(inst.Arguments); -#if DEBUG - Console.WriteLine($"*** Next Instruction *** {inst}"); -#else - _logger.LogInformation($"*** Next Instruction *** {inst}"); -#endif + _logger.LogDebug($"*** Next Instruction *** {inst}"); + await reasoner.AgentExecuting(_router, inst, message, dialogs); // Handover to Task Agent @@ -79,7 +76,7 @@ public partial class RoutingService await reasoner.AgentExecuted(_router, inst, response, dialogs); - if (loopCount >= reasoner.MaxLoopCount || _context.IsEmpty) + if (loopCount >= reasoner.MaxLoopCount || _context.IsEmpty || response.StopCompletion) { break; } diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs index 19654deb..253e7b54 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs @@ -28,17 +28,12 @@ public partial class RoutingService : IRoutingService public async Task InstructDirect(Agent agent, RoleDialogModel message) { - var handlers = _services.GetServices(); - - var handler = handlers.FirstOrDefault(x => x.Name == "route_to_agent"); - var conv = _services.GetRequiredService(); var storage = _services.GetRequiredService(); storage.Append(conv.ConversationId, message); var dialogs = conv.GetDialogHistory(); Context.SetDialogs(dialogs); - handler.SetDialogs(dialogs); var inst = new FunctionCallFromLlm { @@ -50,7 +45,8 @@ public partial class RoutingService : IRoutingService ExecutingDirectly = true }; - var result = await handler.Handle(this, inst, message); + message.Instruction = inst; + var result = await InvokeFunction("route_to_agent", message); var response = dialogs.Last(); response.MessageId = message.MessageId; @@ -59,21 +55,6 @@ public partial class RoutingService : IRoutingService return response; } - public List GetHandlers(Agent router) - { - var reasoner = GetReasoner(router); - - return _services.GetServices() - .Where(x => x.Planers == null || x.Planers.Contains(reasoner.GetType().Name)) - .Where(x => !string.IsNullOrEmpty(x.Description)) - .Select((x, i) => new RoutingHandlerDef - { - Name = x.Name, - Description = x.Description, - Parameters = x.Parameters - }).ToList(); - } - #if !DEBUG [SharpCache(10)] #endif diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/functions/response_to_user.json b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/functions/response_to_user.json index a2685810..9e7f8929 100644 --- a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/functions/response_to_user.json +++ b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/functions/response_to_user.json @@ -1,15 +1,14 @@ { "name": "response_to_user", - "description": "Response to user without routing to any other agent", - "visibility_expression": "{% if states.routing_mode == 'lazy' %}visible{% endif %}", + "description": "Response to user without routing to any other agent, user has no specific request.", "parameters": { "type": "object", "properties": { - "response": { + "content": { "type": "string", "description": "Response content" } }, - "required": [ "response" ] + "required": [ "content" ] } } \ No newline at end of file diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/functions/route_to_agent.json b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/functions/route_to_agent.json index 08f938ec..01301bbf 100644 --- a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/functions/route_to_agent.json +++ b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/functions/route_to_agent.json @@ -1,7 +1,6 @@ { "name": "route_to_agent", "description": "Route request to appropriate AI agent.", - "visibility_expression": "{% if states.routing_mode == 'lazy' %}visible{% endif %}", "parameters": { "type": "object", "properties": { diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/instructions/instruction.liquid b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/instructions/instruction.liquid index 99f7a219..d49215d1 100644 --- a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/instructions/instruction.liquid +++ b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/instructions/instruction.liquid @@ -18,21 +18,6 @@ Follow these steps to handle user request: {%- endfor %} {% endif %} -{% if routing_mode != 'lazy' %} -[FUNCTIONS] -{% for handler in routing_handlers -%} -# {{ handler.description}} -{% if handler.parameters and handler.parameters != empty -%} -Parameters: - - function: {{ handler.name }} - {% for p in handler.parameters -%} - - {{ p.name }} {% if p.required -%}(required){%- endif %}: {{ p.description }}{{ "\r\n " }} - {%- endfor %} -{%- endif %} -{{ "\r\n" }} -{%- endfor %} -{% endif %} - [AGENTS] {% for agent in routing_agents -%} * Agent: {{ agent.name }} diff --git a/src/Plugins/BotSharp.Plugin.Planner/Sequential/SequentialPlanner.cs b/src/Plugins/BotSharp.Plugin.Planner/Sequential/SequentialPlanner.cs index 043c7380..94b4a687 100644 --- a/src/Plugins/BotSharp.Plugin.Planner/Sequential/SequentialPlanner.cs +++ b/src/Plugins/BotSharp.Plugin.Planner/Sequential/SequentialPlanner.cs @@ -41,7 +41,7 @@ public class SequentialPlanner : ITaskPlanner var decomposation = await GetDecomposedStepAsync(router, messageId, dialogs); if (decomposation.TotalRemainingSteps > 0 && _lastInst != null) { - _lastInst.Response = decomposation.Description; + // _lastInst.Response = decomposation.Description; _lastInst.NextActionReason = $"Having {decomposation.TotalRemainingSteps} steps left."; return _lastInst; } @@ -62,8 +62,6 @@ public class SequentialPlanner : ITaskPlanner var next = GetNextStepPrompt(router); - var inst = new FunctionCallFromLlm(); - // text completion /*var agentService = _services.GetRequiredService(); var instruction = agentService.RenderedInstruction(router); @@ -76,43 +74,26 @@ public class SequentialPlanner : ITaskPlanner provider: router?.LlmConfig?.Provider, model: router?.LlmConfig?.Model); - int retryCount = 0; - while (retryCount < 3) - { - string text = string.Empty; - try - { - // text completion - // text = await completion.GetCompletion(content, router.Id, messageId); - dialogs = new List - { - new RoleDialogModel(AgentRole.User, next) - { - FunctionName = nameof(SequentialPlanner), - MessageId = messageId - } - }; - var response = await completion.GetChatCompletions(router, dialogs); - inst = response.Content.JsonContent(); - break; - } - catch (Exception ex) + string text = string.Empty; + + // text completion + // text = await completion.GetCompletion(content, router.Id, messageId); + dialogs = new List + { + new RoleDialogModel(AgentRole.User, next) { - _logger.LogError($"{ex.Message}: {text}"); - inst.Function = "response_to_user"; - inst.Response = ex.Message; - inst.AgentName = "Router"; + FunctionName = nameof(SequentialPlanner), + MessageId = messageId } - finally - { - retryCount++; - } - } + }; + var response = await completion.GetChatCompletions(router, dialogs); + + var inst = response.Content.JsonContent(); if (decomposation.TotalRemainingSteps > 0) { - inst.Response = decomposation.Description; + // inst.Response = decomposation.Description; inst.NextActionReason = $"{decomposation.TotalRemainingSteps} steps left."; inst.HandleDialogsByPlanner = true; } @@ -125,10 +106,10 @@ public class SequentialPlanner : ITaskPlanner { var taskAgentDialogs = new List { - new RoleDialogModel(AgentRole.User, inst.Response) + /*new RoleDialogModel(AgentRole.User, inst.Response) { MessageId = message.MessageId, - } + }*/ }; return taskAgentDialogs; diff --git a/src/Plugins/BotSharp.Plugin.Planner/SqlGeneration/SqlGenerationPlanner.cs b/src/Plugins/BotSharp.Plugin.Planner/SqlGeneration/SqlGenerationPlanner.cs index 62340e9c..a804b073 100644 --- a/src/Plugins/BotSharp.Plugin.Planner/SqlGeneration/SqlGenerationPlanner.cs +++ b/src/Plugins/BotSharp.Plugin.Planner/SqlGeneration/SqlGenerationPlanner.cs @@ -42,14 +42,14 @@ public class SqlGenerationPlanner : ITaskPlanner public List BeforeHandleContext(FunctionCallFromLlm inst, RoleDialogModel message, List dialogs) { - var question = inst.Response; + // var question = inst.Response; var taskAgentDialogs = new List { - new RoleDialogModel(AgentRole.User, question) + /*new RoleDialogModel(AgentRole.User, question) { MessageId = message.MessageId, - } + }*/ }; return taskAgentDialogs; diff --git a/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/TwoStageTaskPlanner.cs b/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/TwoStageTaskPlanner.cs index 6935bfbf..ea89cd71 100644 --- a/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/TwoStageTaskPlanner.cs +++ b/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/TwoStageTaskPlanner.cs @@ -70,14 +70,14 @@ public partial class TwoStageTaskPlanner : ITaskPlanner public List BeforeHandleContext(FunctionCallFromLlm inst, RoleDialogModel message, List dialogs) { - var question = inst.Response; + // var question = inst.Response; var taskAgentDialogs = new List { - new RoleDialogModel(AgentRole.User, question) + /*new RoleDialogModel(AgentRole.User, question) { MessageId = message.MessageId, - } + }*/ }; return taskAgentDialogs; diff --git a/src/WebStarter/appsettings.json b/src/WebStarter/appsettings.json index ce052798..b48d2963 100644 --- a/src/WebStarter/appsettings.json +++ b/src/WebStarter/appsettings.json @@ -254,8 +254,8 @@ "HostAgentId": "01e2fc5c-2c89-4ec7-8470-7688608b496c", "EnableTranslator": false, "LlmConfig": { - "Provider": "azure-openai", - "Model": "gpt-4o-mini" + "Provider": "openai", + "Model": "gpt-4.1-nano" } }, diff --git a/tests/BotSharp.Plugin.PizzaBot/BotSharp.Plugin.PizzaBot.csproj b/tests/BotSharp.Plugin.PizzaBot/BotSharp.Plugin.PizzaBot.csproj index d132125f..c056982d 100644 --- a/tests/BotSharp.Plugin.PizzaBot/BotSharp.Plugin.PizzaBot.csproj +++ b/tests/BotSharp.Plugin.PizzaBot/BotSharp.Plugin.PizzaBot.csproj @@ -32,9 +32,7 @@ - - @@ -63,9 +61,6 @@ PreserveNewest - - PreserveNewest - PreserveNewest @@ -93,7 +88,7 @@ PreserveNewest - + PreserveNewest diff --git a/tests/BotSharp.Plugin.PizzaBot/Functions/PlaceOrderFn.cs b/tests/BotSharp.Plugin.PizzaBot/Functions/PlaceOrderFn.cs index 87466956..e4198f34 100644 --- a/tests/BotSharp.Plugin.PizzaBot/Functions/PlaceOrderFn.cs +++ b/tests/BotSharp.Plugin.PizzaBot/Functions/PlaceOrderFn.cs @@ -1,11 +1,12 @@ using BotSharp.Abstraction.Conversations; using BotSharp.Abstraction.Conversations.Models; +using BotSharp.Abstraction.Infrastructures.Enums; namespace BotSharp.Plugin.PizzaBot.Functions; public class PlaceOrderFn : IFunctionCallback { - public string Name => "place_an_order"; + public string Name => "place_order"; private readonly IServiceProvider _service; public PlaceOrderFn(IServiceProvider service) @@ -19,6 +20,9 @@ public class PlaceOrderFn : IFunctionCallback var state = _service.GetRequiredService(); state.SetState("order_number", "P123-01"); + // Set the next action agent to Payment + state.SetState(StateConst.EXPECTED_ACTION_AGENT, "Payment", activeRounds: 2); + 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 3a28b3e0..99f1f2fd 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 @@ -1,7 +1,7 @@ { "id": "8970b1e5-d260-4e2c-90b1-f1415a257c18", "name": "Pizza Bot", - "description": "AI assistant that can help customer place pizza order, make payment or inquiry order status.", + "description": "AI assistant that can help customer place pizza order, make payment or inquiry existing order.", "type": "routing", "inheritAgentId": "01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a", "createdDateTime": "2023-08-18T10:39:32.2349685Z", @@ -11,6 +11,10 @@ "isPublic": true, "profiles": [ "pizza" ], "labels": [ "experiment" ], + "llmConfig": { + "provider": "openai", + "model": "gpt-4.1-nano" + }, "routingRules": [ { "type": "reasoner", 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 09f7489b..e9bb78d0 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 @@ -1,6 +1,6 @@ { "name": "Order Inquiry", - "description": "Check the order status like payment, delivery or baking.", + "description": "Check the existing order status like payment, delivery or baking.", "createdDateTime": "2023-08-18T14:39:32.2349685Z", "updatedDateTime": "2023-08-18T14:39:32.2349686Z", "id": "b284db86-e9c2-4c25-a59e-4649797dd130", diff --git a/tests/BotSharp.Plugin.PizzaBot/data/agents/b284db86-e9c2-4c25-a59e-4649797dd130/functions/get_order_status.json b/tests/BotSharp.Plugin.PizzaBot/data/agents/b284db86-e9c2-4c25-a59e-4649797dd130/functions/get_order_status.json index 49de63fe..fc7abb8b 100644 --- a/tests/BotSharp.Plugin.PizzaBot/data/agents/b284db86-e9c2-4c25-a59e-4649797dd130/functions/get_order_status.json +++ b/tests/BotSharp.Plugin.PizzaBot/data/agents/b284db86-e9c2-4c25-a59e-4649797dd130/functions/get_order_status.json @@ -6,7 +6,7 @@ "properties": { "order_number": { "type": "string", - "description": "order number." + "description": "order number, value must be provided by user." } }, "required": [ "order_number" ] 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 a6948ac4..8cade6f1 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 @@ -1,5 +1,5 @@ { - "name": "Ordering", + "name": "Order Placement", "description": "Provide types of pizza available, pizza unit price, total cost and place the order.", "createdDateTime": "2023-07-26T02:29:25.123224Z", "updatedDateTime": "2023-07-26T02:29:25.123274Z", diff --git a/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/functions/place_an_order.json b/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/functions/place_order.json similarity index 94% rename from tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/functions/place_an_order.json rename to tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/functions/place_order.json index d5514fba..9fe8278a 100644 --- a/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/functions/place_an_order.json +++ b/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/functions/place_order.json @@ -1,5 +1,5 @@ { - "name": "place_an_order", + "name": "place_order", "description": "Place an order when user has confirmed the pizza type and quantity.", "parameters": { "type": "object", diff --git a/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/instructions/instruction.liquid b/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/instructions/instruction.liquid index 73b33cc3..5194fc79 100644 --- a/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/instructions/instruction.liquid +++ b/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/instructions/instruction.liquid @@ -1,10 +1,9 @@ You are now a Pizza Ordering agent, and you can help customers order a pizza according to the user's preferences. -Follow below step to place order: -1: Ask user preferences, call function get_pizza_types to provide the variety of pizza options. -2: Confirm with user the pizza type and quantity. -3: Call function place_an_order to purchase. -4: Ask user how to pay for this order. - -Use below information to help ordering process: * Today is {{current_date}}, the time now is {{current_time}}, day of week is {{current_weekday}}. + +Follow below step to response: +1: Ask user preferences, call function get_pizza_types to provide the variety of pizza options. +2: Call get_pizza_price to tell customer the price per unit, then ask user for the quantity. +3: Confirm the order with total price, call function place_order to place the order. +4: Ask user how to pay for this order. diff --git a/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/responses/func.get_pizza_price.0.liquid b/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/responses/func.get_pizza_price.0.liquid deleted file mode 100644 index 62041ece..00000000 --- a/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/responses/func.get_pizza_price.0.liquid +++ /dev/null @@ -1,13 +0,0 @@ -{% assign pizza_type = pizza_type | downcase %} -{% if pizza_type contains "cheese" -%} - The price for a slice of {{pizza_type}} pizza is ${{ cheese_unit_price }}. Would you like to proceed the order? -{%- elsif pizza_type contains "pepperoni" -%} - The price for a slice of {{pizza_type}} pizza is ${{ pepperoni_unit_price }}. Would you like to proceed the order? -{%- elsif pizza_type contains "margherita" -%} - The price for a slice of {{pizza_type}} pizza is ${{ margherita_unit_price }}. Would you like to proceed the order? -{%- else -%} - We don't have {{pizza_type}} pizza, would you like something else? -{%- endif %} -{% if quantity == nil -%} - How many slices would you like to order? -{%- endif %} \ No newline at end of file