diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs
index 4bf197ea..e6599836 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs
@@ -16,6 +16,10 @@ public interface IAgentService
///
Task LoadAgent(string id);
+ string RenderedInstruction(Agent agent);
+
+ string RenderedTemplate(Agent agent, string templateName);
+
///
/// Get agent detail without trigger any hook.
///
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs
index 42710520..7115ccf1 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs
@@ -65,6 +65,12 @@ public class Agent
public List RoutingRules { get; set; }
= new List();
+ ///
+ /// For rendering deferral
+ ///
+ [JsonIgnore]
+ public Dictionary TemplateDict { get; set; }
+
public override string ToString()
=> $"{Name} {Id}";
diff --git a/src/Infrastructure/BotSharp.Abstraction/Functions/Models/ParameterPropertyDef.cs b/src/Infrastructure/BotSharp.Abstraction/Functions/Models/ParameterPropertyDef.cs
index 04159b95..fd927bbc 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Functions/Models/ParameterPropertyDef.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Functions/Models/ParameterPropertyDef.cs
@@ -1,5 +1,3 @@
-using BotSharp.Abstraction.Models;
-
namespace BotSharp.Abstraction.Functions.Models;
public class ParameterPropertyDef : NameDesc
@@ -10,6 +8,9 @@ public class ParameterPropertyDef : NameDesc
Type = type;
}
+ [JsonPropertyName("required")]
+ public bool Required { get; set; }
+
///
/// string, number, object
///
diff --git a/src/Infrastructure/BotSharp.Abstraction/Instructs/IInstructService.cs b/src/Infrastructure/BotSharp.Abstraction/Instructs/IInstructService.cs
index 2162204d..476a9f01 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Instructs/IInstructService.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Instructs/IInstructService.cs
@@ -4,5 +4,5 @@ namespace BotSharp.Abstraction.Instructs;
public interface IInstructService
{
- Task Execute(Agent agent, RoleDialogModel message);
+ Task Execute(string agentId, RoleDialogModel message, string? templateName = null);
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Planning/IExecutor.cs b/src/Infrastructure/BotSharp.Abstraction/Planning/IExecutor.cs
new file mode 100644
index 00000000..54c674db
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/Planning/IExecutor.cs
@@ -0,0 +1,13 @@
+using BotSharp.Abstraction.Functions.Models;
+using BotSharp.Abstraction.Routing;
+
+namespace BotSharp.Abstraction.Planning;
+
+public interface IExecutor
+{
+ Task Execute(IRoutingService routing,
+ Agent router,
+ FunctionCallFromLlm inst,
+ List dialogs,
+ RoleDialogModel message);
+}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Planning/IPlaner.cs b/src/Infrastructure/BotSharp.Abstraction/Planning/IPlaner.cs
new file mode 100644
index 00000000..e42e99c5
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/Planning/IPlaner.cs
@@ -0,0 +1,12 @@
+using BotSharp.Abstraction.Functions.Models;
+
+namespace BotSharp.Abstraction.Planning;
+
+///
+/// Task breakdown and execution plan
+///
+public interface IPlaner
+{
+ Task GetNextInstruction(Agent router, string conversation);
+ Task AgentExecuted(FunctionCallFromLlm inst, RoleDialogModel message);
+}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingHandler.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingHandler.cs
index 6c8ae94e..f57080d7 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingHandler.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingHandler.cs
@@ -1,4 +1,5 @@
using BotSharp.Abstraction.Functions.Models;
+using BotSharp.Abstraction.Planning;
namespace BotSharp.Abstraction.Routing;
@@ -10,9 +11,9 @@ public interface IRoutingHandler
{
string Name { get; }
string Description { get; }
- bool IsReasoning => false;
+ List Planers => null;
bool Enabled => true;
- List Parameters => new List();
+ List Parameters => new List();
void SetRouter(Agent router) { }
diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs
index 47744957..127c708e 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs
@@ -1,5 +1,3 @@
-using BotSharp.Abstraction.Functions.Models;
-
namespace BotSharp.Abstraction.Routing;
public interface IRoutingService
@@ -7,7 +5,6 @@ public interface IRoutingService
List Dialogs { get; }
void ResetRecursiveCounter();
void RefreshDialogs();
- Task GetNextInstruction();
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/RoutingHandlerDef.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingHandlerDef.cs
index 0591fa0c..f0bfbf5a 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingHandlerDef.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingHandlerDef.cs
@@ -1,4 +1,4 @@
-using BotSharp.Abstraction.Models;
+using BotSharp.Abstraction.Functions.Models;
namespace BotSharp.Abstraction.Routing.Models;
@@ -6,7 +6,7 @@ public class RoutingHandlerDef
{
public string Name { get; set; }
public string Description { get; set; }
- public List Parameters { get; set; }
+ public List Parameters { get; set; }
public override string ToString()
=> $"{Name}: {Description} ({Parameters.Count} Parameters)";
diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingItem.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingItem.cs
index 8ea5269d..ca632ee1 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingItem.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingItem.cs
@@ -13,6 +13,6 @@ public class RoutingItem
[JsonPropertyName("description")]
public string Description { get; set; } = string.Empty;
- [JsonPropertyName("required_fields")]
- public List RequiredFields { get; set; } = new List();
+ [JsonPropertyName("fields")]
+ public List Fields { get; set; } = new List();
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/Settings/RoutingSettings.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/Settings/RoutingSettings.cs
index 39338b13..62a6ae4a 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Routing/Settings/RoutingSettings.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Routing/Settings/RoutingSettings.cs
@@ -7,9 +7,7 @@ public class RoutingSettings
///
public string RouterId { get; set; } = string.Empty;
- public bool EnableReasoning { get; set; } = false;
- public bool UseTextCompletion { get; set; } = false;
-
+ public string Planner { get; set; } = string.Empty;
public string Provider { get; set; } = string.Empty;
public string Model { get; set; } = string.Empty;
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs
index 5912b1e0..45d3b76d 100644
--- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs
+++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs
@@ -4,14 +4,16 @@ namespace BotSharp.Core.Agents.Services;
public partial class AgentService
{
- [MemoryCache(10 * 60, PerInstanceCache = true)]
+ [MemoryCache(10 * 60)]
public async Task> GetAgents(bool? allowRouting = null)
{
var agents = _db.GetAgents(allowRouting: allowRouting);
return await Task.FromResult(agents);
}
- [MemoryCache(10 * 60, PerInstanceCache = true)]
+#if !DEBUG
+ [MemoryCache(10 * 60)]
+#endif
public async Task GetAgent(string id)
{
var profile = _db.GetAgent(id);
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs
index 301da3b7..1b7a6e99 100644
--- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs
+++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs
@@ -27,8 +27,10 @@ public partial class AgentService
throw new Exception($"Can't load agent by id: {id}");
}
- var templateDict = new Dictionary();
- PopulateState(templateDict);
+ agent.TemplateDict = new Dictionary();
+
+ // Populate state into dictionary
+ PopulateState(agent.TemplateDict);
// After agent is loaded
foreach (var hook in hooks)
@@ -42,7 +44,7 @@ public partial class AgentService
if (!string.IsNullOrEmpty(agent.Instruction))
{
- hook.OnInstructionLoaded(agent.Instruction, templateDict);
+ hook.OnInstructionLoaded(agent.Instruction, agent.TemplateDict);
}
if (agent.Functions != null)
@@ -58,15 +60,25 @@ public partial class AgentService
hook.OnAgentLoaded(agent);
}
- // render liquid template
- var render = _services.GetRequiredService();
- agent.Instruction = render.Render(agent.Instruction, templateDict);
-
_logger.LogInformation($"Loaded agent {agent}.");
return agent;
}
+ public string RenderedTemplate(Agent agent, string templateName)
+ {
+ // render liquid template
+ var render = _services.GetRequiredService();
+ var template = agent.Templates.First(x => x.Name == templateName).Content;
+ return render.Render(template, agent.TemplateDict);
+ }
+
+ public string RenderedInstruction(Agent agent)
+ {
+ var render = _services.GetRequiredService();
+ return render.Render(agent.Instruction, agent.TemplateDict);
+ }
+
private void PopulateState(Dictionary dict)
{
var conv = _services.GetRequiredService();
diff --git a/src/Infrastructure/BotSharp.Core/BotSharpServiceCollectionExtensions.cs b/src/Infrastructure/BotSharp.Core/BotSharpServiceCollectionExtensions.cs
index 9b64b127..757faab8 100644
--- a/src/Infrastructure/BotSharp.Core/BotSharpServiceCollectionExtensions.cs
+++ b/src/Infrastructure/BotSharp.Core/BotSharpServiceCollectionExtensions.cs
@@ -17,6 +17,8 @@ using BotSharp.Abstraction.Evaluations;
using BotSharp.Core.Evaluatings;
using BotSharp.Core.Evaluations;
using BotSharp.Abstraction.MLTasks.Settings;
+using BotSharp.Abstraction.Planning;
+using BotSharp.Core.Planning;
namespace BotSharp.Core;
@@ -68,6 +70,18 @@ public static class BotSharpServiceCollectionExtensions
config.Bind("Router", routingSettings);
services.AddSingleton((IServiceProvider x) => routingSettings);
+ services.AddScoped();
+ services.AddScoped();
+ services.AddScoped(provider =>
+ {
+ if (routingSettings.Planner == "NaivePlanner")
+ return provider.GetRequiredService();
+ else if (routingSettings.Planner == "FeedbackReasoningPlanner")
+ return provider.GetRequiredService();
+ throw new NotImplementedException();
+ });
+
+ services.AddScoped();
services.AddScoped();
services.AddScoped();
diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs
index 387a18e7..63972742 100644
--- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs
+++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs
@@ -20,7 +20,7 @@ public partial class ConversationService
var content = $"Received [{agent.Name}] {message.Role}: {message.Content}";
#if DEBUG
- Console.WriteLine(content, Color.OrangeRed);
+ Console.WriteLine(content, Color.GreenYellow);
#else
_logger.LogInformation(content);
#endif
diff --git a/src/Infrastructure/BotSharp.Core/Instructs/InstructService.cs b/src/Infrastructure/BotSharp.Core/Instructs/InstructService.cs
index 8ee49eac..e135afed 100644
--- a/src/Infrastructure/BotSharp.Core/Instructs/InstructService.cs
+++ b/src/Infrastructure/BotSharp.Core/Instructs/InstructService.cs
@@ -1,7 +1,6 @@
using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Instructs;
using BotSharp.Abstraction.Instructs.Models;
-
namespace BotSharp.Core.Instructs;
public partial class InstructService : IInstructService
@@ -15,13 +14,13 @@ public partial class InstructService : IInstructService
_logger = logger;
}
- public async Task Execute(Agent agent, RoleDialogModel message)
+ public async Task Execute(string agentId, RoleDialogModel message, string? templateName = null)
{
// Trigger before completion hooks
var hooks = _services.GetServices();
foreach (var hook in hooks)
{
- if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agent.Id)
+ if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agentId)
{
continue;
}
@@ -39,8 +38,15 @@ public partial class InstructService : IInstructService
}
}
+ // Render prompt
+ var agentService = _services.GetRequiredService();
+ Agent agent = await agentService.LoadAgent(agentId);
+ var prompt = string.IsNullOrEmpty(templateName) ?
+ agentService.RenderedInstruction(agent) :
+ agentService.RenderedTemplate(agent, templateName);
+
var completer = CompletionProvider.GetTextCompletion(_services);
- var result = await completer.GetCompletion(agent.Instruction);
+ var result = await completer.GetCompletion(prompt);
var response = new InstructResult
{
MessageId = message.MessageId,
@@ -49,7 +55,7 @@ public partial class InstructService : IInstructService
foreach (var hook in hooks)
{
- if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agent.Id)
+ if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agentId)
{
continue;
}
diff --git a/src/Infrastructure/BotSharp.Core/Planning/FeedbackReasoningPlanner.cs b/src/Infrastructure/BotSharp.Core/Planning/FeedbackReasoningPlanner.cs
new file mode 100644
index 00000000..156cb590
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Core/Planning/FeedbackReasoningPlanner.cs
@@ -0,0 +1,75 @@
+using BotSharp.Abstraction.Agents.Models;
+using BotSharp.Abstraction.Functions.Models;
+using BotSharp.Abstraction.Planning;
+using BotSharp.Abstraction.Templating;
+
+namespace BotSharp.Core.Planning;
+
+public class FeedbackReasoningPlanner : IPlaner
+{
+ private readonly IServiceProvider _services;
+ private readonly ILogger _logger;
+
+ public FeedbackReasoningPlanner(IServiceProvider services, ILogger logger)
+ {
+ _services = services;
+ _logger = logger;
+ }
+
+ public async Task GetNextInstruction(Agent router, string conversation)
+ {
+ var next = GetNextStepPrompt(router);
+
+ RoleDialogModel response = default;
+ var inst = new FunctionCallFromLlm();
+
+ var content = $"{conversation}\r\n###\r\n{next}";
+
+ var completion = CompletionProvider.GetChatCompletion(_services,
+ model: "llm-gpt4");
+
+ int retryCount = 0;
+ while (retryCount < 3)
+ {
+ try
+ {
+ response = completion.GetChatCompletions(router, new List
+ {
+ new RoleDialogModel(AgentRole.User, content)
+ });
+
+ 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++;
+ }
+ }
+
+ return inst;
+ }
+
+ public async Task AgentExecuted(FunctionCallFromLlm inst, RoleDialogModel message)
+ {
+ inst.AgentName = null;
+ return true;
+ }
+
+ private string GetNextStepPrompt(Agent router)
+ {
+ var template = router.Templates.First(x => x.Name == "next_step_prompt").Content;
+
+ var render = _services.GetRequiredService();
+ return render.Render(template, new Dictionary
+ {
+ });
+ }
+}
diff --git a/src/Infrastructure/BotSharp.Core/Planning/InstructExecutor.cs b/src/Infrastructure/BotSharp.Core/Planning/InstructExecutor.cs
new file mode 100644
index 00000000..c6588ef8
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Core/Planning/InstructExecutor.cs
@@ -0,0 +1,45 @@
+using BotSharp.Abstraction.Agents.Models;
+using BotSharp.Abstraction.Functions.Models;
+using BotSharp.Abstraction.Planning;
+using BotSharp.Abstraction.Routing;
+
+namespace BotSharp.Core.Planning;
+
+public class InstructExecutor : IExecutor
+{
+ private readonly IServiceProvider _services;
+ private readonly ILogger _logger;
+
+ public InstructExecutor(IServiceProvider services, ILogger logger)
+ {
+ _services = services;
+ _logger = logger;
+ }
+
+ public async Task Execute(IRoutingService routing,
+ Agent router,
+ FunctionCallFromLlm inst,
+ List dialogs,
+ RoleDialogModel message)
+ {
+ // Set user content as Planner's question
+ inst.Question = message.Content;
+ message.Instruction = inst;
+
+ var handlers = _services.GetServices();
+
+ var handler = handlers.FirstOrDefault(x => x.Name == inst.Function);
+ handler.SetRouter(router);
+ handler.SetDialogs(dialogs);
+
+ message.FunctionName = inst.Function;
+ message.Role = AgentRole.Function;
+ message.FunctionArgs = inst.Arguments == null ? "{}" : JsonSerializer.Serialize(inst.Arguments);
+
+ var handled = await handler.Handle(routing, inst, message);
+
+ inst.Response = message.Content;
+
+ return handled;
+ }
+}
diff --git a/src/Infrastructure/BotSharp.Core/Planning/NaivePlanner.cs b/src/Infrastructure/BotSharp.Core/Planning/NaivePlanner.cs
new file mode 100644
index 00000000..c9aaf783
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Core/Planning/NaivePlanner.cs
@@ -0,0 +1,76 @@
+using BotSharp.Abstraction.Agents.Models;
+using BotSharp.Abstraction.Functions.Models;
+using BotSharp.Abstraction.Planning;
+using BotSharp.Abstraction.Templating;
+
+namespace BotSharp.Core.Planning;
+
+public class NaivePlanner : IPlaner
+{
+ private readonly IServiceProvider _services;
+ private readonly ILogger _logger;
+
+ public NaivePlanner(IServiceProvider services, ILogger logger)
+ {
+ _services = services;
+ _logger = logger;
+ }
+
+ public async Task GetNextInstruction(Agent router, string conversation)
+ {
+ var next = GetNextStepPrompt(router);
+
+ RoleDialogModel response = default;
+ var inst = new FunctionCallFromLlm();
+
+ var agentService = _services.GetRequiredService();
+ var instruction = agentService.RenderedInstruction(router);
+ var content = $"{instruction}\r\n{conversation}\r\n###\r\n{next}";
+
+ // text completion
+ content = content + "\r\nResponse: ";
+
+ var completion = CompletionProvider.GetTextCompletion(_services);
+
+ int retryCount = 0;
+ while (retryCount < 3)
+ {
+ try
+ {
+ var text = await completion.GetCompletion(content);
+ response = new RoleDialogModel(AgentRole.Assistant, text);
+ 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++;
+ }
+ }
+
+ return inst;
+ }
+
+ public async Task AgentExecuted(FunctionCallFromLlm inst, RoleDialogModel message)
+ {
+ inst.AgentName = null;
+ return true;
+ }
+
+ private string GetNextStepPrompt(Agent router)
+ {
+ var template = router.Templates.First(x => x.Name == "next_step_prompt").Content;
+
+ var render = _services.GetRequiredService();
+ return render.Render(template, new Dictionary
+ {
+ });
+ }
+}
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/ContinueExecuteTaskRoutingHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/ContinueExecuteTaskRoutingHandler.cs
index 1c809ef4..10724208 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/ContinueExecuteTaskRoutingHandler.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/Handlers/ContinueExecuteTaskRoutingHandler.cs
@@ -12,14 +12,20 @@ public class ContinueExecuteTaskRoutingHandler : RoutingHandlerBase, IRoutingHan
public string Description => "Continue to execute user's request without further information retrival.";
- public List Parameters => new List
+ public List Parameters => new List
{
- new NameDesc("agent", "the name of the agent"),
- new NameDesc("args", "required parameters extracted from question"),
- new NameDesc("reason", "why continue to execute current task")
+ new ParameterPropertyDef("agent", "the name of the agent"),
+ new ParameterPropertyDef("reason", "why continue to execute current task"),
+ new ParameterPropertyDef("args", "required parameters extracted from question")
+ {
+ Type = "object"
+ }
};
- public bool IsReasoning => true;
+ public List Planers => new List
+ {
+ "FeedbackReasoningPlanner"
+ };
public ContinueExecuteTaskRoutingHandler(IServiceProvider services, ILogger logger, RoutingSettings settings)
: base(services, logger, settings)
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/ConversationEndRoutingHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/ConversationEndRoutingHandler.cs
index 97eafa46..754016d0 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/ConversationEndRoutingHandler.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/Handlers/ConversationEndRoutingHandler.cs
@@ -11,12 +11,10 @@ public class ConversationEndRoutingHandler : RoutingHandlerBase, IRoutingHandler
public string Description => "User completed his task and wants to end the conversation.";
- public bool IsReasoning => false;
-
- public List Parameters => new List
+ public List Parameters => new List
{
- new NameDesc("reason", "why end conversation"),
- new NameDesc("response", "response content to user")
+ new ParameterPropertyDef("reason", "why end conversation"),
+ new ParameterPropertyDef("response", "response content to user")
};
public ConversationEndRoutingHandler(IServiceProvider services, ILogger logger, RoutingSettings settings)
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/HumanInterventionNeededHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/HumanInterventionNeededHandler.cs
index 671dc644..612f6722 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/HumanInterventionNeededHandler.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/Handlers/HumanInterventionNeededHandler.cs
@@ -1,5 +1,4 @@
using BotSharp.Abstraction.Functions.Models;
-using BotSharp.Abstraction.Models;
using BotSharp.Abstraction.Routing;
using BotSharp.Abstraction.Routing.Settings;
@@ -11,10 +10,10 @@ public class HumanInterventionNeededHandler : RoutingHandlerBase, IRoutingHandle
public string Description => "Reach out to human being, customer service or customer representative.";
- public List Parameters => new List
+ public List Parameters => new List
{
- new NameDesc("reason", "why need customer service"),
- new NameDesc("response", "response content to user")
+ new ParameterPropertyDef("reason", "why need customer service"),
+ new ParameterPropertyDef("response", "response content to user")
};
public HumanInterventionNeededHandler(IServiceProvider services, ILogger logger, RoutingSettings settings)
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/InterruptTaskExecutionRoutingHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/InterruptTaskExecutionRoutingHandler.cs
index 76d18be3..9932777d 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/InterruptTaskExecutionRoutingHandler.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/Handlers/InterruptTaskExecutionRoutingHandler.cs
@@ -1,5 +1,4 @@
using BotSharp.Abstraction.Functions.Models;
-using BotSharp.Abstraction.Models;
using BotSharp.Abstraction.Routing;
using BotSharp.Abstraction.Routing.Settings;
@@ -11,13 +10,16 @@ public class InterruptTaskExecutionRoutingHandler : RoutingHandlerBase, IRouting
public string Description => "Can't continue user's request becauase the requirements are not met.";
- public List Parameters => new List
+ public List Parameters => new List
{
- new NameDesc("reason", "the reason why the request is interrupted"),
- new NameDesc("answer", "the content response to user")
+ new ParameterPropertyDef("reason", "the reason why the request is interrupted"),
+ new ParameterPropertyDef("answer", "the content response to user")
};
- public bool IsReasoning => true;
+ public List Planers => new List
+ {
+ "FeedbackReasoningPlanner"
+ };
public InterruptTaskExecutionRoutingHandler(IServiceProvider services, ILogger logger, RoutingSettings settings)
: base(services, logger, settings)
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/ResponseToUserRoutingHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/ResponseToUserRoutingHandler.cs
index cb480e56..b4e399a7 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/ResponseToUserRoutingHandler.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/Handlers/ResponseToUserRoutingHandler.cs
@@ -11,12 +11,10 @@ public class ResponseToUserRoutingHandler : RoutingHandlerBase, IRoutingHandler
public string Description => "Response according to the context without asking specific agent.";
- public bool IsReasoning => false;
-
- public List Parameters => new List
+ public List Parameters => new List
{
- new NameDesc("reason", "why response to user"),
- new NameDesc("response", "response content")
+ new ParameterPropertyDef("reason", "why response to user"),
+ new ParameterPropertyDef("response", "response content")
};
public ResponseToUserRoutingHandler(IServiceProvider services, ILogger logger, RoutingSettings settings)
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/RetrieveDataFromAgentRoutingHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/RetrieveDataFromAgentRoutingHandler.cs
index 3b30c19d..aa2cbce3 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/RetrieveDataFromAgentRoutingHandler.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/Handlers/RetrieveDataFromAgentRoutingHandler.cs
@@ -1,5 +1,4 @@
using BotSharp.Abstraction.Functions.Models;
-using BotSharp.Abstraction.Models;
using BotSharp.Abstraction.Repositories;
using BotSharp.Abstraction.Routing;
using BotSharp.Abstraction.Routing.Settings;
@@ -12,15 +11,21 @@ public class RetrieveDataFromAgentRoutingHandler : RoutingHandlerBase, IRoutingH
public string Description => "Retrieve data from appropriate agent.";
- public List Parameters => new List
+ public List Parameters => new List
{
- new NameDesc("agent", "the name of the agent"),
- new NameDesc("question", "the question you will ask the agent to get the necessary data"),
- new NameDesc("reason", "why retrieve data"),
- new NameDesc("args", "required parameters extracted from question and hand over to the next agent")
+ new ParameterPropertyDef("agent", "the name of the agent"),
+ new ParameterPropertyDef("question", "the question you will ask the agent to get the necessary data"),
+ new ParameterPropertyDef("reason", "why retrieve data"),
+ new ParameterPropertyDef("args", "required parameters extracted from question and hand over to the next agent")
+ {
+ Type = "object"
+ }
};
- public bool IsReasoning => true;
+ public List Planers => new List
+ {
+ "FeedbackReasoningPlanner"
+ };
public RetrieveDataFromAgentRoutingHandler(IServiceProvider services, ILogger logger, RoutingSettings settings)
: base(services, logger, settings)
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs
index daa4e734..cd614e91 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs
@@ -1,6 +1,5 @@
using BotSharp.Abstraction.Functions;
using BotSharp.Abstraction.Functions.Models;
-using BotSharp.Abstraction.Models;
using BotSharp.Abstraction.Routing;
using BotSharp.Abstraction.Routing.Models;
using BotSharp.Abstraction.Routing.Settings;
@@ -13,16 +12,17 @@ public class RouteToAgentRoutingHandler : RoutingHandlerBase, IRoutingHandler
public string Description => "Route request to appropriate agent.";
- public List Parameters => new List
+ public List Parameters => new List
{
- new NameDesc("reason", "why route to agent"),
- new NameDesc("next_action_agent", "agent for next action based on user latest response"),
- new NameDesc("user_goal_agent", "agent who can achieve user original goal"),
- new NameDesc("args", "useful parameters of next action agent")
+ new ParameterPropertyDef("reason", "why route to agent"),
+ 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("args", "useful parameters of next action agent, format: { }")
+ {
+ Type = "object"
+ }
};
- public bool IsReasoning => false;
-
public RouteToAgentRoutingHandler(IServiceProvider services, ILogger logger, RoutingSettings settings)
: base(services, logger, settings)
{
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/TaskEndRoutingHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/TaskEndRoutingHandler.cs
index edb2cfc9..656302e5 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/TaskEndRoutingHandler.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/Handlers/TaskEndRoutingHandler.cs
@@ -1,5 +1,4 @@
using BotSharp.Abstraction.Functions.Models;
-using BotSharp.Abstraction.Models;
using BotSharp.Abstraction.Routing;
using BotSharp.Abstraction.Routing.Settings;
@@ -11,12 +10,15 @@ public class TaskEndRoutingHandler : RoutingHandlerBase, IRoutingHandler
public string Description => "Call this function when current task is completed.";
- public List Parameters => new List
+ public List Parameters => new List
{
- new NameDesc("abandoned_arguments", "the arguments next task can't reuse")
+ new ParameterPropertyDef("abandoned_arguments", "the arguments next task can't reuse")
};
- public bool IsReasoning => true;
+ public List Planers => new List
+ {
+ "FeedbackReasoningPlanner"
+ };
public TaskEndRoutingHandler(IServiceProvider services, ILogger logger, RoutingSettings settings)
: base(services, logger, settings)
diff --git a/src/Infrastructure/BotSharp.Core/Routing/RouterInstance.cs b/src/Infrastructure/BotSharp.Core/Routing/RouterInstance.cs
index 2ee8e023..1c6f4e54 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/RouterInstance.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/RouterInstance.cs
@@ -1,6 +1,6 @@
using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Functions.Models;
-using BotSharp.Abstraction.Models;
+using BotSharp.Abstraction.Planning;
using BotSharp.Abstraction.Repositories;
using BotSharp.Abstraction.Routing;
using BotSharp.Abstraction.Routing.Models;
@@ -36,8 +36,10 @@ public class RouterInstance : IRouterInstance
public List GetHandlers()
{
+ var planer = _services.GetRequiredService();
+
return _services.GetServices()
- .Where(x => x.IsReasoning == _settings.EnableReasoning)
+ .Where(x => x.Planers == null || x.Planers.Contains(planer.GetType().Name))
.Where(x => !string.IsNullOrEmpty(x.Description))
.Select((x, i) => new RoutingHandlerDef
{
@@ -90,10 +92,11 @@ public class RouterInstance : IRouterInstance
AgentId = x.Id,
Description = x.Description,
Name = x.Name,
- RequiredFields = x.RoutingRules
- .Where(x => x.Required)
- .Select(p => new ParameterPropertyDef(p.Field, p.Description, type: p.Type))
- .ToList()
+ Fields = x.RoutingRules
+ .Select(p => new ParameterPropertyDef(p.Field, p.Description, type: p.Type)
+ {
+ Required = p.Required
+ }).ToList()
}).ToArray();
}
diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.FixMalformedResponse.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.FixMalformedResponse.cs
new file mode 100644
index 00000000..1818924c
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.FixMalformedResponse.cs
@@ -0,0 +1,56 @@
+using BotSharp.Abstraction.Functions.Models;
+
+namespace BotSharp.Core.Routing;
+
+public partial class RoutingService
+{
+ ///
+ /// Sometimes LLM hallucinates and fails to set function names correctly.
+ ///
+ ///
+ private void FixMalformedResponse(FunctionCallFromLlm args)
+ {
+ var agentService = _services.GetRequiredService();
+ var agents = agentService.GetAgents(allowRouting: true).Result;
+ var malformed = false;
+
+ // Sometimes it populate malformed Function in Agent name
+ if (!string.IsNullOrEmpty(args.Function) &&
+ args.Function == args.AgentName)
+ {
+ args.Function = "route_to_agent";
+ malformed = true;
+ }
+
+ // Another case of malformed response
+ if (string.IsNullOrEmpty(args.AgentName) &&
+ agents.Select(x => x.Name).Contains(args.Function))
+ {
+ args.AgentName = args.Function;
+ args.Function = "route_to_agent";
+ malformed = true;
+ }
+
+ // It should be Route to agent, but it is used as Response to user.
+ if (!string.IsNullOrEmpty(args.AgentName) &&
+ agents.Select(x => x.Name).Contains(args.AgentName) &&
+ args.Function != "route_to_agent")
+ {
+ args.Function = "route_to_agent";
+ malformed = true;
+ }
+
+ // Function name shouldn't contain dot symbol
+ if (!string.IsNullOrEmpty(args.Function) &&
+ args.Function.Contains('.'))
+ {
+ args.Function = args.Function.Split('.').Last();
+ malformed = true;
+ }
+
+ if (malformed)
+ {
+ _logger.LogWarning($"Captured LLM malformed response");
+ }
+ }
+}
diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.GetConversationContent.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.GetConversationContent.cs
new file mode 100644
index 00000000..bd883314
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.GetConversationContent.cs
@@ -0,0 +1,24 @@
+namespace BotSharp.Core.Routing;
+
+public partial class RoutingService
+{
+ public async Task GetConversationContent(List dialogs, int maxDialogCount = 50)
+ {
+ var agentService = _services.GetRequiredService();
+ var conversation = "";
+
+ foreach (var dialog in dialogs.TakeLast(maxDialogCount))
+ {
+ var role = dialog.Role;
+ if (role != AgentRole.User)
+ {
+ var agent = await agentService.GetAgent(dialog.CurrentAgentId);
+ role = agent.Name;
+ }
+
+ conversation += $"{role}: {dialog.Content}\r\n";
+ }
+
+ return conversation;
+ }
+}
diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.GetNextInstruction.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.GetNextInstruction.cs
deleted file mode 100644
index e217dd89..00000000
--- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.GetNextInstruction.cs
+++ /dev/null
@@ -1,187 +0,0 @@
-using BotSharp.Abstraction.Functions.Models;
-using BotSharp.Abstraction.Templating;
-using System.Drawing;
-using System.Text.RegularExpressions;
-namespace BotSharp.Core.Routing;
-
-public partial class RoutingService
-{
- public async Task GetNextInstruction()
- {
- var content = GetNextStepPrompt();
-
- RoleDialogModel response = default;
- var args = new FunctionCallFromLlm();
-
- if (_settings.UseTextCompletion)
- {
- var completion = CompletionProvider.GetTextCompletion(_services,
- provider: _settings.Provider,
- model: _settings.Model);
-
- content = _routerInstance.Router.Instruction + "\r\n\r\n" + content + "\r\nResponse: ";
-
- int retryCount = 0;
-
- while (retryCount < 3)
- {
- try
- {
- var text = await completion.GetCompletion(content);
- response = new RoleDialogModel(AgentRole.Assistant, text);
-
- var pattern = @"\{(?:[^{}]|(?\{)|(?<-open>\}))+(?(open)(?!))\}";
- response.Content = Regex.Match(response.Content, pattern).Value;
- args = JsonSerializer.Deserialize(response.Content);
- break;
- }
- catch (Exception ex)
- {
- _logger.LogError($"{ex.Message}: {response.Content}");
- args.Function = "response_to_user";
- args.Response = ex.Message;
- args.AgentName = "Router";
- content += "\r\nPlease response in JSON format.";
- }
- finally
- {
- retryCount++;
- }
- }
- }
- else
- {
- var completion = CompletionProvider.GetChatCompletion(_services,
- provider: _settings.Provider,
- 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(50))
- {
- 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}";
-
- response = completion.GetChatCompletions(_routerInstance.Router, new List
- {
- new RoleDialogModel(AgentRole.User, content)
- });
-
- args = response.Content.JsonContent();
- break;
- }
- catch (Exception ex)
- {
- _logger.LogError($"{ex.Message}: {response.Content}");
- args.Function = "response_to_user";
- args.Response = ex.Message;
- args.AgentName = "Router";
- content += "\r\nPlease response in JSON format.";
- }
- finally
- {
- retryCount++;
- }
- }
- }
-
-#if DEBUG
- Console.WriteLine(response.Content, Color.Green);
-#else
- _logger.LogInformation(response.Content);
-#endif
-
- // Fix LLM malformed response
- FixMalformedResponse(args);
-
- SaveStateByArgs(args.Arguments);
-
-#if DEBUG
- Console.WriteLine($"*** Next Instruction *** {args}", Color.Green);
-#else
- _logger.LogInformation($"*** Next Instruction *** {args}");
-#endif
-
- return args;
- }
-
- private string GetNextStepPrompt()
- {
- var template = _routerInstance.Router.Templates.First(x => x.Name == "next_step_prompt").Content;
-
- // If enabled reasoning
- // JsonSerializer.Serialize(new FunctionCallFromLlm());
-
- var render = _services.GetRequiredService();
- return render.Render(template, new Dictionary
- {
- { "enabled_reasoning", _settings.EnableReasoning }
- });
- }
-
- ///
- /// Sometimes LLM hallucinates and fails to set function names correctly.
- ///
- ///
- private void FixMalformedResponse(FunctionCallFromLlm args)
- {
- var agentService = _services.GetRequiredService();
- var agents = agentService.GetAgents(allowRouting: true).Result;
- var malformed = false;
-
- // Sometimes it populate malformed Function in Agent name
- if (!string.IsNullOrEmpty(args.Function) &&
- args.Function == args.AgentName)
- {
- args.Function = "route_to_agent";
- malformed = true;
- }
-
- // Another case of malformed response
- if (string.IsNullOrEmpty(args.AgentName) &&
- agents.Select(x => x.Name).Contains(args.Function))
- {
- args.AgentName = args.Function;
- args.Function = "route_to_agent";
- malformed = true;
- }
-
- // It should be Route to agent, but it is used as Response to user.
- if (!string.IsNullOrEmpty(args.AgentName) &&
- agents.Select(x => x.Name).Contains(args.AgentName) &&
- args.Function != "route_to_agent")
- {
- args.Function = "route_to_agent";
- malformed = true;
- }
-
- // Function name shouldn't contain dot symbol
- if (!string.IsNullOrEmpty(args.Function) &&
- args.Function.Contains('.'))
- {
- args.Function = args.Function.Split('.').Last();
- malformed = true;
- }
-
- if (malformed)
- {
- _logger.LogWarning($"Captured LLM malformed response");
- }
- }
-}
diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs
index b7073f04..25d4732b 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs
@@ -1,7 +1,9 @@
using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Functions.Models;
+using BotSharp.Abstraction.Planning;
using BotSharp.Abstraction.Routing;
using BotSharp.Abstraction.Routing.Settings;
+using System.Drawing;
namespace BotSharp.Core.Routing;
@@ -69,7 +71,8 @@ public partial class RoutingService : IRoutingService
_routerInstance.Load();
var router = _routerInstance.Router;
- var handlers = _services.GetServices();
+ var planner = _services.GetRequiredService();
+ var executor = _services.GetRequiredService();
int loopCount = 0;
var stop = false;
@@ -77,28 +80,33 @@ public partial class RoutingService : IRoutingService
{
loopCount++;
- var inst = await GetNextInstruction();
- message.Instruction = inst;
- inst.Question = message.Content;
+ var conversation = await GetConversationContent(Dialogs);
- var handler = handlers.FirstOrDefault(x => x.Name == inst.Function);
- if (handler == null)
+ // Get instruction from Planner
+ var inst = await planner.GetNextInstruction(router, conversation);
+
+ // Fix LLM malformed response
+ FixMalformedResponse(inst);
+
+ // Save states
+ SaveStateByArgs(inst.Arguments);
+
+#if DEBUG
+ Console.WriteLine($"*** Next Instruction *** {inst}", Color.GreenYellow);
+#else
+ _logger.LogInformation($"*** Next Instruction *** {inst}");
+#endif
+
+ // Handle instruction by Executor
+ var executed = await executor.Execute(this, router, inst, Dialogs, message);
+
+ await planner.AgentExecuted(inst, message);
+
+ // There is no need for the agent to continue processing, indicating that the task has been completed.
+ if (inst.AgentName == null)
{
- handler = handlers.FirstOrDefault(x => x.Name == "get_next_instruction");
- continue;
+ break;
}
- handler.SetRouter(router);
- handler.SetDialogs(Dialogs);
-
- 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 true;
diff --git a/src/Infrastructure/BotSharp.Core/Templating/TemplateRender.cs b/src/Infrastructure/BotSharp.Core/Templating/TemplateRender.cs
index 64a8608f..3aba223f 100644
--- a/src/Infrastructure/BotSharp.Core/Templating/TemplateRender.cs
+++ b/src/Infrastructure/BotSharp.Core/Templating/TemplateRender.cs
@@ -39,6 +39,7 @@ public class TemplateRender : ITemplateRender
}
else
{
+ _logger.LogWarning(error);
return template;
}
}
diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs
index c34bf42a..3af20b6c 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs
@@ -31,23 +31,10 @@ public class InstructModeController : ControllerBase, IApiAdapter
.SetState("model", input.Model)
.SetState("input_text", input.Text);
- var agentService = _services.GetRequiredService();
- Agent agent = await agentService.LoadAgent(agentId);
-
- // switch to different instruction template
- if (!string.IsNullOrEmpty(input.Template))
- {
- var template = agent.Templates.First(x => x.Name == input.Template).Content;
- var render = _services.GetRequiredService();
- var dict = new Dictionary();
- state.GetStates().Select(x => dict[x.Key] = x.Value).ToArray();
- var prompt = render.Render(template, dict);
- agent.Instruction = prompt;
- }
-
var instructor = _services.GetRequiredService();
- var result = await instructor.Execute(agent,
- new RoleDialogModel(AgentRole.User, input.Text));
+ var result = await instructor.Execute(agentId,
+ new RoleDialogModel(AgentRole.User, input.Text),
+ templateName: input.Template);
result.States = state.GetStates();
diff --git a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs
index bd2933f3..651c2906 100644
--- a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs
+++ b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs
@@ -1,5 +1,6 @@
using Azure;
using Azure.AI.OpenAI;
+using BotSharp.Abstraction.Agents;
using BotSharp.Abstraction.Agents.Enums;
using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Conversations;
@@ -73,6 +74,12 @@ public class ChatCompletionProvider : IChatCompletion
}
}
+ var setting = _services.GetRequiredService();
+ if (setting.ShowVerboseLog)
+ {
+ _logger.LogInformation(msg.Content);
+ }
+
// After chat completion hook
Task.WaitAll(hooks.Select(hook =>
hook.AfterGenerated(msg, new TokenStatsModel
@@ -193,11 +200,14 @@ public class ChatCompletionProvider : IChatCompletion
protected ChatCompletionsOptions PrepareOptions(Agent agent, List conversations)
{
+ var agentService = _services.GetRequiredService();
+
var chatCompletionsOptions = new ChatCompletionsOptions();
if (!string.IsNullOrEmpty(agent.Instruction))
{
- chatCompletionsOptions.Messages.Add(new ChatMessage(ChatRole.System, agent.Instruction));
+ var instruction = agentService.RenderedInstruction(agent);
+ chatCompletionsOptions.Messages.Add(new ChatMessage(ChatRole.System, instruction));
}
if (!string.IsNullOrEmpty(agent.Knowledges))
diff --git a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ProviderHelper.cs b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ProviderHelper.cs
index e3411fcc..caaa520f 100644
--- a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ProviderHelper.cs
+++ b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ProviderHelper.cs
@@ -11,7 +11,7 @@ public class ProviderHelper
{
public static OpenAIClient GetClient(string model, AzureOpenAiSettings settings)
{
- if (model == "gpt-4")
+ if (model == "gpt-4" || model == "llm-gpt4")
{
var client = new OpenAIClient(new Uri(settings.GPT4.Endpoint), new AzureKeyCredential(settings.GPT4.ApiKey));
return client;
diff --git a/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/ChatCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/ChatCompletionProvider.cs
index 0495799d..9733f39b 100644
--- a/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/ChatCompletionProvider.cs
+++ b/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/ChatCompletionProvider.cs
@@ -1,3 +1,4 @@
+using BotSharp.Abstraction.Agents;
using BotSharp.Abstraction.Agents.Enums;
using BotSharp.Abstraction.Conversations;
using BotSharp.Plugin.GoogleAI.Settings;
@@ -35,7 +36,9 @@ public class ChatCompletionProvider : IChatCompletion
var messages = conversations.Select(c => new PalmChatMessage(c.Content, c.Role == AgentRole.User ? "user" : "AI"))
.ToList();
- var response = client.ChatAsync(messages, agent.Instruction, null).Result;
+ var agentService = _services.GetRequiredService();
+ var instruction = agentService.RenderedInstruction(agent);
+ var response = client.ChatAsync(messages, instruction, null).Result;
var message = response.Candidates.First();
var msg = new RoleDialogModel(AgentRole.Assistant, message.Content)
diff --git a/src/Plugins/BotSharp.Plugin.HuggingFace/Providers/ChatCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.HuggingFace/Providers/ChatCompletionProvider.cs
index db6daf4f..8756c7b5 100644
--- a/src/Plugins/BotSharp.Plugin.HuggingFace/Providers/ChatCompletionProvider.cs
+++ b/src/Plugins/BotSharp.Plugin.HuggingFace/Providers/ChatCompletionProvider.cs
@@ -1,3 +1,4 @@
+using BotSharp.Abstraction.Agents;
using BotSharp.Abstraction.Agents.Enums;
using BotSharp.Abstraction.Conversations.Settings;
using BotSharp.Plugin.HuggingFace.Services;
@@ -97,7 +98,9 @@ public class ChatCompletionProvider : IChatCompletion
var content = string.Join("\r\n", conversations.Select(x => $"{AgentRole.System}: {x.Content}")).Trim();
content += $"\r\n{AgentRole.Assistant}: ";
- var prompt = agent.Instruction + "\r\n" + content;
+ var agentService = _services.GetRequiredService();
+ var instruction = agentService.RenderedInstruction(agent);
+ var prompt = instruction + "\r\n" + content;
var convSetting = _services.GetRequiredService();
if (convSetting.ShowVerboseLog)
diff --git a/src/Plugins/BotSharp.Plugin.LLamaSharp/Providers/ChatCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.LLamaSharp/Providers/ChatCompletionProvider.cs
index adf452e0..9dc0d7e5 100644
--- a/src/Plugins/BotSharp.Plugin.LLamaSharp/Providers/ChatCompletionProvider.cs
+++ b/src/Plugins/BotSharp.Plugin.LLamaSharp/Providers/ChatCompletionProvider.cs
@@ -1,3 +1,5 @@
+using BotSharp.Abstraction.Agents;
+
namespace BotSharp.Plugin.LLamaSharp.Providers;
public class ChatCompletionProvider : IChatCompletion
@@ -42,7 +44,9 @@ public class ChatCompletionProvider : IChatCompletion
string totalResponse = "";
- var prompt = agent.Instruction + "\r\n" + content;
+ var agentService = _services.GetRequiredService();
+ var instruction = agentService.RenderedInstruction(agent);
+ var prompt = instruction + "\r\n" + content;
var convSetting = _services.GetRequiredService();
if (convSetting.ShowVerboseLog)
diff --git a/src/WebStarter/appsettings.json b/src/WebStarter/appsettings.json
index 318c4298..ed51f673 100644
--- a/src/WebStarter/appsettings.json
+++ b/src/WebStarter/appsettings.json
@@ -15,8 +15,7 @@
"Router": {
"RouterId": "01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a",
- "UseTextCompletion": false,
- "EnableReasoning": false,
+ "Planner": "NaivePlanner",
"Provider": "azure-openai",
"Model": "gpt-3.5-turbo"
},
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 67cd6d1a..7b4d552d 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
@@ -9,23 +9,24 @@ You're {{router.name}} ({{router.description}}). Follow these steps to handle us
{% for handler in routing_handlers %}
# {{ handler.description}}
{% if handler.parameters and handler.parameters != empty -%}
-Response: { "function": "{{ handler.name }}",
+Parameters:
+ - function: {{ handler.name }}
{% for p in handler.parameters -%}
- "{{ p.name }}": "{{ p.description }}"{{ ",\r\n " }}
- {%- endfor %}}
+ - {{ p.name }}: {{ p.description }}{{ "\r\n " }}
+ {%- endfor %}
{%- endif %}
{% endfor %}
[AGENTS]
{% for agent in routing_agents %}
-* Agent: {{ agent.name }}
-{{ agent.description}}
-{% if agent.required_fields and agent.required_fields != empty -%}
-Required args:
- {% for f in agent.required_fields -%}
- - {{ f.name }} ({{ f.type }}): {{ f.description }}{{ "\r\n " }}
+* {{ agent.description}}
+Agent: {{ agent.name }}
+{% if agent.fields and agent.fields != empty -%}
+Arguments:
+ {% for f in agent.fields -%}
+ - {{ f.name }}: {{ f.description }} (type: {{ f.type }}, required: {{f.required}}){{ "\r\n " }}
{%- endfor %}
{%- endif %}
{% endfor %}
-[CONVERSATION]
+[CONVERSATION]
\ No newline at end of file
diff --git a/src/WebStarter/data/agents/b284db86-e9c2-4c25-a59e-4649797dd130/agent.json b/src/WebStarter/data/agents/b284db86-e9c2-4c25-a59e-4649797dd130/agent.json
index 14d27b26..6b2a2771 100644
--- a/src/WebStarter/data/agents/b284db86-e9c2-4c25-a59e-4649797dd130/agent.json
+++ b/src/WebStarter/data/agents/b284db86-e9c2-4c25-a59e-4649797dd130/agent.json
@@ -5,5 +5,13 @@
"updatedDateTime": "2023-08-18T14:39:32.2349686Z",
"id": "b284db86-e9c2-4c25-a59e-4649797dd130",
"allowRouting": true,
- "isPublic": true
+ "isPublic": true,
+ "routingRules": [
+ {
+ "field": "order_number",
+ "description": "order number",
+ "type": "string",
+ "redirectTo": "c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd"
+ }
+ ]
}
\ No newline at end of file