Merge pull request #266 from hchen2020/master

Standarderize agent type.
This commit is contained in:
Haiping 2024-01-25 22:38:04 -06:00 committed by GitHub
commit 34b3dc47ba
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
27 changed files with 112 additions and 111 deletions

View file

@ -2,7 +2,7 @@
An agent helps you process user sentences (unstructure data) into structure data that you can use to return an appropriate response.
Agent is a collection that contains prompt words and function Json Schema definitions, few-shot examples and knowledge base data. You can create multiple different Agents to perform specific operations in specific domains. BotSharp has built-in maintenance for Agents, including creating, updating and deleting, importing and exporting. Agents are divided into task agents and routing (non-task) agents. Business domain agents belong to task agents, and routers belong to non-task agents.
Agent is a collection that contains prompt words and function Json Schema definitions, few-shot examples and knowledge base data. You can create multiple different Agents to perform specific operations in specific domains. BotSharp has built-in maintenance for Agents, including creating, updating and deleting, importing and exporting. Agents are divided into `task agents`, `routing (non-task) agents`, `evaluating agents` and `static agents`. Business domain agents belong to task agents, and routers belong to non-task agents, static agents don't have capabilities to interact with external environment.
## My Agent
After creating the platform account, you can start to enter the steps of creating the Agent.

View file

@ -7,7 +7,7 @@ public enum AgentField
Description,
IsPublic,
Disabled,
AllowRouting,
Type,
Profiles,
RoutingRule,
Instruction,

View file

@ -0,0 +1,22 @@
namespace BotSharp.Abstraction.Agents.Enums;
public class AgentType
{
/// <summary>
/// Routing Agent
/// </summary>
public const string Routing = "routing";
public const string Evaluating = "evaluating";
/// <summary>
/// Routable task agent with capability of interaction with external environment
/// </summary>
public const string Task = "task";
/// <summary>
/// Agent that cannot use external tools
/// </summary>
public const string Static = "static";
}

View file

@ -9,6 +9,10 @@ public class Agent
public string Id { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
/// <summary>
/// Agent Type
/// </summary>
public string Type { get; set; } = AgentType.Task;
public DateTime CreatedDateTime { get; set; }
public DateTime UpdatedDateTime { get; set; }
@ -57,9 +61,6 @@ public class Agent
public bool IsPublic { get; set; }
[JsonIgnore]
public bool IsRouter { get; set; }
[JsonIgnore]
public bool IsHost { get; set; }
@ -69,11 +70,6 @@ public class Agent
[JsonIgnore]
public bool Installed => Plugin.Enabled;
/// <summary>
/// Allow to be routed
/// </summary>
public bool AllowRouting { get; set; }
/// <summary>
/// Default is True, user will enable this by installing appropriate plugin.
/// </summary>
@ -107,6 +103,7 @@ public class Agent
Id = agent.Id,
Name = agent.Name,
Description = agent.Description,
Type = agent.Type,
Instruction = agent.Instruction,
Functions = agent.Functions,
Responses = agent.Responses,
@ -114,7 +111,6 @@ public class Agent
Knowledges = agent.Knowledges,
IsPublic = agent.IsPublic,
Disabled = agent.Disabled,
AllowRouting = agent.AllowRouting,
Profiles = agent.Profiles,
RoutingRules = agent.RoutingRules,
LlmConfig = agent.LlmConfig,
@ -183,9 +179,9 @@ public class Agent
return this;
}
public Agent SetAllowRouting(bool allowRouting)
public Agent SetAgentType(string type)
{
AllowRouting = allowRouting;
Type = type;
return this;
}

View file

@ -6,9 +6,7 @@ public class AgentFilter
public string? AgentName { get; set; }
public bool? Disabled { get; set; }
public bool? Installed { get; set; }
public bool? AllowRouting { get; set; }
public string? Type { get; set; }
public bool? IsPublic { get; set; }
public bool? IsRouter { get; set; }
public bool? IsEvaluator { get; set; }
public List<string>? AgentIds { get; set; }
}

View file

@ -5,7 +5,14 @@ namespace BotSharp.Abstraction.Routing;
public interface IRoutingService
{
Agent Router { get; }
/// <summary>
/// Get routable agents
/// </summary>
/// <param name="profiles">router's profile</param>
/// <returns></returns>
RoutableAgent[] GetRoutableAgents(List<string> profiles);
RoutingRule[] GetRulesByName(string name);
RoutingRule[] GetRulesByAgentId(string id);
List<RoutingHandlerDef> GetHandlers();

View file

@ -1,12 +1,19 @@
using BotSharp.Abstraction.Agents;
using BotSharp.Abstraction.Repositories.Filters;
using BotSharp.Abstraction.Routing.Settings;
using Microsoft.Extensions.DependencyInjection;
namespace BotSharp.Abstraction.Routing.Models;
public class RoutingContext
{
private readonly IServiceProvider _services;
private readonly RoutingSettings _setting;
public RoutingContext(RoutingSettings setting)
private string[] _routerAgentIds;
public RoutingContext(IServiceProvider services, RoutingSettings setting)
{
_services = services;
_setting = setting;
}
@ -22,7 +29,22 @@ public class RoutingContext
/// Agent that can handle user original goal.
/// </summary>
public string OriginAgentId
=> _stack.Where(x => !_setting.AgentIds.Contains(x)).Last();
{
get
{
if (_routerAgentIds == null)
{
var agentService = _services.GetRequiredService<IAgentService>();
_routerAgentIds = agentService.GetAgents(new AgentFilter
{
Type = AgentType.Routing
}).Result.Items
.Select(x => x.Id).ToArray();
}
return _stack.Where(x => !_routerAgentIds.Contains(x)).Last();
}
}
public bool IsEmpty => !_stack.Any();
public string GetCurrentAgentId()

View file

@ -2,10 +2,5 @@ namespace BotSharp.Abstraction.Routing.Settings;
public class RoutingSettings
{
/// <summary>
/// Router Agent Id
/// </summary>
public string[] AgentIds { get; set; } = new string[0];
public string Planner { get; set; } = string.Empty;
}

View file

@ -33,7 +33,7 @@ public partial class AgentService
.SetDescription(foundAgent.Description)
.SetIsPublic(foundAgent.IsPublic)
.SetDisabled(foundAgent.Disabled)
.SetAllowRouting(foundAgent.AllowRouting)
.SetAgentType(foundAgent.Type)
.SetProfiles(foundAgent.Profiles)
.SetRoutingRules(foundAgent.RoutingRules)
.SetInstruction(foundAgent.Instruction)

View file

@ -17,7 +17,6 @@ public partial class AgentService
var routeSetting = _services.GetRequiredService<RoutingSettings>();
foreach (var agent in agents)
{
agent.IsRouter = routeSetting.AgentIds.Contains(agent.Id);
agent.Plugin = GetPlugin(agent.Id);
}
@ -58,9 +57,6 @@ public partial class AgentService
profile.LlmConfig.IsInherit = true;
}
// Set IsRouter
var routeSetting = _services.GetRequiredService<RoutingSettings>();
profile.IsRouter = routeSetting.AgentIds.Contains(profile.Id);
profile.Plugin = GetPlugin(profile.Id);
return profile;

View file

@ -19,7 +19,7 @@ public partial class AgentService
record.Description = agent.Description ?? string.Empty;
record.IsPublic = agent.IsPublic;
record.Disabled = agent.Disabled;
record.AllowRouting = agent.AllowRouting;
record.Type = agent.Type;
record.Profiles = agent.Profiles ?? new List<string>();
record.RoutingRules = agent.RoutingRules ?? new List<RoutingRule>();
record.Instruction = agent.Instruction ?? string.Empty;
@ -60,7 +60,7 @@ public partial class AgentService
.SetDescription(foundAgent.Description)
.SetIsPublic(foundAgent.IsPublic)
.SetDisabled(foundAgent.Disabled)
.SetAllowRouting(foundAgent.AllowRouting)
.SetAgentType(foundAgent.Type)
.SetProfiles(foundAgent.Profiles)
.SetRoutingRules(foundAgent.RoutingRules)
.SetInstruction(foundAgent.Instruction)

View file

@ -59,7 +59,7 @@ public partial class ConversationService
var routing = _services.GetRequiredService<IRoutingService>();
var settings = _services.GetRequiredService<RoutingSettings>();
response = settings.AgentIds.Contains(agentId) ?
response = agent.Type == AgentType.Routing ?
await routing.InstructLoop(message) :
await routing.InstructDirect(agent, message);

View file

@ -126,7 +126,7 @@ public class NaivePlanner : IPlaner
var agentService = _services.GetRequiredService<IAgentService>();
var agents = agentService.GetAgents(new AgentFilter
{
AllowRouting = true
Type = AgentType.Task
}).Result.Items.ToList();
var malformed = false;

View file

@ -28,8 +28,8 @@ namespace BotSharp.Core.Repository
case AgentField.Disabled:
UpdateAgentDisabled(agent.Id, agent.Disabled);
break;
case AgentField.AllowRouting:
UpdateAgentAllowRouting(agent.Id, agent.AllowRouting);
case AgentField.Type:
UpdateAgentType(agent.Id, agent.Type);
break;
case AgentField.Profiles:
UpdateAgentProfiles(agent.Id, agent.Profiles);
@ -112,12 +112,12 @@ namespace BotSharp.Core.Repository
File.WriteAllText(agentFile, json);
}
private void UpdateAgentAllowRouting(string agentId, bool allowRouting)
private void UpdateAgentType(string agentId, string type)
{
var (agent, agentFile) = GetAgentFromFile(agentId);
if (agent == null) return;
agent.AllowRouting = allowRouting;
agent.Type = type;
agent.UpdatedDateTime = DateTime.UtcNow;
var json = JsonSerializer.Serialize(agent, _options);
File.WriteAllText(agentFile, json);
@ -260,7 +260,7 @@ namespace BotSharp.Core.Repository
agent.Description = inputAgent.Description;
agent.IsPublic = inputAgent.IsPublic;
agent.Disabled = inputAgent.Disabled;
agent.AllowRouting = inputAgent.AllowRouting;
agent.Type = inputAgent.Type;
agent.Profiles = inputAgent.Profiles;
agent.RoutingRules = inputAgent.RoutingRules;
agent.LlmConfig = inputAgent.LlmConfig;
@ -336,9 +336,9 @@ namespace BotSharp.Core.Repository
query = query.Where(x => x.Disabled == filter.Disabled);
}
if (filter.AllowRouting.HasValue)
if (filter.Type != null)
{
query = query.Where(x => x.AllowRouting == filter.AllowRouting);
query = query.Where(x => x.Type == filter.Type);
}
if (filter.IsPublic.HasValue)
@ -346,22 +346,6 @@ namespace BotSharp.Core.Repository
query = query.Where(x => x.IsPublic == filter.IsPublic);
}
if (filter.IsRouter.HasValue)
{
var route = _services.GetRequiredService<RoutingSettings>();
query = filter.IsRouter.Value ?
query.Where(x => route.AgentIds.Contains(x.Id)) :
query.Where(x => !route.AgentIds.Contains(x.Id));
}
if (filter.IsEvaluator.HasValue)
{
var evaluate = _services.GetRequiredService<EvaluatorSetting>();
query = filter.IsEvaluator.Value ?
query.Where(x => x.Id == evaluate.AgentId) :
query.Where(x => x.Id != evaluate.AgentId);
}
if (filter.AgentIds != null)
{
query = query.Where(x => filter.AgentIds.Contains(x.Id));

View file

@ -17,7 +17,7 @@ public class RoutingAgentHook : AgentHookBase
public override bool OnInstructionLoaded(string template, Dictionary<string, object> dict)
{
if (!_routingSetting.AgentIds.Contains(_agent.Id))
if (_agent.Type != AgentType.Routing)
{
return base.OnInstructionLoaded(template, dict);
}

View file

@ -134,7 +134,7 @@ public partial class RoutingService : IRoutingService
var filter = new AgentFilter
{
Disabled = false,
AllowRouting = true
Type = AgentType.Task
};
var agents = db.GetAgents(filter);
var records = agents.SelectMany(x =>
@ -160,7 +160,7 @@ public partial class RoutingService : IRoutingService
var filter = new AgentFilter
{
Disabled = false,
AllowRouting = true
Type = AgentType.Task
};
var agents = db.GetAgents(filter);
@ -192,6 +192,12 @@ public partial class RoutingService : IRoutingService
x.Profiles.Exists(x1 => profiles.Exists(y => x1 == y)))
.ToArray();
}
else if (profiles == null || profiles.Count == 0)
{
routableAgents = routableAgents.Where(x => x.Profiles == null ||
x.Profiles.Count == 0)
.ToArray();
}
return routableAgents;
}

View file

@ -1,10 +1,12 @@
{
"id": "01e2fc5c-2c89-4ec7-8470-7688608b496c",
"name": "Chatbot",
"description": "AI chatbot that can do variaty of tasks",
"type": "task",
"createdDateTime": "2024-01-15T10:39:32Z",
"updatedDateTime": "2024-01-15T14:39:32Z",
"id": "01e2fc5c-2c89-4ec7-8470-7688608b496c",
"iconUrl": "/images/users/bot.png",
"disabled": false,
"isPublic": true
"isPublic": true,
"profiles": [ "standalone" ]
}

View file

@ -1,9 +1,10 @@
{
"id": "01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a",
"name": "AI Assistant",
"description": "AI assistant that can complete many different tasks",
"type": "routing",
"createdDateTime": "2023-08-18T10:39:32.2349685Z",
"updatedDateTime": "2023-08-18T14:39:32.2349686Z",
"id": "01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a",
"iconUrl": "https://cdn.iconscout.com/icon/premium/png-256-thumb/route-1613278-1368497.png",
"disabled": false,
"isPublic": true

View file

@ -8,6 +8,7 @@ public class AgentCreationModel
{
public string Name { get; set; }
public string Description { get; set; }
public string Type { get; set; } = AgentType.Task;
/// <summary>
/// LLM default system instructions
@ -57,7 +58,7 @@ public class AgentCreationModel
Responses = Responses,
Samples = Samples,
IsPublic = IsPublic,
AllowRouting = AllowRouting,
Type = Type,
Disabled = Disabled,
Profiles = Profiles,
RoutingRules = RoutingRules?

View file

@ -9,7 +9,7 @@ public class AgentUpdateModel
{
public string Name { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public string Type { get; set; } = AgentType.Task;
/// <summary>
/// Instruction
/// </summary>
@ -62,7 +62,7 @@ public class AgentUpdateModel
Description = Description ?? string.Empty,
IsPublic = IsPublic,
Disabled = Disabled,
AllowRouting = AllowRouting,
Type = Type,
Profiles = Profiles ?? new List<string>(),
RoutingRules = RoutingRules?
.Select(x => RoutingRuleUpdateModel.ToDomainElement(x))?

View file

@ -11,6 +11,7 @@ public class AgentViewModel
public string Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Type { get; set; } = AgentType.Task;
public string Instruction { get; set; }
public List<AgentTemplate> Templates { get; set; }
public List<FunctionDef> Functions { get; set; }
@ -59,17 +60,16 @@ public class AgentViewModel
Id = agent.Id,
Name = agent.Name,
Description = agent.Description,
Type = agent.Type,
Instruction = agent.Instruction,
Templates = agent.Templates,
Functions = agent.Functions,
Responses = agent.Responses,
Samples = agent.Samples,
IsPublic= agent.IsPublic,
IsRouter = agent.IsRouter,
IsHost = agent.IsHost,
Disabled = agent.Disabled,
IconUrl = agent.IconUrl,
AllowRouting = agent.AllowRouting,
Profiles = agent.Profiles ?? new List<string>(),
RoutingRules = agent.RoutingRules,
LlmConfig = agent.LlmConfig,

View file

@ -6,6 +6,7 @@ public class AgentDocument : MongoBase
{
public string Name { get; set; }
public string Description { get; set; }
public string Type { get; set; }
public string? IconUrl { get; set; }
public string Instruction { get; set; }
public List<AgentTemplateMongoElement> Templates { get; set; }
@ -13,7 +14,6 @@ public class AgentDocument : MongoBase
public List<AgentResponseMongoElement> Responses { get; set; }
public List<string> Samples { get; set; }
public bool IsPublic { get; set; }
public bool AllowRouting { get; set; }
public bool Disabled { get; set; }
public List<string> Profiles { get; set; }
public List<RoutingRuleMongoElement> RoutingRules { get; set; }

View file

@ -29,8 +29,8 @@ public partial class MongoRepository
case AgentField.Disabled:
UpdateAgentDisabled(agent.Id, agent.Disabled);
break;
case AgentField.AllowRouting:
UpdateAgentAllowRouting(agent.Id, agent.AllowRouting);
case AgentField.Type:
UpdateAgentType(agent.Id, agent.Type);
break;
case AgentField.Profiles:
UpdateAgentProfiles(agent.Id, agent.Profiles);
@ -109,11 +109,11 @@ public partial class MongoRepository
_dc.Agents.UpdateOne(filter, update);
}
private void UpdateAgentAllowRouting(string agentId, bool allowRouting)
private void UpdateAgentType(string agentId, string type)
{
var filter = Builders<AgentDocument>.Filter.Eq(x => x.Id, agentId);
var update = Builders<AgentDocument>.Update
.Set(x => x.AllowRouting, allowRouting)
.Set(x => x.Type, type)
.Set(x => x.UpdatedTime, DateTime.UtcNow);
_dc.Agents.UpdateOne(filter, update);
@ -225,7 +225,7 @@ public partial class MongoRepository
.Set(x => x.Name, agent.Name)
.Set(x => x.Description, agent.Description)
.Set(x => x.Disabled, agent.Disabled)
.Set(x => x.AllowRouting, agent.AllowRouting)
.Set(x => x.Type, agent.Type)
.Set(x => x.Profiles, agent.Profiles)
.Set(x => x.RoutingRules, agent.RoutingRules.Select(r => RoutingRuleMongoElement.ToMongoElement(r)).ToList())
.Set(x => x.Instruction, agent.Instruction)
@ -267,7 +267,7 @@ public partial class MongoRepository
Samples = agent.Samples ?? new List<string>(),
IsPublic = agent.IsPublic,
Disabled = agent.Disabled,
AllowRouting = agent.AllowRouting,
Type = agent.Type,
Profiles = agent.Profiles,
RoutingRules = !agent.RoutingRules.IsNullOrEmpty() ? agent.RoutingRules
.Select(r => RoutingRuleMongoElement.ToDomainElement(agent.Id, agent.Name, r))
@ -292,9 +292,9 @@ public partial class MongoRepository
filters.Add(builder.Eq(x => x.Disabled, filter.Disabled.Value));
}
if (filter.AllowRouting.HasValue)
if (filter.Type != null)
{
filters.Add(builder.Eq(x => x.AllowRouting, filter.AllowRouting.Value));
filters.Add(builder.Eq(x => x.Type, filter.Type));
}
if (filter.IsPublic.HasValue)
@ -302,32 +302,6 @@ public partial class MongoRepository
filters.Add(builder.Eq(x => x.IsPublic, filter.IsPublic.Value));
}
if (filter.IsRouter.HasValue)
{
var route = _services.GetRequiredService<RoutingSettings>();
if (filter.IsRouter.Value)
{
filters.Add(builder.In(x => x.Id, route.AgentIds));
}
else
{
filters.Add(builder.Nin(x => x.Id, route.AgentIds));
}
}
if (filter.IsEvaluator.HasValue)
{
var evaluate = _services.GetRequiredService<EvaluatorSetting>();
if (filter.IsEvaluator.Value)
{
filters.Add(builder.Eq(x => x.Id, evaluate.AgentId));
}
else
{
filters.Add(builder.Ne(x => x.Id, evaluate.AgentId));
}
}
if (filter.AgentIds != null)
{
filters.Add(builder.In(x => x.Id, filter.AgentIds));
@ -354,7 +328,7 @@ public partial class MongoRepository
Samples = x.Samples ?? new List<string>(),
IsPublic = x.IsPublic,
Disabled = x.Disabled,
AllowRouting = x.AllowRouting,
Type = x.Type,
Profiles = x.Profiles,
RoutingRules = !x.RoutingRules.IsNullOrEmpty() ? x.RoutingRules
.Select(r => RoutingRuleMongoElement.ToDomainElement(x.Id, x.Name, r))
@ -418,7 +392,7 @@ public partial class MongoRepository
.ToList() ?? new List<AgentResponseMongoElement>(),
Samples = x.Samples ?? new List<string>(),
IsPublic = x.IsPublic,
AllowRouting = x.AllowRouting,
Type = x.Type,
Disabled = x.Disabled,
Profiles = x.Profiles,
RoutingRules = x.RoutingRules?

View file

@ -54,7 +54,7 @@ public partial class MongoRepository
.ToList() ?? new List<AgentResponseMongoElement>(),
Samples = x.Samples ?? new List<string>(),
IsPublic = x.IsPublic,
AllowRouting = x.AllowRouting,
Type = x.Type,
Disabled = x.Disabled,
Profiles = x.Profiles,
RoutingRules = x.RoutingRules?
@ -77,7 +77,7 @@ public partial class MongoRepository
.Set(x => x.Responses, agent.Responses)
.Set(x => x.Samples, agent.Samples)
.Set(x => x.IsPublic, agent.IsPublic)
.Set(x => x.AllowRouting, agent.AllowRouting)
.Set(x => x.Type, agent.Type)
.Set(x => x.Disabled, agent.Disabled)
.Set(x => x.Profiles, agent.Profiles)
.Set(x => x.RoutingRules, agent.RoutingRules)

View file

@ -53,7 +53,7 @@ public class RoutingConversationHook: ConversationHookBase
public override async Task OnResponseGenerated(RoleDialogModel message)
{
var routerSettings = _services.GetRequiredService<RoutingSettings>();
bool saveFlag = !routerSettings.AgentIds.Contains(message.CurrentAgentId);
bool saveFlag = _agent.Type != AgentType.Routing;
if (saveFlag)
{

View file

@ -1,9 +1,9 @@
{
"id": "f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b",
"name": "Web Driver",
"description": "Perform a specific action on a web browser",
"type": "task",
"createdDateTime": "2024-01-02T00:00:00Z",
"updatedDateTime": "2024-01-02T00:00:00Z",
"id": "f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b",
"allowRouting": true,
"isPublic": true
}

View file

@ -60,9 +60,6 @@
],
"Router": {
"AgentIds": [
"01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a"
],
"Planner": "NaivePlanner"
},