Move router profile to liquid.
This commit is contained in:
parent
8003fc39f0
commit
4e2d00611b
|
|
@ -2,7 +2,10 @@ namespace BotSharp.Abstraction.Models;
|
||||||
|
|
||||||
public class NameDesc
|
public class NameDesc
|
||||||
{
|
{
|
||||||
|
[JsonPropertyName("name")]
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("description")]
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
|
|
||||||
public NameDesc(string name, string description)
|
public NameDesc(string name, string description)
|
||||||
|
|
@ -10,4 +13,7 @@ public class NameDesc
|
||||||
Name = name;
|
Name = name;
|
||||||
Description = description;
|
Description = description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
=> $"{Name}: {Description}";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ public interface IRouterInstance
|
||||||
{
|
{
|
||||||
string AgentId { get; }
|
string AgentId { get; }
|
||||||
Agent Router { get; }
|
Agent Router { get; }
|
||||||
|
RoutingItem[] GetRoutingItems();
|
||||||
List<RoutingHandlerDef> GetHandlers();
|
List<RoutingHandlerDef> GetHandlers();
|
||||||
IRouterInstance Load();
|
IRouterInstance Load();
|
||||||
IRouterInstance WithDialogs(List<RoleDialogModel> dialogs);
|
IRouterInstance WithDialogs(List<RoleDialogModel> dialogs);
|
||||||
|
|
|
||||||
|
|
@ -7,4 +7,7 @@ public class RoutingHandlerDef
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
public List<NameDesc> Parameters { get; set; }
|
public List<NameDesc> Parameters { get; set; }
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
=> $"{Name}: {Description} ({Parameters.Count} Parameters)";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,6 @@ public class RoutingSettings
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string RouterId { get; set; } = string.Empty;
|
public string RouterId { get; set; } = string.Empty;
|
||||||
|
|
||||||
public string RouterName { get; set; } = "Router";
|
|
||||||
|
|
||||||
public string Description { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public bool EnableReasoning { get; set; } = false;
|
public bool EnableReasoning { get; set; } = false;
|
||||||
public bool UseTextCompletion { get; set; } = false;
|
public bool UseTextCompletion { get; set; } = false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,13 +25,6 @@ public partial class AgentService
|
||||||
#endif
|
#endif
|
||||||
public async Task<Agent> GetAgent(string id)
|
public async Task<Agent> GetAgent(string id)
|
||||||
{
|
{
|
||||||
var settings = _services.GetRequiredService<RoutingSettings>();
|
|
||||||
var routerInstance = _services.GetRequiredService<IRouterInstance>();
|
|
||||||
if (settings.RouterId == id)
|
|
||||||
{
|
|
||||||
return routerInstance.Load().Router;
|
|
||||||
}
|
|
||||||
|
|
||||||
var profile = _db.GetAgent(id);
|
var profile = _db.GetAgent(id);
|
||||||
|
|
||||||
var instructionFile = profile?.Instruction;
|
var instructionFile = profile?.Instruction;
|
||||||
|
|
|
||||||
|
|
@ -63,4 +63,8 @@
|
||||||
<ProjectReference Include="..\BotSharp.Abstraction\BotSharp.Abstraction.csproj" />
|
<ProjectReference Include="..\BotSharp.Abstraction\BotSharp.Abstraction.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Routing\Functions\" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ public partial class ConversationService
|
||||||
|
|
||||||
var routingSetting = _services.GetRequiredService<RoutingSettings>();
|
var routingSetting = _services.GetRequiredService<RoutingSettings>();
|
||||||
var agentName = routingSetting.RouterId == message.CurrentAgentId ?
|
var agentName = routingSetting.RouterId == message.CurrentAgentId ?
|
||||||
routingSetting.RouterName :
|
"Router" :
|
||||||
(await _services.GetRequiredService<IAgentService>().GetAgent(message.CurrentAgentId)).Name;
|
(await _services.GetRequiredService<IAgentService>().GetAgent(message.CurrentAgentId)).Name;
|
||||||
|
|
||||||
var text = message.Role == AgentRole.Function ?
|
var text = message.Role == AgentRole.Function ?
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ public class ConversationStorage : IConversationStorage
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var routingSetting = _services.GetRequiredService<RoutingSettings>();
|
var routingSetting = _services.GetRequiredService<RoutingSettings>();
|
||||||
var agentName = routingSetting.RouterId == agentId ? routingSetting.RouterName : db.Agents.First(x => x.Id == agentId).Name;
|
var agentName = routingSetting.RouterId == agentId ? "Router" : db.Agents.First(x => x.Id == agentId).Name;
|
||||||
|
|
||||||
sb.AppendLine($"{dialog.CreatedAt}|{dialog.Role}|{agentId}|{agentName}|");
|
sb.AppendLine($"{dialog.CreatedAt}|{dialog.Role}|{agentId}|{agentName}|");
|
||||||
var content = dialog.Content.Replace("\r", " ").Replace("\n", " ").Trim();
|
var content = dialog.Content.Replace("\r", " ").Replace("\n", " ").Trim();
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
using BotSharp.Abstraction.Functions.Models;
|
using BotSharp.Abstraction.Functions.Models;
|
||||||
|
using BotSharp.Abstraction.Models;
|
||||||
|
using BotSharp.Abstraction.Repositories;
|
||||||
|
using BotSharp.Abstraction.Routing;
|
||||||
|
using BotSharp.Abstraction.Routing.Models;
|
||||||
|
|
||||||
namespace BotSharp.Core.Routing.Hooks;
|
namespace BotSharp.Core.Routing.Hooks;
|
||||||
|
|
||||||
|
|
@ -9,6 +13,17 @@ public class RoutingAgentHook : AgentHookBase
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool OnInstructionLoaded(string template, Dictionary<string, object> dict)
|
||||||
|
{
|
||||||
|
dict["router"] = _agent;
|
||||||
|
|
||||||
|
var router = _services.GetRequiredService<IRouterInstance>();
|
||||||
|
dict["routing_agents"] = router.GetRoutingItems();
|
||||||
|
dict["routing_handlers"] = router.GetHandlers();
|
||||||
|
|
||||||
|
return base.OnInstructionLoaded(template, dict);
|
||||||
|
}
|
||||||
|
|
||||||
public override bool OnFunctionsLoaded(List<FunctionDef> functions)
|
public override bool OnFunctionsLoaded(List<FunctionDef> functions)
|
||||||
{
|
{
|
||||||
/*functions.Add(new FunctionDef
|
/*functions.Add(new FunctionDef
|
||||||
|
|
|
||||||
|
|
@ -28,80 +28,8 @@ public class RouterInstance : IRouterInstance
|
||||||
|
|
||||||
public IRouterInstance Load()
|
public IRouterInstance Load()
|
||||||
{
|
{
|
||||||
var db = _services.GetRequiredService<IBotSharpRepository>();
|
var agentService = _services.GetRequiredService<IAgentService>();
|
||||||
|
_router = agentService.LoadAgent(_settings.RouterId).Result;
|
||||||
_router = new Agent()
|
|
||||||
{
|
|
||||||
Id = _settings.RouterId,
|
|
||||||
Name = _settings.RouterName,
|
|
||||||
Description = _settings.Description
|
|
||||||
};
|
|
||||||
var agents = db.Agents.Where(x => !x.Disabled && x.AllowRouting).ToArray();
|
|
||||||
|
|
||||||
// Assemble prompt
|
|
||||||
var prompt = @$"You're {_settings.RouterName} ({_settings.Description}). Follow these steps to handle user's request:
|
|
||||||
1. Read the CONVERSATION context.
|
|
||||||
2. Select a appropriate function from FUNCTIONS.
|
|
||||||
3. Determine which agent is suitable according to conversation context.
|
|
||||||
4. Re-think about selected function is from FUNCTIONS to handle the request.
|
|
||||||
5. Make sure agent is not in args.";
|
|
||||||
|
|
||||||
// Append function
|
|
||||||
prompt += "\r\n";
|
|
||||||
prompt += "\r\nFUNCTIONS";
|
|
||||||
GetHandlers().Select((handler, i) =>
|
|
||||||
{
|
|
||||||
prompt += "\r\n";
|
|
||||||
prompt += $"\r\n{i + 1}. {handler.Name}";
|
|
||||||
prompt += $"\r\n{handler.Description}";
|
|
||||||
|
|
||||||
// Append parameters
|
|
||||||
if (handler.Parameters.Any())
|
|
||||||
{
|
|
||||||
prompt += "\r\nParameters:";
|
|
||||||
handler.Parameters.Select((p, i) =>
|
|
||||||
{
|
|
||||||
prompt += $"\r\n - {p.Name}: {p.Description}";
|
|
||||||
return p;
|
|
||||||
}).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
return handler;
|
|
||||||
}).ToList();
|
|
||||||
|
|
||||||
prompt += "\r\n";
|
|
||||||
prompt += "\r\nAGENTS";
|
|
||||||
agents.Select(x => new RoutingItem
|
|
||||||
{
|
|
||||||
AgentId = x.Id,
|
|
||||||
Description = x.Description,
|
|
||||||
Name = x.Name,
|
|
||||||
RequiredFields = x.RoutingRules.Where(x => x.Required)
|
|
||||||
.Select(x => new NameDesc(x.Field, x.Description))
|
|
||||||
.ToList()
|
|
||||||
}).Select((agent, i) =>
|
|
||||||
{
|
|
||||||
prompt += "\r\n";
|
|
||||||
prompt += $"\r\n{i + 1}. {agent.Name}";
|
|
||||||
prompt += $"\r\n{agent.Description}";
|
|
||||||
|
|
||||||
// Append parameters
|
|
||||||
if (agent.RequiredFields.Any())
|
|
||||||
{
|
|
||||||
prompt += $"\r\nRequired:";
|
|
||||||
agent.RequiredFields.Select((field, i) =>
|
|
||||||
{
|
|
||||||
prompt += $"\r\n - {field.Name}: {field.Description}";
|
|
||||||
return field;
|
|
||||||
}).ToList();
|
|
||||||
}
|
|
||||||
return agent;
|
|
||||||
}).ToList();
|
|
||||||
|
|
||||||
prompt += "\r\n";
|
|
||||||
prompt += "\r\nCONVERSATION";
|
|
||||||
_router.Instruction = prompt;
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -119,7 +47,7 @@ public class RouterInstance : IRouterInstance
|
||||||
return _services.GetServices<IRoutingHandler>()
|
return _services.GetServices<IRoutingHandler>()
|
||||||
.Where(x => x.IsReasoning == _settings.EnableReasoning)
|
.Where(x => x.IsReasoning == _settings.EnableReasoning)
|
||||||
.Where(x => !string.IsNullOrEmpty(x.Description))
|
.Where(x => !string.IsNullOrEmpty(x.Description))
|
||||||
.Select(x => new RoutingHandlerDef
|
.Select((x, i) => new RoutingHandlerDef
|
||||||
{
|
{
|
||||||
Name = x.Name,
|
Name = x.Name,
|
||||||
Description = x.Description,
|
Description = x.Description,
|
||||||
|
|
@ -157,6 +85,25 @@ public class RouterInstance : IRouterInstance
|
||||||
return records;
|
return records;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !DEBUG
|
||||||
|
[MemoryCache(10 * 60)]
|
||||||
|
#endif
|
||||||
|
public RoutingItem[] GetRoutingItems()
|
||||||
|
{
|
||||||
|
var db = _services.GetRequiredService<IBotSharpRepository>();
|
||||||
|
|
||||||
|
var agents = db.Agents.Where(x => !x.Disabled && x.AllowRouting).ToArray();
|
||||||
|
return agents.Select(x => new RoutingItem
|
||||||
|
{
|
||||||
|
AgentId = x.Id,
|
||||||
|
Description = x.Description,
|
||||||
|
Name = x.Name,
|
||||||
|
RequiredFields = x.RoutingRules.Where(x => x.Required)
|
||||||
|
.Select(x => new NameDesc(x.Field, x.Description))
|
||||||
|
.ToList()
|
||||||
|
}).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
public RoutingRule[] GetRulesByName(string name)
|
public RoutingRule[] GetRulesByName(string name)
|
||||||
{
|
{
|
||||||
return GetRoutingRecords()
|
return GetRoutingRecords()
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ public partial class RoutingService
|
||||||
_logger.LogError($"{ex.Message}: {response.Content}");
|
_logger.LogError($"{ex.Message}: {response.Content}");
|
||||||
args.Function = "response_to_user";
|
args.Function = "response_to_user";
|
||||||
args.Answer = ex.Message;
|
args.Answer = ex.Message;
|
||||||
args.AgentName = _settings.RouterName;
|
args.AgentName = "Router";
|
||||||
content += "\r\nPlease response in JSON format.";
|
content += "\r\nPlease response in JSON format.";
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
|
@ -85,7 +85,7 @@ public partial class RoutingService
|
||||||
_logger.LogError($"{ex.Message}: {response.Content}");
|
_logger.LogError($"{ex.Message}: {response.Content}");
|
||||||
args.Function = "response_to_user";
|
args.Function = "response_to_user";
|
||||||
args.Answer = ex.Message;
|
args.Answer = ex.Message;
|
||||||
args.AgentName = _settings.RouterName;
|
args.AgentName = "Router";
|
||||||
content += "\r\nPlease response in JSON format.";
|
content += "\r\nPlease response in JSON format.";
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,7 @@ public partial class RoutingService : IRoutingService
|
||||||
loopCount++;
|
loopCount++;
|
||||||
|
|
||||||
var prompt = _settings.EnableReasoning ? "Tell me the next step?" : "Which agent is suitable to handle user's request based on the CONVERSATION?";
|
var prompt = _settings.EnableReasoning ? "Tell me the next step?" : "Which agent is suitable to handle user's request based on the CONVERSATION?";
|
||||||
|
prompt += " Or you can handle without asking specific agent.";
|
||||||
var inst = await GetNextInstruction(prompt);
|
var inst = await GetNextInstruction(prompt);
|
||||||
inst.Question = inst.Question ?? message;
|
inst.Question = inst.Question ?? message;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
using BotSharp.Abstraction.Agents.Models;
|
||||||
|
using BotSharp.Abstraction.Models;
|
||||||
using BotSharp.Abstraction.Routing.Models;
|
using BotSharp.Abstraction.Routing.Models;
|
||||||
using BotSharp.Abstraction.Templating;
|
using BotSharp.Abstraction.Templating;
|
||||||
using Fluid;
|
using Fluid;
|
||||||
|
|
@ -17,6 +19,9 @@ public class TemplateRender : ITemplateRender
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_options = new TemplateOptions();
|
_options = new TemplateOptions();
|
||||||
_options.MemberAccessStrategy.MemberNameStrategy = MemberNameStrategies.SnakeCase;
|
_options.MemberAccessStrategy.MemberNameStrategy = MemberNameStrategies.SnakeCase;
|
||||||
|
|
||||||
|
_options.MemberAccessStrategy.Register<NameDesc>();
|
||||||
|
_options.MemberAccessStrategy.Register<Agent>();
|
||||||
_options.MemberAccessStrategy.Register<RoutingItem>();
|
_options.MemberAccessStrategy.Register<RoutingItem>();
|
||||||
_options.MemberAccessStrategy.Register<RoutingHandlerDef>();
|
_options.MemberAccessStrategy.Register<RoutingHandlerDef>();
|
||||||
}
|
}
|
||||||
|
|
@ -31,7 +36,6 @@ public class TemplateRender : ITemplateRender
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
return template;
|
return template;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"name": "PizzaBot",
|
||||||
|
"description": "Pizza restaurant AI Bot",
|
||||||
|
"createdDateTime": "2023-08-18T14:39:32.2349685Z",
|
||||||
|
"updatedDateTime": "2023-08-18T14:39:32.2349686Z",
|
||||||
|
"id": "01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
You're {{router.name}} ({{router.description}}). Follow these steps to handle user's request:
|
||||||
|
1. Read the CONVERSATION context.
|
||||||
|
2. Select a appropriate function from FUNCTIONS.
|
||||||
|
3. Determine which agent is suitable according to conversation context.
|
||||||
|
4. Re-think about selected function is from FUNCTIONS to handle the request.
|
||||||
|
5. Make sure agent is not in args.
|
||||||
|
|
||||||
|
FUNCTIONS
|
||||||
|
{% for handler in routing_handlers %}
|
||||||
|
# {{ handler.name }}
|
||||||
|
{{ handler.description}}
|
||||||
|
{% if handler.parameters -%}
|
||||||
|
Parameters:
|
||||||
|
{% for p in handler.parameters -%}
|
||||||
|
{{ p.name }}: {{ p.description }}{{ "\r\n " }}
|
||||||
|
{%- endfor %}
|
||||||
|
{%- endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
AGENTS
|
||||||
|
{% for agent in routing_agents %}
|
||||||
|
* {{ agent.name }}
|
||||||
|
{{ agent.description}}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
CONVERSATION
|
||||||
Loading…
Reference in a new issue