add agent channel instructions

This commit is contained in:
Jicheng Lu 2024-08-13 16:36:12 -05:00
parent 3276b7cd8a
commit 8b86ea50d0
19 changed files with 310 additions and 182 deletions

View file

@ -20,6 +20,13 @@ public interface IAgentService
/// <returns></returns> /// <returns></returns>
Task<Agent> LoadAgent(string id); Task<Agent> LoadAgent(string id);
/// <summary>
/// Inherit from host agent
/// </summary>
/// <param name="agent"></param>
/// <returns></returns>
Task InheritAgent(Agent agent);
string RenderedInstruction(Agent agent); string RenderedInstruction(Agent agent);
string RenderedTemplate(Agent agent, string templateName); string RenderedTemplate(Agent agent, string templateName);

View file

@ -1,6 +1,5 @@
using BotSharp.Abstraction.Functions.Models; using BotSharp.Abstraction.Functions.Models;
using BotSharp.Abstraction.Plugins.Models; using BotSharp.Abstraction.Plugins.Models;
using BotSharp.Abstraction.Routing.Models;
using BotSharp.Abstraction.Tasks.Models; using BotSharp.Abstraction.Tasks.Models;
namespace BotSharp.Abstraction.Agents.Models; namespace BotSharp.Abstraction.Agents.Models;
@ -21,8 +20,7 @@ public class Agent
/// Default LLM settings /// Default LLM settings
/// </summary> /// </summary>
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public AgentLlmConfig LlmConfig { get; set; } public AgentLlmConfig LlmConfig { get; set; } = new();
= new AgentLlmConfig();
/// <summary> /// <summary>
/// Instruction /// Instruction
@ -30,33 +28,35 @@ public class Agent
[JsonIgnore] [JsonIgnore]
public string? Instruction { get; set; } public string? Instruction { get; set; }
/// <summary>
/// Channel instructions
/// </summary>
[JsonIgnore]
public List<ChannelInstruction> ChannelInstructions { get; set; } = new();
/// <summary> /// <summary>
/// Templates /// Templates
/// </summary> /// </summary>
[JsonIgnore] [JsonIgnore]
public List<AgentTemplate> Templates { get; set; } public List<AgentTemplate> Templates { get; set; } = new();
= new List<AgentTemplate>();
/// <summary> /// <summary>
/// Agent tasks /// Agent tasks
/// </summary> /// </summary>
[JsonIgnore] [JsonIgnore]
public List<AgentTask> Tasks { get; set; } public List<AgentTask> Tasks { get; set; } = new();
= new List<AgentTask>();
/// <summary> /// <summary>
/// Samples /// Samples
/// </summary> /// </summary>
[JsonIgnore] [JsonIgnore]
public List<string> Samples { get; set; } public List<string> Samples { get; set; } = new();
= new List<string>();
/// <summary> /// <summary>
/// Functions /// Functions
/// </summary> /// </summary>
[JsonIgnore] [JsonIgnore]
public List<FunctionDef> Functions { get; set; } public List<FunctionDef> Functions { get; set; } = new();
= new List<FunctionDef>();
/// <summary> /// <summary>
/// Responses /// Responses
@ -93,23 +93,20 @@ public class Agent
/// <summary> /// <summary>
/// Agent utilities /// Agent utilities
/// </summary> /// </summary>
public List<string> Utilities { get; set; } public List<string> Utilities { get; set; } = new();
= new List<string>();
/// <summary> /// <summary>
/// Inherit from agent /// Inherit from agent
/// </summary> /// </summary>
public string? InheritAgentId { get; set; } public string? InheritAgentId { get; set; }
public List<RoutingRule> RoutingRules { get; set; } public List<RoutingRule> RoutingRules { get; set; } = new();
= new List<RoutingRule>();
/// <summary> /// <summary>
/// For rendering deferral /// For rendering deferral
/// </summary> /// </summary>
[JsonIgnore] [JsonIgnore]
public Dictionary<string, object> TemplateDict { get; set; } public Dictionary<string, object> TemplateDict { get; set; } = new();
= new Dictionary<string, object>();
public override string ToString() public override string ToString()
=> $"{Name} {Id}"; => $"{Name} {Id}";
@ -124,6 +121,7 @@ public class Agent
Description = agent.Description, Description = agent.Description,
Type = agent.Type, Type = agent.Type,
Instruction = agent.Instruction, Instruction = agent.Instruction,
ChannelInstructions = agent.ChannelInstructions,
Functions = agent.Functions, Functions = agent.Functions,
Responses = agent.Responses, Responses = agent.Responses,
Samples = agent.Samples, Samples = agent.Samples,
@ -145,6 +143,12 @@ public class Agent
return this; return this;
} }
public Agent SetChannelInstructions(List<ChannelInstruction> instructions)
{
ChannelInstructions = instructions ?? new List<ChannelInstruction>();
return this;
}
public Agent SetTemplates(List<AgentTemplate> templates) public Agent SetTemplates(List<AgentTemplate> templates)
{ {
Templates = templates ?? new List<AgentTemplate>(); Templates = templates ?? new List<AgentTemplate>();

View file

@ -0,0 +1,7 @@
namespace BotSharp.Abstraction.Agents.Models;
public class ChannelInstruction
{
public string Channel { get; set; }
public string Instruction { get; set; }
}

View file

@ -2,7 +2,7 @@ namespace BotSharp.Abstraction.Knowledges.Models;
public class KnowledgeSearchResult public class KnowledgeSearchResult
{ {
public IDictionary<string, string> Data { get; set; } = new Dictionary<string, string>(); public Dictionary<string, string> Data { get; set; } = new();
public double Score { get; set; } public double Score { get; set; }
public float[]? Vector { get; set; } public float[]? Vector { get; set; }
} }

View file

@ -41,41 +41,49 @@ public partial class AgentService
}); });
Utilities.ClearCache(); Utilities.ClearCache();
return await Task.FromResult(agentRecord); return await Task.FromResult(agentRecord);
} }
private Agent FetchAgentFileByName(string agentName, string filePath) private (string, List<ChannelInstruction>) FetchInstructionsFromFile(string fileDir)
{ {
foreach (var dir in Directory.GetDirectories(filePath)) var defaultInstruction = string.Empty;
var channelInstructions = new List<ChannelInstruction>();
var instructionDir = Path.Combine(fileDir, "instructions");
if (!Directory.Exists(instructionDir))
{ {
var agentJson = File.ReadAllText(Path.Combine(dir, "agent.json")); return (defaultInstruction, channelInstructions);
var agent = JsonSerializer.Deserialize<Agent>(agentJson, _options);
if (agent != null && agent.Name.IsEqualTo(agentName))
{
var functions = FetchFunctionsFromFile(dir);
var instruction = FetchInstructionFromFile(dir);
var responses = FetchResponsesFromFile(dir);
var templates = FetchTemplatesFromFile(dir);
var samples = FetchSamplesFromFile(dir);
return agent.SetInstruction(instruction)
.SetTemplates(templates)
.SetFunctions(functions)
.SetResponses(responses)
.SetSamples(samples);
}
} }
return null; foreach (var file in Directory.GetFiles(instructionDir))
} {
var extension = Path.GetExtension(file).Substring(1);
if (!extension.IsEqualTo(_agentSettings.TemplateFormat))
{
continue;
}
private string FetchInstructionFromFile(string fileDir) var segments = Path.GetFileName(file).Split(".", StringSplitOptions.RemoveEmptyEntries);
{ if (segments.IsNullOrEmpty() || !segments[0].IsEqualTo("instruction"))
var file = Path.Combine(fileDir, $"instruction.{_agentSettings.TemplateFormat}"); {
if (!File.Exists(file)) return null; continue;
}
var instruction = File.ReadAllText(file); if (segments.Length == 2)
return instruction; {
defaultInstruction = File.ReadAllText(file);
}
else if (segments.Length == 3)
{
var item = new ChannelInstruction
{
Channel = segments[1],
Instruction = File.ReadAllText(file)
};
channelInstructions.Add(item);
}
}
return (defaultInstruction, channelInstructions);
} }
private List<AgentTemplate> FetchTemplatesFromFile(string fileDir) private List<AgentTemplate> FetchTemplatesFromFile(string fileDir)
@ -86,10 +94,10 @@ public partial class AgentService
foreach (var file in Directory.GetFiles(templateDir)) foreach (var file in Directory.GetFiles(templateDir))
{ {
var name = Path.GetFileNameWithoutExtension(file);
var extension = Path.GetExtension(file).Substring(1); var extension = Path.GetExtension(file).Substring(1);
if (extension.IsEqualTo(_agentSettings.TemplateFormat)) if (extension.IsEqualTo(_agentSettings.TemplateFormat))
{ {
var name = Path.GetFileNameWithoutExtension(file);
var content = File.ReadAllText(file); var content = File.ReadAllText(file);
templates.Add(new AgentTemplate(name, content)); templates.Add(new AgentTemplate(name, content));
} }

View file

@ -53,7 +53,29 @@ public partial class AgentService
} }
profile.Plugin = GetPlugin(profile.Id); profile.Plugin = GetPlugin(profile.Id);
return profile; return profile;
} }
public async Task InheritAgent(Agent agent)
{
if (string.IsNullOrWhiteSpace(agent?.InheritAgentId)) return;
var inheritedAgent = await GetAgent(agent.InheritAgentId);
agent.Templates.AddRange(inheritedAgent.Templates
// exclude private template
.Where(x => !x.Name.StartsWith("."))
// exclude duplicate name
.Where(x => !agent.Templates.Exists(t => t.Name == x.Name)));
agent.Functions.AddRange(inheritedAgent.Functions
// exclude private template
.Where(x => !x.Name.StartsWith("."))
// exclude duplicate name
.Where(x => !agent.Functions.Exists(t => t.Name == x.Name)));
if (string.IsNullOrWhiteSpace(agent.Instruction))
{
agent.Instruction = inheritedAgent.Instruction;
}
}
} }

View file

@ -34,31 +34,12 @@ public partial class AgentService
return null; return null;
} }
if (agent.InheritAgentId != null) await InheritAgent(agent);
{ OverrideInstructionByChannel(agent);
var inheritedAgent = await GetAgent(agent.InheritAgentId);
agent.Templates.AddRange(inheritedAgent.Templates
// exclude private template
.Where(x => !x.Name.StartsWith("."))
// exclude duplicate name
.Where(x => !agent.Templates.Exists(t => t.Name == x.Name)));
agent.Functions.AddRange(inheritedAgent.Functions
// exclude private template
.Where(x => !x.Name.StartsWith("."))
// exclude duplicate name
.Where(x => !agent.Functions.Exists(t => t.Name == x.Name)));
if (agent.Instruction == null)
{
agent.Instruction = inheritedAgent.Instruction;
}
}
AddOrUpdateParameters(agent); AddOrUpdateParameters(agent);
agent.TemplateDict = new Dictionary<string, object>();
// Populate state into dictionary // Populate state into dictionary
agent.TemplateDict = new Dictionary<string, object>();
PopulateState(agent.TemplateDict); PopulateState(agent.TemplateDict);
// After agent is loaded // After agent is loaded
@ -94,6 +75,23 @@ public partial class AgentService
return agent; return agent;
} }
private void OverrideInstructionByChannel(Agent agent)
{
var instructions = agent.ChannelInstructions;
if (instructions.IsNullOrEmpty()) return;
var state = _services.GetRequiredService<IConversationStateService>();
var channel = state.GetState("channel");
if (string.IsNullOrWhiteSpace(channel))
{
return;
}
var found = instructions.FirstOrDefault(x => x.Channel.IsEqualTo(channel));
agent.Instruction = !string.IsNullOrWhiteSpace(found?.Instruction) ? found.Instruction : agent.Instruction;
}
private void PopulateState(Dictionary<string, object> dict) private void PopulateState(Dictionary<string, object> dict)
{ {
var conv = _services.GetRequiredService<IConversationService>(); var conv = _services.GetRequiredService<IConversationService>();
@ -114,18 +112,27 @@ public partial class AgentService
private void AddOrUpdateRoutesParameters(string agentId, List<RoutingRule> routingRules) private void AddOrUpdateRoutesParameters(string agentId, List<RoutingRule> routingRules)
{ {
if(!AgentParameterTypes.TryGetValue(agentId, out var parameterTypes)) parameterTypes = new(); if(!AgentParameterTypes.TryGetValue(agentId, out var parameterTypes))
{
parameterTypes = new();
}
foreach (var rule in routingRules.Where(x => x.Required)) foreach (var rule in routingRules.Where(x => x.Required))
{ {
if (string.IsNullOrEmpty(rule.FieldType)) continue; if (string.IsNullOrEmpty(rule.FieldType)) continue;
parameterTypes.TryAdd(rule.Field, rule.FieldType); parameterTypes.TryAdd(rule.Field, rule.FieldType);
} }
AgentParameterTypes.TryAdd(agentId, parameterTypes); AgentParameterTypes.TryAdd(agentId, parameterTypes);
} }
private void AddOrUpdateFunctionsParameters(string agentId, List<FunctionDef> functions) private void AddOrUpdateFunctionsParameters(string agentId, List<FunctionDef> functions)
{ {
if (!AgentParameterTypes.TryGetValue(agentId, out var parameterTypes)) parameterTypes = new(); if (!AgentParameterTypes.TryGetValue(agentId, out var parameterTypes))
{
parameterTypes = new();
}
var parameters = functions.Select(p => p.Parameters); var parameters = functions.Select(p => p.Parameters);
foreach (var param in parameters) foreach (var param in parameters)
{ {
@ -139,6 +146,7 @@ public partial class AgentService
} }
} }
} }
AgentParameterTypes.TryAdd(agentId, parameterTypes); AgentParameterTypes.TryAdd(agentId, parameterTypes);
} }
} }

View file

@ -42,12 +42,13 @@ public partial class AgentService
continue; continue;
} }
var (defaultInstruction, channelInstructions) = FetchInstructionsFromFile(dir);
var functions = FetchFunctionsFromFile(dir); var functions = FetchFunctionsFromFile(dir);
var instruction = FetchInstructionFromFile(dir);
var responses = FetchResponsesFromFile(dir); var responses = FetchResponsesFromFile(dir);
var templates = FetchTemplatesFromFile(dir); var templates = FetchTemplatesFromFile(dir);
var samples = FetchSamplesFromFile(dir); var samples = FetchSamplesFromFile(dir);
agent.SetInstruction(instruction) agent.SetInstruction(defaultInstruction)
.SetChannelInstructions(channelInstructions)
.SetTemplates(templates) .SetTemplates(templates)
.SetFunctions(functions) .SetFunctions(functions)
.SetResponses(responses) .SetResponses(responses)

View file

@ -28,6 +28,7 @@ public partial class AgentService
record.Profiles = agent.Profiles ?? new List<string>(); record.Profiles = agent.Profiles ?? new List<string>();
record.RoutingRules = agent.RoutingRules ?? new List<RoutingRule>(); record.RoutingRules = agent.RoutingRules ?? new List<RoutingRule>();
record.Instruction = agent.Instruction ?? string.Empty; record.Instruction = agent.Instruction ?? string.Empty;
record.ChannelInstructions = agent.ChannelInstructions ?? new List<ChannelInstruction>();
record.Functions = agent.Functions ?? new List<FunctionDef>(); record.Functions = agent.Functions ?? new List<FunctionDef>();
record.Templates = agent.Templates ?? new List<AgentTemplate>(); record.Templates = agent.Templates ?? new List<AgentTemplate>();
record.Responses = agent.Responses ?? new List<AgentResponse>(); record.Responses = agent.Responses ?? new List<AgentResponse>();
@ -41,7 +42,6 @@ public partial class AgentService
_db.UpdateAgent(record, updateField); _db.UpdateAgent(record, updateField);
Utilities.ClearCache(); Utilities.ClearCache();
await Task.CompletedTask; await Task.CompletedTask;
} }
@ -90,6 +90,7 @@ public partial class AgentService
.SetProfiles(foundAgent.Profiles) .SetProfiles(foundAgent.Profiles)
.SetRoutingRules(foundAgent.RoutingRules) .SetRoutingRules(foundAgent.RoutingRules)
.SetInstruction(foundAgent.Instruction) .SetInstruction(foundAgent.Instruction)
.SetChannelInstructions(foundAgent.ChannelInstructions)
.SetTemplates(foundAgent.Templates) .SetTemplates(foundAgent.Templates)
.SetFunctions(foundAgent.Functions) .SetFunctions(foundAgent.Functions)
.SetResponses(foundAgent.Responses) .SetResponses(foundAgent.Responses)
@ -175,12 +176,13 @@ public partial class AgentService
var agent = JsonSerializer.Deserialize<Agent>(agentJson, _options); var agent = JsonSerializer.Deserialize<Agent>(agentJson, _options);
if (agent != null && agent.Id == agentId) if (agent != null && agent.Id == agentId)
{ {
var (defaultInstruction, channelInstructions) = FetchInstructionsFromFile(dir);
var functions = FetchFunctionsFromFile(dir); var functions = FetchFunctionsFromFile(dir);
var instruction = FetchInstructionFromFile(dir);
var responses = FetchResponsesFromFile(dir); var responses = FetchResponsesFromFile(dir);
var templates = FetchTemplatesFromFile(dir); var templates = FetchTemplatesFromFile(dir);
var samples = FetchSamplesFromFile(dir); var samples = FetchSamplesFromFile(dir);
return agent.SetInstruction(instruction) return agent.SetInstruction(defaultInstruction)
.SetChannelInstructions(channelInstructions)
.SetTemplates(templates) .SetTemplates(templates)
.SetFunctions(functions) .SetFunctions(functions)
.SetResponses(responses) .SetResponses(responses)

View file

@ -1,6 +1,6 @@
using BotSharp.Abstraction.Functions.Models;
using BotSharp.Abstraction.Routing.Models; using BotSharp.Abstraction.Routing.Models;
using System.IO; using System.IO;
using System.Threading;
namespace BotSharp.Core.Repository namespace BotSharp.Core.Repository
{ {
@ -37,7 +37,7 @@ namespace BotSharp.Core.Repository
UpdateAgentRoutingRules(agent.Id, agent.RoutingRules); UpdateAgentRoutingRules(agent.Id, agent.RoutingRules);
break; break;
case AgentField.Instruction: case AgentField.Instruction:
UpdateAgentInstruction(agent.Id, agent.Instruction); UpdateAgentInstructions(agent.Id, agent.Instruction, agent.ChannelInstructions);
break; break;
case AgentField.Function: case AgentField.Function:
UpdateAgentFunctions(agent.Id, agent.Functions); UpdateAgentFunctions(agent.Id, agent.Functions);
@ -175,17 +175,30 @@ namespace BotSharp.Core.Repository
File.WriteAllText(agentFile, json); File.WriteAllText(agentFile, json);
} }
private void UpdateAgentInstruction(string agentId, string instruction) private void UpdateAgentInstructions(string agentId, string instruction, List<ChannelInstruction> channelInstructions)
{ {
if (string.IsNullOrWhiteSpace(instruction)) return; if (string.IsNullOrWhiteSpace(instruction)) return;
var (agent, agentFile) = GetAgentFromFile(agentId); var (agent, agentFile) = GetAgentFromFile(agentId);
if (agent == null) return; if (agent == null) return;
var instructionFile = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, var instructionDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId, AGENT_INSTRUCTIONS_FOLDER);
agentId, $"{AGENT_INSTRUCTION_FILE}.{_agentSettings.TemplateFormat}"); DeleteBeforeCreateDirectory(instructionDir);
File.WriteAllText(instructionFile, instruction); // Save default instructions
var instructionFile = Path.Combine(instructionDir, $"{AGENT_INSTRUCTION_FILE}.{_agentSettings.TemplateFormat}");
File.WriteAllText(instructionFile, instruction ?? string.Empty);
Thread.Sleep(100);
// Save channel instructions
foreach (var ci in channelInstructions)
{
if (string.IsNullOrWhiteSpace(ci.Channel)) continue;
var file = Path.Combine(instructionDir, $"{AGENT_INSTRUCTION_FILE}.{ci.Channel}.{_agentSettings.TemplateFormat}");
File.WriteAllText(file, ci.Instruction ?? string.Empty);
Thread.Sleep(100);
}
} }
private void UpdateAgentFunctions(string agentId, List<FunctionDef> inputFunctions) private void UpdateAgentFunctions(string agentId, List<FunctionDef> inputFunctions)
@ -195,14 +208,8 @@ namespace BotSharp.Core.Repository
var (agent, agentFile) = GetAgentFromFile(agentId); var (agent, agentFile) = GetAgentFromFile(agentId);
if (agent == null) return; if (agent == null) return;
var functionDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, var functionDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId, AGENT_FUNCTIONS_FOLDER);
agentId, AGENT_FUNCTIONS_FOLDER); DeleteBeforeCreateDirectory(functionDir);
if (Directory.Exists(functionDir))
{
Directory.Delete(functionDir, true);
}
Directory.CreateDirectory(functionDir);
foreach (var func in inputFunctions) foreach (var func in inputFunctions)
{ {
@ -211,7 +218,7 @@ namespace BotSharp.Core.Repository
var text = JsonSerializer.Serialize(func, _options); var text = JsonSerializer.Serialize(func, _options);
var file = Path.Combine(functionDir, $"{func.Name}.json"); var file = Path.Combine(functionDir, $"{func.Name}.json");
File.WriteAllText(file, text); File.WriteAllText(file, text);
Thread.Sleep(200); Thread.Sleep(100);
} }
} }
@ -223,16 +230,7 @@ namespace BotSharp.Core.Repository
if (agent == null) return; if (agent == null) return;
var templateDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId, AGENT_TEMPLATES_FOLDER); var templateDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId, AGENT_TEMPLATES_FOLDER);
DeleteBeforeCreateDirectory(templateDir);
if (!Directory.Exists(templateDir))
{
Directory.CreateDirectory(templateDir);
}
foreach (var file in Directory.GetFiles(templateDir))
{
File.Delete(file);
}
foreach (var template in templates) foreach (var template in templates)
{ {
@ -249,15 +247,7 @@ namespace BotSharp.Core.Repository
if (agent == null) return; if (agent == null) return;
var responseDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId, AGENT_RESPONSES_FOLDER); var responseDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId, AGENT_RESPONSES_FOLDER);
if (!Directory.Exists(responseDir)) DeleteBeforeCreateDirectory(responseDir);
{
Directory.CreateDirectory(responseDir);
}
foreach (var file in Directory.GetFiles(responseDir))
{
File.Delete(file);
}
for (int i = 0; i < responses.Count; i++) for (int i = 0; i < responses.Count; i++)
{ {
@ -308,7 +298,7 @@ namespace BotSharp.Core.Repository
var json = JsonSerializer.Serialize(agent, _options); var json = JsonSerializer.Serialize(agent, _options);
File.WriteAllText(agentFile, json); File.WriteAllText(agentFile, json);
UpdateAgentInstruction(inputAgent.Id, inputAgent.Instruction); UpdateAgentInstructions(inputAgent.Id, inputAgent.Instruction, agent.ChannelInstructions);
UpdateAgentResponses(inputAgent.Id, inputAgent.Responses); UpdateAgentResponses(inputAgent.Id, inputAgent.Responses);
UpdateAgentTemplates(inputAgent.Id, inputAgent.Templates); UpdateAgentTemplates(inputAgent.Id, inputAgent.Templates);
UpdateAgentFunctions(inputAgent.Id, inputAgent.Functions); UpdateAgentFunctions(inputAgent.Id, inputAgent.Functions);
@ -348,12 +338,13 @@ namespace BotSharp.Core.Repository
var record = JsonSerializer.Deserialize<Agent>(json, _options); var record = JsonSerializer.Deserialize<Agent>(json, _options);
if (record == null) return null; if (record == null) return null;
var instruction = FetchInstruction(dir); var (defaultInstruction, channelInstructions) = FetchInstructions(dir);
var functions = FetchFunctions(dir); var functions = FetchFunctions(dir);
var samples = FetchSamples(dir); var samples = FetchSamples(dir);
var templates = FetchTemplates(dir); var templates = FetchTemplates(dir);
var responses = FetchResponses(dir); var responses = FetchResponses(dir);
return record.SetInstruction(instruction) return record.SetInstruction(defaultInstruction)
.SetChannelInstructions(channelInstructions)
.SetFunctions(functions) .SetFunctions(functions)
.SetTemplates(templates) .SetTemplates(templates)
.SetSamples(samples) .SetSamples(samples)
@ -451,13 +442,9 @@ namespace BotSharp.Core.Repository
return true; return true;
} }
public void BulkInsertAgents(List<Agent> agents) public void BulkInsertAgents(List<Agent> agents) { }
{
}
public void BulkInsertUserAgents(List<UserAgent> userAgents) public void BulkInsertUserAgents(List<UserAgent> userAgents) { }
{
}
public bool DeleteAgents() public bool DeleteAgents()
{ {

View file

@ -34,6 +34,7 @@ public partial class FileRepository : IBotSharpRepository
private const string AGENT_TASK_PREFIX = "#metadata"; private const string AGENT_TASK_PREFIX = "#metadata";
private const string AGENT_TASK_SUFFIX = "/metadata"; private const string AGENT_TASK_SUFFIX = "/metadata";
private const string TRANSLATION_MEMORY_FILE = "memory.json"; private const string TRANSLATION_MEMORY_FILE = "memory.json";
private const string AGENT_INSTRUCTIONS_FOLDER = "instructions";
private const string AGENT_FUNCTIONS_FOLDER = "functions"; private const string AGENT_FUNCTIONS_FOLDER = "functions";
private const string AGENT_TEMPLATES_FOLDER = "templates"; private const string AGENT_TEMPLATES_FOLDER = "templates";
private const string AGENT_RESPONSES_FOLDER = "responses"; private const string AGENT_RESPONSES_FOLDER = "responses";
@ -123,7 +124,9 @@ public partial class FileRepository : IBotSharpRepository
var agent = JsonSerializer.Deserialize<Agent>(json, _options); var agent = JsonSerializer.Deserialize<Agent>(json, _options);
if (agent != null) if (agent != null)
{ {
agent = agent.SetInstruction(FetchInstruction(d)) var (defaultInstruction, channelInstructions) = FetchInstructions(d);
agent = agent.SetInstruction(defaultInstruction)
.SetChannelInstructions(channelInstructions)
.SetFunctions(FetchFunctions(d)) .SetFunctions(FetchFunctions(d))
.SetTemplates(FetchTemplates(d)) .SetTemplates(FetchTemplates(d))
.SetResponses(FetchResponses(d)) .SetResponses(FetchResponses(d))
@ -165,6 +168,17 @@ public partial class FileRepository : IBotSharpRepository
#region Private methods #region Private methods
private void DeleteBeforeCreateDirectory(string dir)
{
if (string.IsNullOrWhiteSpace(dir)) return;
if (Directory.Exists(dir))
{
Directory.Delete(dir, true);
}
Directory.CreateDirectory(dir);
}
private string GetAgentDataDir(string agentId) private string GetAgentDataDir(string agentId)
{ {
var dir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId); var dir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId);
@ -186,13 +200,46 @@ public partial class FileRepository : IBotSharpRepository
return (agent, agentFile); return (agent, agentFile);
} }
private string? FetchInstruction(string fileDir) private (string, List<ChannelInstruction>) FetchInstructions(string fileDir)
{ {
var file = Path.Combine(fileDir, $"{AGENT_INSTRUCTION_FILE}.{_agentSettings.TemplateFormat}"); var defaultInstruction = string.Empty;
if (!File.Exists(file)) return null; var channelInstructions = new List<ChannelInstruction>();
var instruction = File.ReadAllText(file); var instructionDir = Path.Combine(fileDir, AGENT_INSTRUCTIONS_FOLDER);
return instruction; if (!Directory.Exists(instructionDir))
{
return (defaultInstruction, channelInstructions);
}
foreach (var file in Directory.GetFiles(instructionDir))
{
var extension = Path.GetExtension(file).Substring(1);
if (!extension.IsEqualTo(_agentSettings.TemplateFormat))
{
continue;
}
var segments = Path.GetFileName(file).Split(".", StringSplitOptions.RemoveEmptyEntries);
if (segments.IsNullOrEmpty() || !segments[0].IsEqualTo(AGENT_INSTRUCTION_FILE))
{
continue;
}
if (segments.Length == 2)
{
defaultInstruction = File.ReadAllText(file);
}
else if (segments.Length == 3)
{
var item = new ChannelInstruction
{
Channel = segments[1],
Instruction = File.ReadAllText(file)
};
channelInstructions.Add(item);
}
}
return (defaultInstruction, channelInstructions);
} }
private List<FunctionDef> FetchFunctions(string fileDir) private List<FunctionDef> FetchFunctions(string fileDir)
@ -298,13 +345,14 @@ public partial class FileRepository : IBotSharpRepository
var agent = JsonSerializer.Deserialize<Agent>(agentJson, _options); var agent = JsonSerializer.Deserialize<Agent>(agentJson, _options);
if (agent == null) return null; if (agent == null) return null;
var instruction = FetchInstruction(agentDir); var (defaultInstruction, channelInstructions) = FetchInstructions(agentDir);
var functions = FetchFunctions(agentDir); var functions = FetchFunctions(agentDir);
var samples = FetchSamples(agentDir); var samples = FetchSamples(agentDir);
var templates = FetchTemplates(agentDir); var templates = FetchTemplates(agentDir);
var responses = FetchResponses(agentDir); var responses = FetchResponses(agentDir);
return agent.SetInstruction(instruction) return agent.SetInstruction(defaultInstruction)
.SetChannelInstructions(channelInstructions)
.SetFunctions(functions) .SetFunctions(functions)
.SetTemplates(templates) .SetTemplates(templates)
.SetSamples(samples) .SetSamples(samples)

View file

@ -1,4 +1,3 @@
using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Users.Enums; using BotSharp.Abstraction.Users.Enums;
namespace BotSharp.OpenAPI.Controllers; namespace BotSharp.OpenAPI.Controllers;
@ -28,13 +27,18 @@ public class AgentController : ControllerBase
[HttpGet("/agent/{id}")] [HttpGet("/agent/{id}")]
public async Task<AgentViewModel?> GetAgent([FromRoute] string id) public async Task<AgentViewModel?> GetAgent([FromRoute] string id)
{ {
var agents = await GetAgents(new AgentFilter var pagedAgents = await _agentService.GetAgents(new AgentFilter
{ {
AgentIds = new List<string> { id } AgentIds = new List<string> { id }
}, useHook: true); });
var targetAgent = agents.Items.FirstOrDefault(); var foundAgent = pagedAgents.Items.FirstOrDefault();
if (targetAgent == null) return null; if (foundAgent == null) return null;
await _agentService.InheritAgent(foundAgent);
var targetAgent = AgentViewModel.FromAgent(foundAgent);
var agentSetting = _services.GetRequiredService<AgentSettings>();
targetAgent.IsHost = targetAgent.Id == agentSetting.HostAgentId;
var redirectAgentIds = targetAgent.RoutingRules var redirectAgentIds = targetAgent.RoutingRules
.Where(x => !string.IsNullOrEmpty(x.RedirectTo)) .Where(x => !string.IsNullOrEmpty(x.RedirectTo))
@ -65,39 +69,16 @@ public class AgentController : ControllerBase
} }
[HttpGet("/agents")] [HttpGet("/agents")]
public async Task<PagedItems<AgentViewModel>> GetAgents([FromQuery] AgentFilter filter, [FromQuery] bool useHook = false) public async Task<PagedItems<AgentViewModel>> GetAgents([FromQuery] AgentFilter filter)
{ {
var agentSetting = _services.GetRequiredService<AgentSettings>(); var agentSetting = _services.GetRequiredService<AgentSettings>();
var pagedAgents = await _agentService.GetAgents(filter); var pagedAgents = await _agentService.GetAgents(filter);
var agents = pagedAgents?.Items?.Select(x => AgentViewModel.FromAgent(x))?.ToList() ?? new List<AgentViewModel>();
var items = new List<Agent>();
var agents = new List<AgentViewModel>();
if (useHook)
{
// prerender agent
foreach (var agent in pagedAgents.Items)
{
var renderedAgent = await _agentService.LoadAgent(agent.Id);
items.Add(renderedAgent);
}
// Set IsHost
agents = items.Select(x => AgentViewModel.FromAgent(x)).ToList();
foreach (var agent in agents)
{
agent.IsHost = agentSetting.HostAgentId == agent.Id;
}
}
else
{
items = pagedAgents.Items.ToList();
agents = items.Select(x => AgentViewModel.FromAgent(x)).ToList();
}
return new PagedItems<AgentViewModel> return new PagedItems<AgentViewModel>
{ {
Items = agents, Items = agents,
Count = pagedAgents.Count Count = pagedAgents?.Count ?? 0
}; };
} }

View file

@ -1,7 +1,6 @@
using BotSharp.Abstraction.Agents.Models; using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Functions.Models; using BotSharp.Abstraction.Functions.Models;
using BotSharp.Abstraction.Routing.Models; using BotSharp.Abstraction.Routing.Models;
using BotSharp.Core.Infrastructures;
namespace BotSharp.OpenAPI.ViewModels.Agents; namespace BotSharp.OpenAPI.ViewModels.Agents;
@ -16,21 +15,26 @@ public class AgentCreationModel
/// </summary> /// </summary>
public string Instruction { get; set; } = string.Empty; public string Instruction { get; set; } = string.Empty;
/// <summary>
///
/// </summary>
public List<ChannelInstruction> ChannelInstructions { get; set; } = new();
/// <summary> /// <summary>
/// LLM extensible Instructions in addition to the default Instructions /// LLM extensible Instructions in addition to the default Instructions
/// </summary> /// </summary>
public List<AgentTemplate> Templates { get; set; } = new List<AgentTemplate>(); public List<AgentTemplate> Templates { get; set; } = new();
/// <summary> /// <summary>
/// LLM callable function definition /// LLM callable function definition
/// </summary> /// </summary>
public List<FunctionDef> Functions { get; set; } = new List<FunctionDef>(); public List<FunctionDef> Functions { get; set; } = new();
/// <summary> /// <summary>
/// Response template /// Response template
/// </summary> /// </summary>
public List<AgentResponse> Responses { get; set; } = new List<AgentResponse>(); public List<AgentResponse> Responses { get; set; } = new();
public List<string> Samples { get; set; } = new List<string>(); public List<string> Samples { get; set; } = new();
public bool IsPublic { get; set; } public bool IsPublic { get; set; }
@ -43,9 +47,9 @@ public class AgentCreationModel
/// <summary> /// <summary>
/// Combine different Agents together to form a Profile. /// Combine different Agents together to form a Profile.
/// </summary> /// </summary>
public List<string> Profiles { get; set; } = new List<string>(); public List<string> Profiles { get; set; } = new();
public List<string> Utilities { get; set; } = new List<string>(); public List<string> Utilities { get; set; } = new();
public List<RoutingRuleUpdateModel> RoutingRules { get; set; } = new List<RoutingRuleUpdateModel>(); public List<RoutingRuleUpdateModel> RoutingRules { get; set; } = new();
public AgentLlmConfig? LlmConfig { get; set; } public AgentLlmConfig? LlmConfig { get; set; }
public Agent ToAgent() public Agent ToAgent()
@ -55,6 +59,7 @@ public class AgentCreationModel
Name = Name, Name = Name,
Description = Description, Description = Description,
Instruction = Instruction, Instruction = Instruction,
ChannelInstructions = ChannelInstructions,
Templates = Templates, Templates = Templates,
Functions = Functions, Functions = Functions,
Responses = Responses, Responses = Responses,
@ -64,9 +69,7 @@ public class AgentCreationModel
Type = Type, Type = Type,
Disabled = Disabled, Disabled = Disabled,
Profiles = Profiles, Profiles = Profiles,
RoutingRules = RoutingRules? RoutingRules = RoutingRules?.Select(x => RoutingRuleUpdateModel.ToDomainElement(x))?.ToList() ?? new List<RoutingRule>(),
.Select(x => RoutingRuleUpdateModel.ToDomainElement(x))?
.ToList() ?? new List<RoutingRule>(),
LlmConfig = LlmConfig LlmConfig = LlmConfig
}; };
} }

View file

@ -15,6 +15,12 @@ public class AgentUpdateModel
/// </summary> /// </summary>
public string Instruction { get; set; } = string.Empty; public string Instruction { get; set; } = string.Empty;
/// <summary>
/// Channel instructions
/// </summary>
[JsonPropertyName("channel_instructions")]
public List<ChannelInstruction>? ChannelInstructions { get; set; }
/// <summary> /// <summary>
/// Templates /// Templates
/// </summary> /// </summary>
@ -39,11 +45,11 @@ public class AgentUpdateModel
/// Routes /// Routes
/// </summary> /// </summary>
public List<AgentResponse>? Responses { get; set; } public List<AgentResponse>? Responses { get; set; }
[JsonPropertyName("is_public")] [JsonPropertyName("is_public")]
public bool IsPublic { get; set; } public bool IsPublic { get; set; }
[JsonPropertyName("allow_routing")]
[JsonPropertyName("allow_routing")]
public bool AllowRouting { get; set; } public bool AllowRouting { get; set; }
public bool Disabled { get; set; } public bool Disabled { get; set; }
@ -52,8 +58,8 @@ public class AgentUpdateModel
/// Profile by channel /// Profile by channel
/// </summary> /// </summary>
public List<string>? Profiles { get; set; } public List<string>? Profiles { get; set; }
[JsonPropertyName("routing_rules")]
[JsonPropertyName("routing_rules")]
public List<RoutingRuleUpdateModel>? RoutingRules { get; set; } public List<RoutingRuleUpdateModel>? RoutingRules { get; set; }
[JsonPropertyName("llm_config")] [JsonPropertyName("llm_config")]
@ -69,10 +75,9 @@ public class AgentUpdateModel
Disabled = Disabled, Disabled = Disabled,
Type = Type, Type = Type,
Profiles = Profiles ?? new List<string>(), Profiles = Profiles ?? new List<string>(),
RoutingRules = RoutingRules? RoutingRules = RoutingRules?.Select(x => RoutingRuleUpdateModel.ToDomainElement(x))?.ToList() ?? new List<RoutingRule>(),
.Select(x => RoutingRuleUpdateModel.ToDomainElement(x))?
.ToList() ?? new List<RoutingRule>(),
Instruction = Instruction ?? string.Empty, Instruction = Instruction ?? string.Empty,
ChannelInstructions = ChannelInstructions ?? new List<ChannelInstruction>(),
Templates = Templates ?? new List<AgentTemplate>(), Templates = Templates ?? new List<AgentTemplate>(),
Functions = Functions ?? new List<FunctionDef>(), Functions = Functions ?? new List<FunctionDef>(),
Responses = Responses ?? new List<AgentResponse>(), Responses = Responses ?? new List<AgentResponse>(),

View file

@ -13,6 +13,7 @@ public class AgentViewModel
public string Description { get; set; } public string Description { get; set; }
public string Type { get; set; } = AgentType.Task; public string Type { get; set; } = AgentType.Task;
public string Instruction { get; set; } public string Instruction { get; set; }
public List<ChannelInstruction> ChannelInstructions { get; set; }
public List<AgentTemplate> Templates { get; set; } public List<AgentTemplate> Templates { get; set; }
public List<FunctionDef> Functions { get; set; } public List<FunctionDef> Functions { get; set; }
public List<AgentResponse> Responses { get; set; } public List<AgentResponse> Responses { get; set; }
@ -60,6 +61,7 @@ public class AgentViewModel
Description = agent.Description, Description = agent.Description,
Type = agent.Type, Type = agent.Type,
Instruction = agent.Instruction, Instruction = agent.Instruction,
ChannelInstructions = agent.ChannelInstructions,
Templates = agent.Templates, Templates = agent.Templates,
Functions = agent.Functions, Functions = agent.Functions,
Responses = agent.Responses, Responses = agent.Responses,

View file

@ -8,6 +8,7 @@ public class AgentDocument : MongoBase
public string? InheritAgentId { get; set; } public string? InheritAgentId { get; set; }
public string? IconUrl { get; set; } public string? IconUrl { get; set; }
public string Instruction { get; set; } public string Instruction { get; set; }
public List<ChannelInstructionMongoElement> ChannelInstructions { get; set; }
public List<AgentTemplateMongoElement> Templates { get; set; } public List<AgentTemplateMongoElement> Templates { get; set; }
public List<FunctionDefMongoElement> Functions { get; set; } public List<FunctionDefMongoElement> Functions { get; set; }
public List<AgentResponseMongoElement> Responses { get; set; } public List<AgentResponseMongoElement> Responses { get; set; }

View file

@ -0,0 +1,27 @@
using BotSharp.Abstraction.Agents.Models;
namespace BotSharp.Plugin.MongoStorage.Models;
public class ChannelInstructionMongoElement
{
public string Channel { get; set; }
public string Instruction { get; set; }
public static ChannelInstructionMongoElement ToMongoElement(ChannelInstruction instruction)
{
return new ChannelInstructionMongoElement
{
Channel = instruction.Channel,
Instruction = instruction.Instruction
};
}
public static ChannelInstruction ToDomainElement(ChannelInstructionMongoElement instruction)
{
return new ChannelInstruction
{
Channel = instruction.Channel,
Instruction = instruction.Instruction
};
}
}

View file

@ -38,7 +38,7 @@ public partial class MongoRepository
UpdateAgentRoutingRules(agent.Id, agent.RoutingRules); UpdateAgentRoutingRules(agent.Id, agent.RoutingRules);
break; break;
case AgentField.Instruction: case AgentField.Instruction:
UpdateAgentInstruction(agent.Id, agent.Instruction); UpdateAgentInstructions(agent.Id, agent.Instruction, agent.ChannelInstructions);
break; break;
case AgentField.Function: case AgentField.Function:
UpdateAgentFunctions(agent.Id, agent.Functions); UpdateAgentFunctions(agent.Id, agent.Functions);
@ -156,13 +156,17 @@ public partial class MongoRepository
_dc.Agents.UpdateOne(filter, update); _dc.Agents.UpdateOne(filter, update);
} }
private void UpdateAgentInstruction(string agentId, string instruction) private void UpdateAgentInstructions(string agentId, string instruction, List<ChannelInstruction>? channelInstructions)
{ {
if (string.IsNullOrWhiteSpace(instruction)) return; if (string.IsNullOrWhiteSpace(agentId)) return;
var instructionElements = channelInstructions?.Select(x => ChannelInstructionMongoElement.ToMongoElement(x))?
.ToList() ?? new List<ChannelInstructionMongoElement>();
var filter = Builders<AgentDocument>.Filter.Eq(x => x.Id, agentId); var filter = Builders<AgentDocument>.Filter.Eq(x => x.Id, agentId);
var update = Builders<AgentDocument>.Update var update = Builders<AgentDocument>.Update
.Set(x => x.Instruction, instruction) .Set(x => x.Instruction, instruction)
.Set(x => x.ChannelInstructions, instructionElements)
.Set(x => x.UpdatedTime, DateTime.UtcNow); .Set(x => x.UpdatedTime, DateTime.UtcNow);
_dc.Agents.UpdateOne(filter, update); _dc.Agents.UpdateOne(filter, update);
@ -253,6 +257,7 @@ public partial class MongoRepository
.Set(x => x.Profiles, agent.Profiles) .Set(x => x.Profiles, agent.Profiles)
.Set(x => x.RoutingRules, agent.RoutingRules.Select(r => RoutingRuleMongoElement.ToMongoElement(r)).ToList()) .Set(x => x.RoutingRules, agent.RoutingRules.Select(r => RoutingRuleMongoElement.ToMongoElement(r)).ToList())
.Set(x => x.Instruction, agent.Instruction) .Set(x => x.Instruction, agent.Instruction)
.Set(x => x.ChannelInstructions, agent.ChannelInstructions.Select(i => ChannelInstructionMongoElement.ToMongoElement(i)).ToList())
.Set(x => x.Templates, agent.Templates.Select(t => AgentTemplateMongoElement.ToMongoElement(t)).ToList()) .Set(x => x.Templates, agent.Templates.Select(t => AgentTemplateMongoElement.ToMongoElement(t)).ToList())
.Set(x => x.Functions, agent.Functions.Select(f => FunctionDefMongoElement.ToMongoElement(f)).ToList()) .Set(x => x.Functions, agent.Functions.Select(f => FunctionDefMongoElement.ToMongoElement(f)).ToList())
.Set(x => x.Responses, agent.Responses.Select(r => AgentResponseMongoElement.ToMongoElement(r)).ToList()) .Set(x => x.Responses, agent.Responses.Select(r => AgentResponseMongoElement.ToMongoElement(r)).ToList())
@ -373,6 +378,9 @@ public partial class MongoRepository
IconUrl = x.IconUrl, IconUrl = x.IconUrl,
Description = x.Description, Description = x.Description,
Instruction = x.Instruction, Instruction = x.Instruction,
ChannelInstructions = x.ChannelInstructions?
.Select(i => ChannelInstructionMongoElement.ToMongoElement(i))?
.ToList() ?? new List<ChannelInstructionMongoElement>(),
Templates = x.Templates? Templates = x.Templates?
.Select(t => AgentTemplateMongoElement.ToMongoElement(t))? .Select(t => AgentTemplateMongoElement.ToMongoElement(t))?
.ToList() ?? new List<AgentTemplateMongoElement>(), .ToList() ?? new List<AgentTemplateMongoElement>(),
@ -463,6 +471,9 @@ public partial class MongoRepository
IconUrl = agentDoc.IconUrl, IconUrl = agentDoc.IconUrl,
Description = agentDoc.Description, Description = agentDoc.Description,
Instruction = agentDoc.Instruction, Instruction = agentDoc.Instruction,
ChannelInstructions = !agentDoc.ChannelInstructions.IsNullOrEmpty() ? agentDoc.ChannelInstructions
.Select(i => ChannelInstructionMongoElement.ToDomainElement(i))
.ToList() : new List<ChannelInstruction>(),
Templates = !agentDoc.Templates.IsNullOrEmpty() ? agentDoc.Templates Templates = !agentDoc.Templates.IsNullOrEmpty() ? agentDoc.Templates
.Select(t => AgentTemplateMongoElement.ToDomainElement(t)) .Select(t => AgentTemplateMongoElement.ToDomainElement(t))
.ToList() : new List<AgentTemplate>(), .ToList() : new List<AgentTemplate>(),
@ -472,6 +483,10 @@ public partial class MongoRepository
Responses = !agentDoc.Responses.IsNullOrEmpty() ? agentDoc.Responses Responses = !agentDoc.Responses.IsNullOrEmpty() ? agentDoc.Responses
.Select(r => AgentResponseMongoElement.ToDomainElement(r)) .Select(r => AgentResponseMongoElement.ToDomainElement(r))
.ToList() : new List<AgentResponse>(), .ToList() : new List<AgentResponse>(),
RoutingRules = !agentDoc.RoutingRules.IsNullOrEmpty() ? agentDoc.RoutingRules
.Select(r => RoutingRuleMongoElement.ToDomainElement(agentDoc.Id, agentDoc.Name, r))
.ToList() : new List<RoutingRule>(),
LlmConfig = AgentLlmConfigMongoElement.ToDomainElement(agentDoc.LlmConfig),
Samples = agentDoc.Samples ?? new List<string>(), Samples = agentDoc.Samples ?? new List<string>(),
Utilities = agentDoc.Utilities ?? new List<string>(), Utilities = agentDoc.Utilities ?? new List<string>(),
IsPublic = agentDoc.IsPublic, IsPublic = agentDoc.IsPublic,
@ -479,10 +494,6 @@ public partial class MongoRepository
Type = agentDoc.Type, Type = agentDoc.Type,
InheritAgentId = agentDoc.InheritAgentId, InheritAgentId = agentDoc.InheritAgentId,
Profiles = agentDoc.Profiles, Profiles = agentDoc.Profiles,
RoutingRules = !agentDoc.RoutingRules.IsNullOrEmpty() ? agentDoc.RoutingRules
.Select(r => RoutingRuleMongoElement.ToDomainElement(agentDoc.Id, agentDoc.Name, r))
.ToList() : new List<RoutingRule>(),
LlmConfig = AgentLlmConfigMongoElement.ToDomainElement(agentDoc.LlmConfig)
}; };
} }
} }

View file

@ -37,9 +37,12 @@ public partial class MongoRepository
{ {
Id = !string.IsNullOrEmpty(x.Id) ? x.Id : Guid.NewGuid().ToString(), Id = !string.IsNullOrEmpty(x.Id) ? x.Id : Guid.NewGuid().ToString(),
Name = x.Name, Name = x.Name,
IconUrl = x.IconUrl,
Description = x.Description, Description = x.Description,
Instruction = x.Instruction, Instruction = x.Instruction,
IconUrl = x.IconUrl, ChannelInstructions = x.ChannelInstructions?
.Select(i => ChannelInstructionMongoElement.ToMongoElement(i))?
.ToList() ?? new List<ChannelInstructionMongoElement>(),
Templates = x.Templates? Templates = x.Templates?
.Select(t => AgentTemplateMongoElement.ToMongoElement(t))? .Select(t => AgentTemplateMongoElement.ToMongoElement(t))?
.ToList() ?? new List<AgentTemplateMongoElement>(), .ToList() ?? new List<AgentTemplateMongoElement>(),
@ -71,6 +74,7 @@ public partial class MongoRepository
.Set(x => x.Name, agent.Name) .Set(x => x.Name, agent.Name)
.Set(x => x.Description, agent.Description) .Set(x => x.Description, agent.Description)
.Set(x => x.Instruction, agent.Instruction) .Set(x => x.Instruction, agent.Instruction)
.Set(x => x.ChannelInstructions, agent.ChannelInstructions)
.Set(x => x.Templates, agent.Templates) .Set(x => x.Templates, agent.Templates)
.Set(x => x.Functions, agent.Functions) .Set(x => x.Functions, agent.Functions)
.Set(x => x.Responses, agent.Responses) .Set(x => x.Responses, agent.Responses)