commit
0aa52c15d4
|
|
@ -1,3 +1,5 @@
|
|||
using System.Text.Json;
|
||||
|
||||
namespace BotSharp.Abstraction.Conversations;
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -11,6 +13,7 @@ public interface IConversationStateService
|
|||
bool ContainsState(string name);
|
||||
ConversationState GetStates();
|
||||
IConversationStateService SetState<T>(string name, T value);
|
||||
void SaveStateByArgs(JsonDocument args);
|
||||
void CleanState();
|
||||
void Save();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +0,0 @@
|
|||
using BotSharp.Abstraction.Routing.Models;
|
||||
|
||||
namespace BotSharp.Abstraction.Routing;
|
||||
|
||||
public interface IRouterInstance
|
||||
{
|
||||
string AgentId { get; }
|
||||
Agent Router { get; }
|
||||
RoutingItem[] GetRoutingItems();
|
||||
List<RoutingHandlerDef> GetHandlers();
|
||||
IRouterInstance Load();
|
||||
RoutingRule[] GetRulesByName(string name);
|
||||
}
|
||||
|
|
@ -1,8 +1,14 @@
|
|||
using BotSharp.Abstraction.Routing.Models;
|
||||
|
||||
namespace BotSharp.Abstraction.Routing;
|
||||
|
||||
public interface IRoutingService
|
||||
{
|
||||
Agent Router { get; }
|
||||
RoutingItem[] GetRoutingItems();
|
||||
RoutingRule[] GetRulesByName(string name);
|
||||
RoutingRule[] GetRulesByAgentId(string id);
|
||||
List<RoutingHandlerDef> GetHandlers();
|
||||
void ResetRecursiveCounter();
|
||||
Task<bool> InvokeAgent(string agentId, List<RoleDialogModel> dialogs);
|
||||
Task<RoleDialogModel> InstructLoop(RoleDialogModel message);
|
||||
|
|
|
|||
|
|
@ -81,7 +81,6 @@ public static class BotSharpServiceCollectionExtensions
|
|||
});
|
||||
|
||||
services.AddScoped<IExecutor, InstructExecutor>();
|
||||
services.AddScoped<IRouterInstance, RouterInstance>();
|
||||
services.AddScoped<IRoutingService, RoutingService>();
|
||||
|
||||
if (myDatabaseSettings.Default == "FileRepository")
|
||||
|
|
|
|||
|
|
@ -128,4 +128,23 @@ public class ConversationStateService : IConversationStateService, IDisposable
|
|||
{
|
||||
return _states.ContainsKey(name) && !string.IsNullOrEmpty(_states[name]);
|
||||
}
|
||||
|
||||
public void SaveStateByArgs(JsonDocument args)
|
||||
{
|
||||
if (args == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.RootElement is JsonElement root)
|
||||
{
|
||||
foreach (JsonProperty property in root.EnumerateObject())
|
||||
{
|
||||
if (!string.IsNullOrEmpty(property.Value.ToString()))
|
||||
{
|
||||
SetState(property.Name, property.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ using BotSharp.Abstraction.Functions.Models;
|
|||
using BotSharp.Abstraction.Planning;
|
||||
using BotSharp.Abstraction.Repositories;
|
||||
using BotSharp.Abstraction.Routing.Models;
|
||||
using BotSharp.Abstraction.Routing.Settings;
|
||||
using BotSharp.Abstraction.Templating;
|
||||
|
||||
namespace BotSharp.Core.Planning;
|
||||
|
|
@ -36,13 +35,14 @@ public class HFPlanner : IPlaner
|
|||
{
|
||||
try
|
||||
{
|
||||
response = completion.GetChatCompletions(router, new List<RoleDialogModel>
|
||||
var dialogs = new List<RoleDialogModel>
|
||||
{
|
||||
new RoleDialogModel(AgentRole.User, next)
|
||||
{
|
||||
MessageId = messageId
|
||||
}
|
||||
});
|
||||
};
|
||||
response = completion.GetChatCompletions(router, dialogs);
|
||||
|
||||
inst = response.Content.JsonContent<FunctionCallFromLlm>();
|
||||
break;
|
||||
|
|
@ -80,18 +80,15 @@ public class HFPlanner : IPlaner
|
|||
public async Task<bool> AgentExecuted(FunctionCallFromLlm inst, RoleDialogModel message)
|
||||
{
|
||||
var context = _services.GetRequiredService<RoutingContext>();
|
||||
context.Pop();
|
||||
|
||||
context.Empty();
|
||||
return true;
|
||||
}
|
||||
|
||||
private string GetNextStepPrompt(Agent router)
|
||||
{
|
||||
var template = router.Templates.First(x => x.Name == "next_step_prompt").Content;
|
||||
|
||||
var render = _services.GetRequiredService<ITemplateRender>();
|
||||
return render.Render(template, new Dictionary<string, object>
|
||||
{
|
||||
});
|
||||
var prompt = render.Render(template, router.TemplateDict);
|
||||
return prompt.Trim();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ using BotSharp.Abstraction.Functions.Models;
|
|||
using BotSharp.Abstraction.Planning;
|
||||
using BotSharp.Abstraction.Routing.Models;
|
||||
using BotSharp.Abstraction.Templating;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal;
|
||||
|
||||
namespace BotSharp.Core.Planning;
|
||||
|
||||
|
|
@ -24,14 +23,15 @@ public class NaivePlanner : IPlaner
|
|||
|
||||
var inst = new FunctionCallFromLlm();
|
||||
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
// text completion
|
||||
/*var agentService = _services.GetRequiredService<IAgentService>();
|
||||
var instruction = agentService.RenderedInstruction(router);
|
||||
var content = $"{instruction}\r\n###\r\n{next}";
|
||||
|
||||
// text completion
|
||||
content = content + "\r\nResponse: ";
|
||||
var completion = CompletionProvider.GetTextCompletion(_services);*/
|
||||
|
||||
var completion = CompletionProvider.GetTextCompletion(_services);
|
||||
// chat completion
|
||||
var completion = CompletionProvider.GetChatCompletion(_services);
|
||||
|
||||
int retryCount = 0;
|
||||
while (retryCount < 3)
|
||||
|
|
@ -39,11 +39,17 @@ public class NaivePlanner : IPlaner
|
|||
string text = string.Empty;
|
||||
try
|
||||
{
|
||||
text = await completion.GetCompletion(content, router.Id, messageId);
|
||||
var response = new RoleDialogModel(AgentRole.Assistant, text)
|
||||
// text completion
|
||||
// text = await completion.GetCompletion(content, router.Id, messageId);
|
||||
var dialogs = new List<RoleDialogModel>
|
||||
{
|
||||
MessageId = messageId
|
||||
new RoleDialogModel(AgentRole.User, next)
|
||||
{
|
||||
MessageId = messageId
|
||||
}
|
||||
};
|
||||
var response = completion.GetChatCompletions(router, dialogs);
|
||||
|
||||
inst = response.Content.JsonContent<FunctionCallFromLlm>();
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,9 +81,9 @@ public class RouteToAgentFn : IFunctionCallback
|
|||
private bool HasMissingRequiredField(RoleDialogModel message, out string agentId)
|
||||
{
|
||||
var args = JsonSerializer.Deserialize<RoutingArgs>(message.FunctionArgs);
|
||||
var router = _services.GetRequiredService<IRouterInstance>();
|
||||
var routing = _services.GetRequiredService<IRoutingService>();
|
||||
|
||||
var routingRules = router.GetRulesByName(args.AgentName);
|
||||
var routingRules = routing.GetRulesByName(args.AgentName);
|
||||
|
||||
if (routingRules == null || !routingRules.Any())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@ public class RoutingAgentHook : AgentHookBase
|
|||
{
|
||||
dict["router"] = _agent;
|
||||
|
||||
var router = _services.GetRequiredService<IRouterInstance>();
|
||||
dict["routing_agents"] = router.GetRoutingItems();
|
||||
dict["routing_handlers"] = router.GetHandlers();
|
||||
var routing = _services.GetRequiredService<IRoutingService>();
|
||||
dict["routing_agents"] = routing.GetRoutingItems();
|
||||
dict["routing_handlers"] = routing.GetHandlers();
|
||||
|
||||
return base.OnInstructionLoaded(template, dict);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,123 +0,0 @@
|
|||
using BotSharp.Abstraction.Agents.Models;
|
||||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Abstraction.Planning;
|
||||
using BotSharp.Abstraction.Repositories;
|
||||
using BotSharp.Abstraction.Routing;
|
||||
using BotSharp.Abstraction.Routing.Models;
|
||||
using BotSharp.Abstraction.Routing.Settings;
|
||||
|
||||
namespace BotSharp.Core.Routing;
|
||||
|
||||
public class RouterInstance : IRouterInstance
|
||||
{
|
||||
protected readonly IServiceProvider _services;
|
||||
protected readonly ILogger _logger;
|
||||
protected readonly RoutingSettings _settings;
|
||||
|
||||
private Agent _router;
|
||||
public Agent Router => _router;
|
||||
public virtual string AgentId => _router.Id;
|
||||
|
||||
public RouterInstance(IServiceProvider services,
|
||||
ILogger<RouterInstance> logger,
|
||||
RoutingSettings settings)
|
||||
{
|
||||
_services = services;
|
||||
_logger = logger;
|
||||
_settings = settings;
|
||||
}
|
||||
|
||||
public IRouterInstance Load()
|
||||
{
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
_router = agentService.LoadAgent(_settings.RouterId).Result;
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<RoutingHandlerDef> GetHandlers()
|
||||
{
|
||||
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)
|
||||
{
|
||||
records = records.Where(x => specifiedProfile.Profiles.Contains(name)).ToArray();
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
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)
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
@ -41,7 +41,8 @@ public partial class RoutingService
|
|||
{
|
||||
// execute function
|
||||
// Save states
|
||||
SaveStateByArgs(JsonSerializer.Deserialize<JsonDocument>(message.FunctionArgs));
|
||||
var states = _services.GetRequiredService<IConversationStateService>();
|
||||
states.SaveStateByArgs(message.FunctionArgs?.JsonContent<JsonDocument>());
|
||||
|
||||
var conversationService = _services.GetRequiredService<IConversationService>();
|
||||
// Call functions
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using BotSharp.Abstraction.Agents.Models;
|
||||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Abstraction.Planning;
|
||||
using BotSharp.Abstraction.Repositories;
|
||||
using BotSharp.Abstraction.Routing;
|
||||
using BotSharp.Abstraction.Routing.Models;
|
||||
using BotSharp.Abstraction.Routing.Settings;
|
||||
|
|
@ -12,7 +13,6 @@ public partial class RoutingService : IRoutingService
|
|||
{
|
||||
private readonly IServiceProvider _services;
|
||||
private readonly RoutingSettings _settings;
|
||||
private readonly IRouterInstance _routerInstance;
|
||||
private readonly ILogger _logger;
|
||||
private Agent _router;
|
||||
public Agent Router => _router;
|
||||
|
|
@ -24,13 +24,11 @@ public partial class RoutingService : IRoutingService
|
|||
|
||||
public RoutingService(IServiceProvider services,
|
||||
RoutingSettings settings,
|
||||
ILogger<RoutingService> logger,
|
||||
IRouterInstance routerInstance)
|
||||
ILogger<RoutingService> logger)
|
||||
{
|
||||
_services = services;
|
||||
_settings = settings;
|
||||
_logger = logger;
|
||||
_routerInstance = routerInstance;
|
||||
}
|
||||
|
||||
public async Task<RoleDialogModel> ExecuteOnce(Agent agent, RoleDialogModel message)
|
||||
|
|
@ -60,11 +58,12 @@ public partial class RoutingService : IRoutingService
|
|||
|
||||
public async Task<RoleDialogModel> InstructLoop(RoleDialogModel message)
|
||||
{
|
||||
_router = _routerInstance.Load()
|
||||
.Router;
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
_router = await agentService.LoadAgent(_settings.RouterId);
|
||||
|
||||
RoleDialogModel response = default;
|
||||
|
||||
var states = _services.GetRequiredService<IConversationStateService>();
|
||||
var conv = _services.GetRequiredService<IConversationService>();
|
||||
var dialogs = conv.GetDialogHistory();
|
||||
|
||||
|
|
@ -81,12 +80,13 @@ public partial class RoutingService : IRoutingService
|
|||
|
||||
var conversation = await GetConversationContent(dialogs);
|
||||
_router.TemplateDict["conversation"] = conversation;
|
||||
_router.TemplateDict["planner"] = _settings.Planner;
|
||||
|
||||
// Get instruction from Planner
|
||||
var inst = await planner.GetNextInstruction(_router, message.MessageId);
|
||||
|
||||
// Save states
|
||||
SaveStateByArgs(inst.Arguments);
|
||||
states.SaveStateByArgs(inst.Arguments);
|
||||
|
||||
#if DEBUG
|
||||
Console.WriteLine($"*** Next Instruction *** {inst}", Color.GreenYellow);
|
||||
|
|
@ -104,23 +104,90 @@ public partial class RoutingService : IRoutingService
|
|||
return response;
|
||||
}
|
||||
|
||||
protected void SaveStateByArgs(JsonDocument args)
|
||||
public List<RoutingHandlerDef> GetHandlers()
|
||||
{
|
||||
if (args == null)
|
||||
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 =>
|
||||
{
|
||||
return;
|
||||
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)
|
||||
{
|
||||
records = records.Where(x => specifiedProfile.Profiles.Contains(name)).ToArray();
|
||||
}
|
||||
|
||||
var stateService = _services.GetRequiredService<IConversationStateService>();
|
||||
if (args.RootElement is JsonElement root)
|
||||
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
|
||||
{
|
||||
foreach (JsonProperty property in root.EnumerateObject())
|
||||
{
|
||||
if (!string.IsNullOrEmpty(property.Value.ToString()))
|
||||
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)
|
||||
{
|
||||
stateService.SetState(property.Name, property.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -282,7 +282,7 @@ public class ChatCompletionProvider : IChatCompletion
|
|||
{
|
||||
return $"{x.Role}: {x.Content}";
|
||||
}));
|
||||
prompt += $"\r\n[INSTRUCTION]\r\n{verbose}\r\n";
|
||||
prompt += $"{verbose}\r\n";
|
||||
|
||||
verbose = string.Join("\r\n", chatCompletionsOptions.Messages
|
||||
.Where(x => x.Role != AgentRole.System).Select(x =>
|
||||
|
|
@ -291,7 +291,7 @@ public class ChatCompletionProvider : IChatCompletion
|
|||
$"{x.Role}: {x.Name} => {x.Content}" :
|
||||
$"{x.Role}: {x.Content}";
|
||||
}));
|
||||
prompt += $"\r\n[CONVERSATION]\r\n{verbose}\r\n";
|
||||
prompt += $"\r\n{verbose}\r\n";
|
||||
}
|
||||
|
||||
if (chatCompletionsOptions.Functions.Count > 0)
|
||||
|
|
|
|||
Loading…
Reference in a new issue