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

279 lines
7 KiB
C#
Raw Normal View History

using BotSharp.Abstraction.Routing.Settings;
2024-02-28 16:21:14 +00:00
namespace BotSharp.Core.Routing;
2024-02-28 16:21:14 +00:00
public class RoutingContext : IRoutingContext
{
2024-01-26 04:32:48 +00:00
private readonly IServiceProvider _services;
private readonly RoutingSettings _setting;
2024-01-26 04:32:48 +00:00
private string[] _routerAgentIds;
2024-02-28 20:40:59 +00:00
private string _conversationId;
private string _messageId;
2024-10-29 19:59:46 +00:00
private int _currentRecursionDepth = 0;
2025-02-03 21:12:36 +00:00
private List<RoleDialogModel> _dialogs = [];
2024-01-26 04:32:48 +00:00
public RoutingContext(IServiceProvider services, RoutingSettings setting)
{
2024-01-26 04:32:48 +00:00
_services = services;
_setting = setting;
}
2024-02-28 20:40:59 +00:00
public int AgentCount => _stack.Count;
public string ConversationId => _conversationId;
public string MessageId => _messageId;
2024-10-29 19:59:46 +00:00
public int CurrentRecursionDepth => _currentRecursionDepth;
2024-02-28 20:40:59 +00:00
2024-10-29 19:59:46 +00:00
private Stack<string> _stack { get; set; } = new();
/// <summary>
/// Intent name
/// </summary>
public string IntentName { get; set; }
2023-10-27 01:23:06 +00:00
/// <summary>
2024-01-13 21:17:40 +00:00
/// Agent that can handle user original goal.
2023-10-27 01:23:06 +00:00
/// </summary>
public string OriginAgentId
2024-01-26 04:32:48 +00:00
{
get
{
if (_routerAgentIds == null)
{
var agentService = _services.GetRequiredService<IAgentService>();
_routerAgentIds = agentService.GetAgents(new AgentFilter
{
2025-01-30 17:14:52 +00:00
Types = [AgentType.Routing],
2024-11-21 07:01:36 +00:00
Pager = new Pagination { Size = 100 }
2024-10-18 15:58:22 +00:00
}).Result.Items.Select(x => x.Id).ToArray();
2024-01-26 04:32:48 +00:00
}
2024-10-18 15:58:22 +00:00
return _stack.Where(x => !_routerAgentIds.Contains(x)).LastOrDefault() ?? string.Empty;
2024-01-26 04:32:48 +00:00
}
}
2024-11-20 23:10:38 +00:00
/// <summary>
/// Entry agent
/// </summary>
public string EntryAgentId
{
get
{
return _stack.LastOrDefault() ?? string.Empty;
}
}
2023-10-29 01:54:10 +00:00
public bool IsEmpty => !_stack.Any();
2024-02-28 20:40:59 +00:00
public string GetCurrentAgentId()
{
2024-02-29 02:45:01 +00:00
if (_stack.Count == 0)
{
return string.Empty;
}
return _stack.Peek();
}
/// <summary>
/// Push agent
/// </summary>
/// <param name="agentId">Id or Name</param>
/// <param name="reason"></param>
2024-02-28 20:40:59 +00:00
public void Push(string agentId, string? reason = null)
{
// Convert id to name
if (!Guid.TryParse(agentId, out _))
{
var agentService = _services.GetRequiredService<IAgentService>();
agentId = agentService.GetAgents(new AgentFilter
{
2025-01-30 17:14:52 +00:00
AgentNames = [agentId]
}).Result.Items.First().Id;
}
if (_stack.Count == 0 || _stack.Peek() != agentId)
{
2024-02-28 16:21:14 +00:00
var preAgentId = _stack.Count == 0 ? agentId : _stack.Peek();
_stack.Push(agentId);
2024-02-28 16:21:14 +00:00
HookEmitter.Emit<IRoutingHook>(_services, async hook =>
2024-02-28 20:40:59 +00:00
await hook.OnAgentEnqueued(agentId, preAgentId, reason: reason)
2024-02-28 16:21:14 +00:00
).Wait();
}
}
/// <summary>
/// Pop current agent
/// </summary>
2024-02-28 20:40:59 +00:00
public void Pop(string? reason = null)
{
2024-02-28 16:21:14 +00:00
if (_stack.Count == 0)
{
return;
}
var agentId = _stack.Pop();
2024-02-29 02:41:21 +00:00
var currentAgentId = GetCurrentAgentId();
2024-02-28 16:21:14 +00:00
HookEmitter.Emit<IRoutingHook>(_services, async hook =>
2024-02-29 02:41:21 +00:00
await hook.OnAgentDequeued(agentId, currentAgentId, reason: reason)
2024-02-28 16:21:14 +00:00
).Wait();
2024-03-21 22:04:45 +00:00
if (string.IsNullOrEmpty(currentAgentId))
{
return;
}
2024-03-21 22:04:45 +00:00
// Run the routing rule
var agency = _services.GetRequiredService<IAgentService>();
var agent = agency.LoadAgent(currentAgentId).Result;
var message = new RoleDialogModel(AgentRole.User, $"Try to route to agent {agent.Name}")
{
2024-05-28 02:06:05 +00:00
CurrentAgentId = currentAgentId,
2024-03-21 22:04:45 +00:00
FunctionName = "route_to_agent",
FunctionArgs = JsonSerializer.Serialize(new FunctionCallFromLlm
{
Function = "route_to_agent",
AgentName = agent.Name,
2024-03-22 19:06:20 +00:00
NextActionReason = $"User manually route to agent {agent.Name}"
2024-03-21 22:04:45 +00:00
})
};
var routing = _services.GetRequiredService<IRoutingService>();
var (missingfield, _) = routing.HasMissingRequiredField(message, out agentId);
2024-03-21 22:04:45 +00:00
if (missingfield)
{
if (currentAgentId != agentId)
{
_stack.Push(agentId);
}
}
2023-10-29 01:54:10 +00:00
}
2024-04-22 20:46:47 +00:00
public void PopTo(string agentId, string reason)
{
var currentAgentId = GetCurrentAgentId();
while (!string.IsNullOrEmpty(currentAgentId) &&
currentAgentId != agentId)
{
Pop(reason);
currentAgentId = GetCurrentAgentId();
}
}
public string FirstGoalAgentId()
2024-02-28 20:40:59 +00:00
{
if (_stack.Count == 1)
{
return GetCurrentAgentId();
}
else if (_stack.Count > 1)
{
2024-03-21 22:04:45 +00:00
return _stack.ToArray()[_stack.Count - 2];
2024-02-28 20:40:59 +00:00
}
return string.Empty;
}
2024-04-22 20:46:47 +00:00
public bool ContainsAgentId(string agentId)
{
return _stack.ToArray().Contains(agentId);
}
2024-02-28 20:40:59 +00:00
public void Replace(string agentId, string? reason = null)
{
2024-02-28 16:21:14 +00:00
var fromAgent = agentId;
var toAgent = agentId;
if (_stack.Count == 0)
{
_stack.Push(agentId);
}
else if (_stack.Peek() != agentId)
{
2024-02-28 16:21:14 +00:00
fromAgent = _stack.Peek();
_stack.Pop();
_stack.Push(agentId);
2024-02-28 16:21:14 +00:00
HookEmitter.Emit<IRoutingHook>(_services, async hook =>
2024-02-28 20:40:59 +00:00
await hook.OnAgentReplaced(fromAgent, toAgent, reason: reason)
2024-02-28 16:21:14 +00:00
).Wait();
}
}
2024-02-28 20:40:59 +00:00
public void Empty(string? reason = null)
2023-10-29 01:54:10 +00:00
{
2024-02-28 16:21:14 +00:00
if (_stack.Count == 0)
{
return;
}
var agentId = GetCurrentAgentId();
2023-10-29 01:54:10 +00:00
_stack.Clear();
2024-02-28 16:21:14 +00:00
HookEmitter.Emit<IRoutingHook>(_services, async hook =>
2024-02-28 20:40:59 +00:00
await hook.OnAgentQueueEmptied(agentId, reason: reason)
2024-02-28 16:21:14 +00:00
).Wait();
}
2024-02-28 20:40:59 +00:00
public void SetMessageId(string conversationId, string messageId)
{
_conversationId = conversationId;
_messageId = messageId;
}
2024-10-29 19:59:46 +00:00
public int GetRecursiveCounter()
{
return _currentRecursionDepth;
}
2024-10-31 20:32:58 +00:00
public void IncreaseRecursiveCounter()
2024-10-29 19:59:46 +00:00
{
2024-10-31 20:32:58 +00:00
_currentRecursionDepth++;
2024-10-29 19:59:46 +00:00
}
public void SetRecursiveCounter(int counter)
{
_currentRecursionDepth = counter;
}
public void ResetRecursiveCounter()
{
_currentRecursionDepth = 0;
}
public Stack<string> GetAgentStack()
{
2024-11-22 01:37:56 +00:00
var copy = _stack.ToList();
copy.Reverse();
return new Stack<string>(copy);
2024-10-29 19:59:46 +00:00
}
public void SetAgentStack(Stack<string> stack)
{
2024-11-22 01:37:56 +00:00
var copy = stack.ToList();
copy.Reverse();
_stack = new Stack<string>(copy);
2024-10-29 19:59:46 +00:00
}
public void ResetAgentStack()
{
_stack.Clear();
}
2025-02-03 21:12:36 +00:00
public void SetDialogs(List<RoleDialogModel> dialogs)
{
_dialogs = dialogs ?? [];
}
public List<RoleDialogModel> GetDialogs()
{
return _dialogs ?? [];
}
public void ResetDialogs()
{
_dialogs = [];
}
}