Merge branch 'master' into add-PdfToTextConverter
This commit is contained in:
commit
37e0a164fd
|
|
@ -1,9 +0,0 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace BotSharp.Abstraction.Agents.Models;
|
||||
|
||||
public class AgentRoutingArgs
|
||||
{
|
||||
[JsonPropertyName("agent_id")]
|
||||
public string AgentId { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace BotSharp.Abstraction.Agents.Models;
|
||||
|
||||
public class RoutingArgs
|
||||
{
|
||||
[JsonPropertyName("agent_name")]
|
||||
public string AgentName { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return AgentName;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace BotSharp.Abstraction.Agents.Models;
|
||||
|
||||
public class RoutingTable
|
||||
{
|
||||
[JsonPropertyName("agent_id")]
|
||||
public string AgentId { get; set; }
|
||||
|
||||
[JsonPropertyName("name")]
|
||||
public string AgentName { get; set; }
|
||||
|
||||
[JsonPropertyName("required")]
|
||||
public List<string> RequiredFields { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return AgentName;
|
||||
}
|
||||
}
|
||||
|
|
@ -30,11 +30,6 @@ public class RoleDialogModel
|
|||
/// </summary>
|
||||
public object ExecutionData { get; set; }
|
||||
|
||||
public bool IsConversationEnd { get; set; }
|
||||
|
||||
public bool NeedReloadAgent { get; set; }
|
||||
public bool StopPropagate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Channel name
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ public static class BotSharpServiceCollectionExtensions
|
|||
|
||||
services.AddScoped<IAgentRouting, AgentRouter>();
|
||||
|
||||
services.AddScoped<IFunctionCallback, GoToRouterFn>();
|
||||
services.AddScoped<IFunctionCallback, RouteToAgentFn>();
|
||||
|
||||
return services;
|
||||
|
|
|
|||
|
|
@ -21,12 +21,21 @@ public partial class ConversationService
|
|||
currentRecursiveDepth++;
|
||||
if (currentRecursiveDepth > maxRecursiveDepth)
|
||||
{
|
||||
_logger.LogError($"Exceed max current recursive depth.");
|
||||
await HandleAssistantMessage(new RoleDialogModel(AgentRole.Assistant, "System has exception, please try later.")
|
||||
_logger.LogWarning($"Exceeded max recursive depth.");
|
||||
|
||||
var latestResponse = wholeDialogs.Last();
|
||||
var text = latestResponse.Content;
|
||||
if (latestResponse.Role == AgentRole.Function)
|
||||
{
|
||||
text = latestResponse.Content.Split("=>").Last();
|
||||
}
|
||||
|
||||
await HandleAssistantMessage(new RoleDialogModel(AgentRole.Assistant, text)
|
||||
{
|
||||
CurrentAgentId = agent.Id,
|
||||
Channel = wholeDialogs.Last().Channel
|
||||
}, onMessageReceived);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -53,18 +62,19 @@ public partial class ConversationService
|
|||
return;
|
||||
}
|
||||
|
||||
fn.Content = fn.ExecutionResult;
|
||||
fn.Content = fn.FunctionArgs.Replace("\r", " ").Replace("\n", " ").Trim() + " => " + fn.ExecutionResult;
|
||||
|
||||
// Agent has been transferred
|
||||
var agentSettings = _services.GetRequiredService<AgentSettings>();
|
||||
if (fn.CurrentAgentId != preAgentId)
|
||||
{
|
||||
var agentSettings = _services.GetRequiredService<AgentSettings>();
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
agent = await agentService.LoadAgent(fn.CurrentAgentId);
|
||||
}
|
||||
|
||||
// Add to dialog history
|
||||
_storage.Append(conversationId, preAgentId, fn);
|
||||
// The server had an error processing your request. Sorry about that!
|
||||
// _storage.Append(conversationId, preAgentId, fn);
|
||||
|
||||
// After function is executed, pass the result to LLM to get a natural response
|
||||
wholeDialogs.Add(fn);
|
||||
|
|
|
|||
|
|
@ -85,7 +85,10 @@ public partial class ConversationService
|
|||
{
|
||||
foreach (JsonProperty property in root.EnumerateObject())
|
||||
{
|
||||
stateService.SetState(property.Name, property.Value.ToString());
|
||||
if (!string.IsNullOrEmpty(property.Value.ToString()))
|
||||
{
|
||||
stateService.SetState(property.Name, property.Value.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,27 +0,0 @@
|
|||
using BotSharp.Abstraction.Conversations.Models;
|
||||
using BotSharp.Abstraction.Functions;
|
||||
using BotSharp.Abstraction.Functions.Models;
|
||||
|
||||
namespace BotSharp.Core.Functions;
|
||||
|
||||
public class GoToRouterFn : IFunctionCallback
|
||||
{
|
||||
public string Name => "go_to_router";
|
||||
private readonly IServiceProvider _services;
|
||||
|
||||
public GoToRouterFn(IServiceProvider services)
|
||||
{
|
||||
_services = services;
|
||||
}
|
||||
|
||||
public async Task<bool> Execute(RoleDialogModel message)
|
||||
{
|
||||
var settings = _services.GetRequiredService<AgentSettings>();
|
||||
message.CurrentAgentId = settings.RouterId;
|
||||
|
||||
var result = new FunctionExecutionValidationResult("true");
|
||||
message.ExecutionResult = JsonSerializer.Serialize(result);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,13 @@
|
|||
using BotSharp.Abstraction.Agents.Models;
|
||||
using BotSharp.Abstraction.Conversations.Models;
|
||||
using BotSharp.Abstraction.Functions;
|
||||
using BotSharp.Abstraction.Functions.Models;
|
||||
using System.IO;
|
||||
|
||||
namespace BotSharp.Core.Functions;
|
||||
|
||||
/// <summary>
|
||||
/// Router calls this function to set the Active Agent according to the context
|
||||
/// </summary>
|
||||
public class RouteToAgentFn : IFunctionCallback
|
||||
{
|
||||
public string Name => "route_to_agent";
|
||||
|
|
@ -17,20 +20,68 @@ public class RouteToAgentFn : IFunctionCallback
|
|||
|
||||
public async Task<bool> Execute(RoleDialogModel message)
|
||||
{
|
||||
var args = JsonSerializer.Deserialize<AgentRoutingArgs>(message.FunctionArgs);
|
||||
var args = JsonSerializer.Deserialize<RoutingArgs>(message.FunctionArgs);
|
||||
|
||||
if (string.IsNullOrEmpty(args.AgentId))
|
||||
if (string.IsNullOrEmpty(args.AgentName))
|
||||
{
|
||||
var result = new FunctionExecutionValidationResult("false", "agent_id can't be parsed.");
|
||||
message.ExecutionResult = JsonSerializer.Serialize(result);
|
||||
message.ExecutionResult = $"missing agent name";
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = new FunctionExecutionValidationResult("true");
|
||||
message.ExecutionResult = JsonSerializer.Serialize(result);
|
||||
message.CurrentAgentId = args.AgentId;
|
||||
if (!HasMissingRequiredField(message, out var agentId))
|
||||
{
|
||||
message.CurrentAgentId = agentId;
|
||||
message.ExecutionResult = $"Routed to {args.AgentName}";
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the target agent needs some required fields but the
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private bool HasMissingRequiredField(RoleDialogModel message, out string agentId)
|
||||
{
|
||||
var args = JsonSerializer.Deserialize<RoutingArgs>(message.FunctionArgs);
|
||||
|
||||
var routes = GetRoutingTable();
|
||||
var agent = routes.FirstOrDefault(x => x.AgentName.ToLower() == args.AgentName.ToLower());
|
||||
|
||||
if (agent == null)
|
||||
{
|
||||
agentId = message.CurrentAgentId;
|
||||
message.ExecutionResult = $"Can't find agent {args.AgentName}";
|
||||
return true;
|
||||
}
|
||||
|
||||
agentId = agent.AgentId;
|
||||
|
||||
// Check required fields
|
||||
var jo = JsonSerializer.Deserialize<object>(message.FunctionArgs);
|
||||
bool hasMissingField = false;
|
||||
foreach (var field in agent.RequiredFields)
|
||||
{
|
||||
if (jo is JsonElement root)
|
||||
{
|
||||
if (!root.EnumerateObject().Any(x => x.Name == field))
|
||||
{
|
||||
message.ExecutionResult = $"missing {field}.";
|
||||
hasMissingField = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hasMissingField;
|
||||
}
|
||||
|
||||
private RoutingTable[] GetRoutingTable()
|
||||
{
|
||||
var agentSettings = _services.GetRequiredService<AgentSettings>();
|
||||
var dbSettings = _services.GetRequiredService<MyDatabaseSettings>();
|
||||
var filePath = Path.Combine(dbSettings.FileRepository, agentSettings.DataDir, agentSettings.RouterId, "route.json");
|
||||
return JsonSerializer.Deserialize<RoutingTable[]>(File.ReadAllText(filePath));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -124,7 +124,10 @@ public class WebhookController : ControllerBase
|
|||
try
|
||||
{
|
||||
var parsed = JsonSerializer.Deserialize<QuickReplyMessageItem[]>(json, jsonOpt);
|
||||
reply.QuickReplies = parsed;
|
||||
if (parsed.Length > 0)
|
||||
{
|
||||
reply.QuickReplies = parsed;
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -13,5 +13,6 @@ public class QuickReplyMessage : IResponseMessage
|
|||
public string Text { get; set; }
|
||||
|
||||
[JsonPropertyName("quick_replies")]
|
||||
public QuickReplyMessageItem[] QuickReplies { get; set; }
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public QuickReplyMessageItem[]? QuickReplies { get; set; }
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue