2023-09-19 12:17:50 +00:00
|
|
|
using BotSharp.Abstraction.Agents.Models;
|
2023-09-23 21:33:05 +00:00
|
|
|
using BotSharp.Abstraction.Functions.Models;
|
2023-10-28 20:59:26 +00:00
|
|
|
using BotSharp.Abstraction.Planning;
|
2023-11-01 01:48:12 +00:00
|
|
|
using BotSharp.Abstraction.Repositories;
|
2023-09-19 12:17:50 +00:00
|
|
|
using BotSharp.Abstraction.Routing;
|
2023-10-29 01:54:10 +00:00
|
|
|
using BotSharp.Abstraction.Routing.Models;
|
2023-09-20 10:31:50 +00:00
|
|
|
using BotSharp.Abstraction.Routing.Settings;
|
2023-10-28 20:59:26 +00:00
|
|
|
using System.Drawing;
|
2023-09-27 12:51:15 +00:00
|
|
|
|
2023-09-19 12:17:50 +00:00
|
|
|
namespace BotSharp.Core.Routing;
|
|
|
|
|
|
2023-09-27 12:51:15 +00:00
|
|
|
public partial class RoutingService : IRoutingService
|
2023-09-19 12:17:50 +00:00
|
|
|
{
|
|
|
|
|
private readonly IServiceProvider _services;
|
2023-09-20 10:31:50 +00:00
|
|
|
private readonly RoutingSettings _settings;
|
2023-09-19 12:17:50 +00:00
|
|
|
private readonly ILogger _logger;
|
2023-10-30 16:48:18 +00:00
|
|
|
private Agent _router;
|
|
|
|
|
public Agent Router => _router;
|
2023-09-19 12:17:50 +00:00
|
|
|
|
2023-10-20 23:57:45 +00:00
|
|
|
public void ResetRecursiveCounter()
|
|
|
|
|
{
|
|
|
|
|
_currentRecursionDepth = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-20 10:31:50 +00:00
|
|
|
public RoutingService(IServiceProvider services,
|
|
|
|
|
RoutingSettings settings,
|
2023-11-01 01:48:12 +00:00
|
|
|
ILogger<RoutingService> logger)
|
2023-09-19 12:17:50 +00:00
|
|
|
{
|
|
|
|
|
_services = services;
|
2023-09-20 10:31:50 +00:00
|
|
|
_settings = settings;
|
2023-09-19 12:17:50 +00:00
|
|
|
_logger = logger;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-30 16:48:18 +00:00
|
|
|
public async Task<RoleDialogModel> ExecuteOnce(Agent agent, RoleDialogModel message)
|
2023-09-23 21:33:05 +00:00
|
|
|
{
|
|
|
|
|
var handlers = _services.GetServices<IRoutingHandler>();
|
|
|
|
|
|
|
|
|
|
var handler = handlers.FirstOrDefault(x => x.Name == "route_to_agent");
|
2023-10-30 16:48:18 +00:00
|
|
|
var dialogs = new List<RoleDialogModel> { message };
|
|
|
|
|
handler.SetDialogs(dialogs);
|
2023-10-27 20:36:26 +00:00
|
|
|
|
2023-10-30 16:48:18 +00:00
|
|
|
var inst = new FunctionCallFromLlm
|
2023-09-23 21:33:05 +00:00
|
|
|
{
|
2023-09-25 22:46:00 +00:00
|
|
|
Function = "route_to_agent",
|
2023-10-27 20:36:26 +00:00
|
|
|
Question = message.Content,
|
|
|
|
|
Reason = message.Content,
|
2023-09-25 22:46:00 +00:00
|
|
|
AgentName = agent.Name
|
2023-10-30 16:48:18 +00:00
|
|
|
};
|
2023-09-23 21:33:05 +00:00
|
|
|
|
2023-10-30 16:48:18 +00:00
|
|
|
var result = await handler.Handle(this, inst, message);
|
|
|
|
|
|
|
|
|
|
var response = dialogs.Last();
|
|
|
|
|
response.MessageId = message.MessageId;
|
|
|
|
|
response.Instruction = inst;
|
|
|
|
|
|
|
|
|
|
return response;
|
2023-09-23 21:33:05 +00:00
|
|
|
}
|
|
|
|
|
|
2023-10-30 16:48:18 +00:00
|
|
|
public async Task<RoleDialogModel> InstructLoop(RoleDialogModel message)
|
2023-09-19 12:17:50 +00:00
|
|
|
{
|
2023-11-01 01:48:12 +00:00
|
|
|
var agentService = _services.GetRequiredService<IAgentService>();
|
|
|
|
|
_router = await agentService.LoadAgent(_settings.RouterId);
|
2023-10-30 16:48:18 +00:00
|
|
|
|
|
|
|
|
RoleDialogModel response = default;
|
|
|
|
|
|
2023-11-01 01:48:12 +00:00
|
|
|
var states = _services.GetRequiredService<IConversationStateService>();
|
2023-10-30 16:48:18 +00:00
|
|
|
var conv = _services.GetRequiredService<IConversationService>();
|
|
|
|
|
var dialogs = conv.GetDialogHistory();
|
2023-09-27 12:51:15 +00:00
|
|
|
|
2023-10-29 01:54:10 +00:00
|
|
|
var context = _services.GetRequiredService<RoutingContext>();
|
2023-10-28 20:59:26 +00:00
|
|
|
var planner = _services.GetRequiredService<IPlaner>();
|
|
|
|
|
var executor = _services.GetRequiredService<IExecutor>();
|
2023-09-22 20:38:58 +00:00
|
|
|
|
2023-10-30 16:48:18 +00:00
|
|
|
context.Push(_router.Id);
|
|
|
|
|
|
2023-09-19 12:17:50 +00:00
|
|
|
int loopCount = 0;
|
2023-10-30 16:48:18 +00:00
|
|
|
while (loopCount < 5 && !context.IsEmpty)
|
2023-09-19 12:17:50 +00:00
|
|
|
{
|
|
|
|
|
loopCount++;
|
|
|
|
|
|
2023-10-30 16:48:18 +00:00
|
|
|
var conversation = await GetConversationContent(dialogs);
|
|
|
|
|
_router.TemplateDict["conversation"] = conversation;
|
2023-11-01 01:48:12 +00:00
|
|
|
_router.TemplateDict["planner"] = _settings.Planner;
|
2023-09-19 12:17:50 +00:00
|
|
|
|
2023-10-28 20:59:26 +00:00
|
|
|
// Get instruction from Planner
|
2023-10-30 16:48:18 +00:00
|
|
|
var inst = await planner.GetNextInstruction(_router, message.MessageId);
|
2023-09-19 12:17:50 +00:00
|
|
|
|
2023-10-28 20:59:26 +00:00
|
|
|
// Save states
|
2023-11-01 01:48:12 +00:00
|
|
|
states.SaveStateByArgs(inst.Arguments);
|
2023-10-27 20:36:26 +00:00
|
|
|
|
2023-10-28 20:59:26 +00:00
|
|
|
#if DEBUG
|
|
|
|
|
Console.WriteLine($"*** Next Instruction *** {inst}", Color.GreenYellow);
|
|
|
|
|
#else
|
|
|
|
|
_logger.LogInformation($"*** Next Instruction *** {inst}");
|
|
|
|
|
#endif
|
2023-10-29 01:54:10 +00:00
|
|
|
await planner.AgentExecuting(inst, message);
|
2023-09-19 12:17:50 +00:00
|
|
|
|
2023-10-28 20:59:26 +00:00
|
|
|
// Handle instruction by Executor
|
2023-10-30 16:48:18 +00:00
|
|
|
response = await executor.Execute(this, inst, message, dialogs);
|
2023-10-28 20:59:26 +00:00
|
|
|
|
2023-10-30 16:48:18 +00:00
|
|
|
await planner.AgentExecuted(inst, response);
|
2023-09-19 12:17:50 +00:00
|
|
|
}
|
|
|
|
|
|
2023-10-30 16:48:18 +00:00
|
|
|
return response;
|
2023-09-19 12:17:50 +00:00
|
|
|
}
|
|
|
|
|
|
2023-11-01 01:48:12 +00:00
|
|
|
public List<RoutingHandlerDef> GetHandlers()
|
2023-09-20 10:31:50 +00:00
|
|
|
{
|
2023-11-01 01:48:12 +00:00
|
|
|
var planer = _services.GetRequiredService<IPlaner>();
|
|
|
|
|
|
|
|
|
|
return _services.GetServices<IRoutingHandler>()
|
|
|
|
|
.Where(x => x.Planers == null || x.Planers.Contains(planer.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
|
|
|
|
|
[MemoryCache(10 * 60)]
|
|
|
|
|
#endif
|
|
|
|
|
protected RoutingRule[] GetRoutingRecords()
|
|
|
|
|
{
|
|
|
|
|
var db = _services.GetRequiredService<IBotSharpRepository>();
|
|
|
|
|
|
|
|
|
|
var agents = db.GetAgents(disabled: false, allowRouting: true);
|
|
|
|
|
var records = agents.SelectMany(x =>
|
|
|
|
|
{
|
|
|
|
|
x.RoutingRules.ForEach(r =>
|
|
|
|
|
{
|
|
|
|
|
r.AgentId = x.Id;
|
|
|
|
|
r.AgentName = x.Name;
|
|
|
|
|
});
|
|
|
|
|
return x.RoutingRules;
|
|
|
|
|
}).ToArray();
|
|
|
|
|
|
|
|
|
|
// Filter agents by profile
|
|
|
|
|
var state = _services.GetRequiredService<IConversationStateService>();
|
|
|
|
|
var name = state.GetState("channel");
|
|
|
|
|
var specifiedProfile = agents.FirstOrDefault(x => x.Profiles.Contains(name));
|
|
|
|
|
if (specifiedProfile != null)
|
2023-09-24 16:20:02 +00:00
|
|
|
{
|
2023-11-01 01:48:12 +00:00
|
|
|
records = records.Where(x => specifiedProfile.Profiles.Contains(name)).ToArray();
|
2023-09-27 12:51:15 +00:00
|
|
|
}
|
2023-09-24 16:20:02 +00:00
|
|
|
|
2023-11-01 01:48:12 +00:00
|
|
|
return records;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if !DEBUG
|
|
|
|
|
[MemoryCache(10 * 60)]
|
|
|
|
|
#endif
|
|
|
|
|
public RoutingItem[] GetRoutingItems()
|
|
|
|
|
{
|
|
|
|
|
var db = _services.GetRequiredService<IBotSharpRepository>();
|
|
|
|
|
|
|
|
|
|
var agents = db.GetAgents(disabled: false, allowRouting: true);
|
|
|
|
|
return agents.Select(x => new RoutingItem
|
2023-09-20 10:31:50 +00:00
|
|
|
{
|
2023-11-01 01:48:12 +00:00
|
|
|
AgentId = x.Id,
|
|
|
|
|
Description = x.Description,
|
|
|
|
|
Name = x.Name,
|
|
|
|
|
RequiredFields = x.RoutingRules
|
|
|
|
|
.Where(p => p.Required)
|
|
|
|
|
.Select(p => new ParameterPropertyDef(p.Field, p.Description, type: p.Type)
|
2023-09-26 03:04:04 +00:00
|
|
|
{
|
2023-11-01 01:48:12 +00:00
|
|
|
Required = p.Required
|
|
|
|
|
}).ToList(),
|
|
|
|
|
OptionalFields = x.RoutingRules
|
|
|
|
|
.Where(p => !p.Required)
|
|
|
|
|
.Select(p => new ParameterPropertyDef(p.Field, p.Description, type: p.Type)
|
|
|
|
|
{
|
|
|
|
|
Required = p.Required
|
|
|
|
|
}).ToList()
|
|
|
|
|
}).ToArray();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public RoutingRule[] GetRulesByName(string name)
|
|
|
|
|
{
|
|
|
|
|
return GetRoutingRecords()
|
|
|
|
|
.Where(x => x.AgentName.ToLower() == name.ToLower())
|
|
|
|
|
.ToArray();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public RoutingRule[] GetRulesByAgentId(string id)
|
|
|
|
|
{
|
|
|
|
|
return GetRoutingRecords()
|
|
|
|
|
.Where(x => x.AgentId == id)
|
|
|
|
|
.ToArray();
|
2023-09-22 20:38:58 +00:00
|
|
|
}
|
2023-09-19 12:17:50 +00:00
|
|
|
}
|