BotSharp/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs

259 lines
8.3 KiB
C#
Raw Normal View History

2024-04-23 19:02:00 +00:00
using BotSharp.Abstraction.Infrastructures.Enums;
2023-10-29 01:54:10 +00:00
using BotSharp.Abstraction.Routing.Models;
using BotSharp.Abstraction.Routing.Planning;
2023-09-20 10:31:50 +00:00
using BotSharp.Abstraction.Routing.Settings;
2023-09-19 12:17:50 +00:00
namespace BotSharp.Core.Routing;
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;
2024-02-28 20:40:59 +00:00
private readonly IRoutingContext _context;
2023-09-19 12:17:50 +00:00
private readonly ILogger _logger;
2023-10-30 16:48:18 +00:00
private Agent _router;
2024-02-28 20:40:59 +00:00
public IRoutingContext Context => _context;
2023-10-30 16:48:18 +00:00
public Agent Router => _router;
2023-09-19 12:17:50 +00:00
public void ResetRecursiveCounter()
{
_currentRecursionDepth = 0;
}
2023-09-20 10:31:50 +00:00
public RoutingService(IServiceProvider services,
RoutingSettings settings,
2024-02-28 20:40:59 +00:00
IRoutingContext context,
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;
2024-02-28 20:40:59 +00:00
_context = context;
2023-09-19 12:17:50 +00:00
_logger = logger;
}
public async Task<RoleDialogModel> InstructDirect(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-11-16 18:20:43 +00:00
var conv = _services.GetRequiredService<IConversationService>();
2024-04-23 19:02:00 +00:00
var storage = _services.GetRequiredService<IConversationStorage>();
storage.Append(conv.ConversationId, message);
var dialogs = conv.GetDialogHistory();
2023-10-30 16:48:18 +00:00
handler.SetDialogs(dialogs);
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",
Question = message.Content,
2024-03-22 19:06:20 +00:00
NextActionReason = message.Content,
2023-11-08 22:27:42 +00:00
AgentName = agent.Name,
OriginalAgent = agent.Name,
ExecutingDirectly = true
2023-10-30 16:48:18 +00:00
};
2023-09-23 21:33:05 +00:00
var result = await handler.Handle(this, inst, message);
2023-10-30 16:48:18 +00:00
var response = dialogs.Last();
response.MessageId = message.MessageId;
response.Instruction = inst;
return response;
2023-09-23 21:33:05 +00:00
}
public async Task<RoleDialogModel> InstructLoop(RoleDialogModel message, List<RoleDialogModel> dialogs)
2023-09-19 12:17:50 +00:00
{
2024-04-23 19:02:00 +00:00
RoleDialogModel response = default;
2023-11-01 01:48:12 +00:00
var agentService = _services.GetRequiredService<IAgentService>();
2024-04-23 19:02:00 +00:00
var convService = _services.GetRequiredService<IConversationService>();
var storage = _services.GetRequiredService<IConversationStorage>();
2023-10-30 16:48:18 +00:00
2024-04-23 19:02:00 +00:00
_router = await agentService.LoadAgent(message.CurrentAgentId);
2023-10-30 16:48:18 +00:00
2023-11-01 01:48:12 +00:00
var states = _services.GetRequiredService<IConversationStateService>();
2023-10-28 20:59:26 +00:00
var executor = _services.GetRequiredService<IExecutor>();
2023-09-22 20:38:58 +00:00
2024-01-27 01:14:14 +00:00
var planner = GetPlanner(_router);
2024-02-28 20:40:59 +00:00
_context.Push(_router.Id);
2023-10-30 16:48:18 +00:00
2024-04-23 19:02:00 +00:00
// Handle multi-language for input
2024-05-09 20:59:59 +00:00
var agentSettings = _services.GetRequiredService<AgentSettings>();
if (agentSettings.EnableTranslator)
2024-04-23 19:02:00 +00:00
{
2024-05-09 20:59:59 +00:00
var translator = _services.GetRequiredService<ITranslationService>();
2024-05-15 19:32:59 +00:00
var language = states.GetState(StateConst.LANGUAGE, LanguageType.ENGLISH);
2024-05-09 20:59:59 +00:00
if (language != LanguageType.ENGLISH)
{
message.SecondaryContent = message.Content;
message.Content = await translator.Translate(_router, message.MessageId, message.Content,
language: LanguageType.ENGLISH,
clone: false);
}
2024-04-23 19:02:00 +00:00
}
2024-04-25 16:27:51 +00:00
2024-05-09 20:59:59 +00:00
dialogs.Add(message);
2024-04-23 19:02:00 +00:00
storage.Append(convService.ConversationId, message);
2023-09-19 12:17:50 +00:00
2024-05-09 20:59:59 +00:00
// Get first instruction
_router.TemplateDict["conversation"] = await GetConversationContent(dialogs);
var inst = await planner.GetNextInstruction(_router, message.MessageId, dialogs);
2024-04-23 19:02:00 +00:00
int loopCount = 1;
while (true)
{
2024-02-28 16:21:14 +00:00
await HookEmitter.Emit<IRoutingHook>(_services, async hook =>
2024-02-28 20:40:59 +00:00
await hook.OnRoutingInstructionReceived(inst, message)
2024-02-28 16:21:14 +00:00
);
2024-02-23 01:53:00 +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-28 20:59:26 +00:00
#if DEBUG
2024-06-26 21:15:29 +00:00
Console.WriteLine($"*** Next Instruction *** {inst}");
2023-10-28 20:59:26 +00:00
#else
_logger.LogInformation($"*** Next Instruction *** {inst}");
#endif
2024-02-19 22:55:41 +00:00
await planner.AgentExecuting(_router, inst, message, dialogs);
2023-09-19 12:17:50 +00:00
2024-02-02 04:16:57 +00:00
// Handover to Task Agent
2024-02-19 22:55:41 +00:00
if (inst.HandleDialogsByPlanner)
2024-02-01 18:32:16 +00:00
{
2024-02-19 22:55:41 +00:00
var dialogWithoutContext = planner.BeforeHandleContext(inst, message, dialogs);
response = await executor.Execute(this, inst, message, dialogWithoutContext);
2024-02-19 22:55:41 +00:00
planner.AfterHandleContext(dialogs, dialogWithoutContext);
2024-02-01 18:32:16 +00:00
}
else
{
response = await executor.Execute(this, inst, message, dialogs);
2024-02-01 18:32:16 +00:00
}
2023-10-28 20:59:26 +00:00
2024-02-19 22:55:41 +00:00
await planner.AgentExecuted(_router, inst, response, dialogs);
2024-04-23 19:02:00 +00:00
if (loopCount >= planner.MaxLoopCount || _context.IsEmpty)
{
break;
}
// Get next instruction from Planner
_router.TemplateDict["conversation"] = await GetConversationContent(dialogs);
inst = await planner.GetNextInstruction(_router, message.MessageId, dialogs);
loopCount++;
}
2023-10-30 16:48:18 +00:00
return response;
2023-09-19 12:17:50 +00:00
}
2024-01-27 01:14:14 +00:00
public List<RoutingHandlerDef> GetHandlers(Agent router)
2023-09-20 10:31:50 +00:00
{
2024-01-27 01:14:14 +00:00
var planer = GetPlanner(router);
2023-11-01 01:48:12 +00:00
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>();
2023-11-27 22:20:49 +00:00
var filter = new AgentFilter
{
Disabled = false,
2024-01-26 04:32:48 +00:00
Type = AgentType.Task
2023-11-27 22:20:49 +00:00
};
var agents = db.GetAgents(filter);
2023-11-01 01:48:12 +00:00
var records = agents.SelectMany(x =>
{
x.RoutingRules.ForEach(r =>
{
r.AgentId = x.Id;
r.AgentName = x.Name;
});
return x.RoutingRules;
}).ToArray();
return records;
}
#if !DEBUG
[MemoryCache(10 * 60)]
#endif
public RoutableAgent[] GetRoutableAgents(List<string> profiles)
2023-11-01 01:48:12 +00:00
{
var db = _services.GetRequiredService<IBotSharpRepository>();
2023-11-27 22:20:49 +00:00
var filter = new AgentFilter
{
Disabled = false,
2024-01-26 04:32:48 +00:00
Type = AgentType.Task
2023-11-27 22:20:49 +00:00
};
2023-11-27 22:20:49 +00:00
var agents = db.GetAgents(filter);
var routableAgents = agents.Select(x => new RoutableAgent
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,
Profiles = x.Profiles,
2023-11-01 01:48:12 +00:00
RequiredFields = x.RoutingRules
.Where(p => p.Required)
.Select(p => new ParameterPropertyDef(p.Field, p.Description, type: p.FieldType)
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.FieldType)
2023-11-01 01:48:12 +00:00
{
Required = p.Required
}).ToList()
}).ToArray();
// Handle profile.
// Router profile must match the agent profile
if (routableAgents.Length > 0 && profiles.Count > 0)
{
routableAgents = routableAgents.Where(x => x.Profiles != null &&
x.Profiles.Exists(x1 => profiles.Exists(y => x1 == y)))
.ToArray();
}
2024-01-26 04:32:48 +00:00
else if (profiles == null || profiles.Count == 0)
{
routableAgents = routableAgents.Where(x => x.Profiles == null ||
x.Profiles.Count == 0)
.ToArray();
}
return routableAgents;
2023-11-01 01:48:12 +00:00
}
public RoutingRule[] GetRulesByAgentName(string name)
2023-11-01 01:48:12 +00:00
{
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
}