diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs
index 7a06cce1d..1f7283fc8 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs
@@ -53,7 +53,8 @@ public interface IAgentService
///
/// Original agent information
Task GetAgent(string id);
-
+ Task GetAgentTemplateDetail(string agentId, string templateName);
+
Task DeleteAgent(string id, AgentDeleteOptions? options = null);
Task UpdateAgent(Agent agent, AgentField updateField);
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentTemplate.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentTemplate.cs
index 2eb3b4a02..a39be67ab 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentTemplate.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentTemplate.cs
@@ -1,9 +1,8 @@
namespace BotSharp.Abstraction.Agents.Models;
-public class AgentTemplate
+public class AgentTemplate : AgentTemplateConfig
{
- public string Name { get; set; }
- public string Content { get; set; }
+ public string Content { get; set; } = string.Empty;
public AgentTemplate()
{
@@ -20,3 +19,23 @@ public override string ToString()
return Name;
}
}
+
+public class AgentTemplateConfig
+{
+ public string Name { get; set; }
+
+ ///
+ /// Response format: json, xml, markdown, yaml, etc.
+ ///
+ [JsonPropertyName("response_format")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? ResponseFormat { get; set; }
+
+ [JsonPropertyName("llm_config")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public AgentTemplateLlmConfig? LlmConfig { get; set; }
+}
+
+public class AgentTemplateLlmConfig : LlmConfigBase
+{
+}
\ No newline at end of file
diff --git a/src/Infrastructure/BotSharp.Abstraction/Models/LlmConfigBase.cs b/src/Infrastructure/BotSharp.Abstraction/Models/LlmConfigBase.cs
index 899f6e7ab..20c66b0a3 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Models/LlmConfigBase.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Models/LlmConfigBase.cs
@@ -5,11 +5,15 @@ public class LlmConfigBase : LlmProviderModel
///
/// Llm maximum output tokens
///
+ [JsonPropertyName("max_output_tokens")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public int? MaxOutputTokens { get; set; }
///
- /// Llm reasoning effort level
+ /// Llm reasoning effort level, thinking level
///
+ [JsonPropertyName("reasoning_effort_level")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? ReasoningEffortLevel { get; set; }
}
@@ -22,4 +26,7 @@ public class LlmProviderModel
[JsonPropertyName("model")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? Model { get; set; }
+
+ [JsonIgnore]
+ public bool IsValid => !string.IsNullOrEmpty(Provider) && !string.IsNullOrEmpty(Model);
}
\ No newline at end of file
diff --git a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs
index 437e6cdd7..cb44f9340 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs
@@ -88,6 +88,8 @@ Task> GetAgentResponses(string agentId, string prefix, string inten
=> throw new NotImplementedException();
Task GetAgentTemplate(string agentId, string templateName)
=> throw new NotImplementedException();
+ Task GetAgentTemplateDetail(string agentId, string templateName)
+ => throw new NotImplementedException();
Task PatchAgentTemplate(string agentId, AgentTemplate template)
=> throw new NotImplementedException();
Task UpdateAgentLabels(string agentId, List labels)
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs
index 334e385b9..b2d056b6b 100644
--- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs
+++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs
@@ -30,7 +30,7 @@ public async Task CreateAgent(Agent agent)
var userService = _services.GetRequiredService();
var auth = await userService.GetUserAuthorizations();
- await _db.BulkInsertAgents(new List { agentRecord });
+ await _db.BulkInsertAgents([agentRecord]);
if (auth.IsAdmin || auth.Permissions.Contains(UserPermission.CreateAgent))
{
await _db.BulkInsertUserAgents(new List
@@ -39,7 +39,7 @@ await _db.BulkInsertUserAgents(new List
{
UserId = user.Id,
AgentId = agentRecord.Id,
- Actions = new List { UserAction.Edit, UserAction.Train, UserAction.Evaluate, UserAction.Chat },
+ Actions = [UserAction.Edit, UserAction.Train, UserAction.Evaluate, UserAction.Chat],
CreatedTime = DateTime.UtcNow,
UpdatedTime = DateTime.UtcNow
}
@@ -98,6 +98,9 @@ private List GetTemplatesFromFile(string fileDir)
var templateDir = Path.Combine(fileDir, "templates");
if (!Directory.Exists(templateDir)) return templates;
+ // Load template configs
+ var configs = GetAgentTemplateConfigs(fileDir);
+
foreach (var file in Directory.GetFiles(templateDir))
{
var extension = Path.GetExtension(file).Substring(1);
@@ -105,13 +108,41 @@ private List GetTemplatesFromFile(string fileDir)
{
var name = Path.GetFileNameWithoutExtension(file);
var content = File.ReadAllText(file);
- templates.Add(new AgentTemplate(name, content));
+ var template = new AgentTemplate(name, content);
+ var config = configs.FirstOrDefault(x => x.Name.IsEqualTo(name));
+ if (config != null)
+ {
+ template.ResponseFormat = config.ResponseFormat;
+ template.LlmConfig = config.LlmConfig;
+ }
+ templates.Add(template);
}
}
-
+
return templates;
}
+ private IEnumerable GetAgentTemplateConfigs(string baseDir)
+ {
+ var configFile = Path.Combine(baseDir, "template_configs.json");
+ var configs = new List();
+
+ try
+ {
+ if (File.Exists(configFile))
+ {
+ var configJson = File.ReadAllText(configFile);
+ configs = JsonSerializer.Deserialize>(configJson, _options.JsonSerializerOptions) ?? [];
+ }
+ return configs;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error when loading template configs in {configFile}", configFile);
+ return configs;
+ }
+ }
+
private List GetFunctionsFromFile(string fileDir)
{
var functions = new List();
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs
index 800a393c3..955c9b2b3 100644
--- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs
+++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs
@@ -105,6 +105,36 @@ private void AddDefaultInstruction(Agent agent, string instruction)
agent.ChannelInstructions = instructions;
}
+#if !DEBUG
+ [SharpCache(10, perInstanceCache: true)]
+#endif
+ public async Task GetAgentTemplateDetail(string agentId, string templateName)
+ {
+ var template = await _db.GetAgentTemplateDetail(agentId, templateName);
+ if (template == null)
+ {
+ return template;
+ }
+
+ if (template.LlmConfig == null)
+ {
+ var agent = await _db.GetAgent(agentId);
+ if (!string.IsNullOrEmpty(agent?.LlmConfig?.Provider)
+ && !string.IsNullOrEmpty(agent?.LlmConfig?.Model))
+ {
+ template.LlmConfig = new AgentTemplateLlmConfig
+ {
+ Provider = agent.LlmConfig.Provider,
+ Model = agent.LlmConfig.Model,
+ MaxOutputTokens = agent.LlmConfig.MaxOutputTokens,
+ ReasoningEffortLevel = agent.LlmConfig.ReasoningEffortLevel
+ };
+ }
+ }
+
+ return template.DeepClone();
+ }
+
public async Task InheritAgent(Agent agent)
{
if (string.IsNullOrWhiteSpace(agent?.InheritAgentId))
diff --git a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj
index 7aa3a42dd..e56d01eec 100644
--- a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj
+++ b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj
@@ -68,6 +68,7 @@
+
@@ -131,6 +132,9 @@
PreserveNewest
+
+ PreserveNewest
+
PreserveNewest
diff --git a/src/Infrastructure/BotSharp.Core/Instructs/Services/InstructService.Execute.cs b/src/Infrastructure/BotSharp.Core/Instructs/Services/InstructService.Execute.cs
index 6995b49ec..29fa0724b 100644
--- a/src/Infrastructure/BotSharp.Core/Instructs/Services/InstructService.Execute.cs
+++ b/src/Infrastructure/BotSharp.Core/Instructs/Services/InstructService.Execute.cs
@@ -242,12 +242,31 @@ private async Task RunLlm(
var result = string.Empty;
// Render prompt
- var prompt = string.IsNullOrEmpty(templateName) ?
- agentService.RenderInstruction(agent) :
- agentService.RenderTemplate(agent, templateName);
+ var prompt = string.Empty;
+ var llmConfig = agent.LlmConfig;
+
+ if (!string.IsNullOrEmpty(templateName))
+ {
+ prompt = agentService.RenderTemplate(agent, templateName);
+ var templateLlmConfig = agent.Templates?.FirstOrDefault(x => x.Name.IsEqualTo(templateName))?.LlmConfig;
+ if (templateLlmConfig?.IsValid == true)
+ {
+ llmConfig = new AgentLlmConfig
+ {
+ Provider = templateLlmConfig.Provider,
+ Model = templateLlmConfig.Model,
+ MaxOutputTokens = templateLlmConfig.MaxOutputTokens,
+ ReasoningEffortLevel = templateLlmConfig.ReasoningEffortLevel
+ };
+ }
+ }
+ else
+ {
+ prompt = agentService.RenderInstruction(agent);
+ }
var completer = CompletionProvider.GetCompletion(_services,
- agentConfig: agent.LlmConfig);
+ agentConfig: llmConfig);
if (completer is ITextCompletion textCompleter)
{
@@ -292,7 +311,7 @@ private async Task RunLlm(
}
else
{
- result = await GetChatCompletion(chatCompleter, agent, instruction, prompt, message.MessageId, files);
+ result = await GetChatCompletion(chatCompleter, agent, instruction, prompt, message.MessageId, llmConfig, files);
}
// Repair JSON format if needed
@@ -343,6 +362,7 @@ private async Task GetChatCompletion(
string instruction,
string text,
string messageId,
+ AgentLlmConfig? llmConfig = null,
IEnumerable? files = null)
{
var result = await chatCompleter.GetChatCompletions(new Agent
@@ -350,7 +370,7 @@ private async Task GetChatCompletion(
Id = agent.Id,
Name = agent.Name,
Instruction = instruction,
- LlmConfig = agent.LlmConfig
+ LlmConfig = llmConfig ?? agent.LlmConfig
}, new List
{
new RoleDialogModel(AgentRole.User, text)
diff --git a/src/Infrastructure/BotSharp.Core/Instructs/Services/InstructService.Instruct.cs b/src/Infrastructure/BotSharp.Core/Instructs/Services/InstructService.Instruct.cs
index f75707605..1ca2d926c 100644
--- a/src/Infrastructure/BotSharp.Core/Instructs/Services/InstructService.Instruct.cs
+++ b/src/Infrastructure/BotSharp.Core/Instructs/Services/InstructService.Instruct.cs
@@ -56,6 +56,7 @@ public partial class InstructService
private async Task BuildInnerAgent(InstructOptions? options)
{
Agent? agent = null;
+ AgentLlmConfig? llmConfig = null;
string? instruction = null;
if (!string.IsNullOrWhiteSpace(options?.AgentId))
@@ -65,8 +66,19 @@ private async Task BuildInnerAgent(InstructOptions? options)
if (!string.IsNullOrWhiteSpace(options?.TemplateName))
{
- var template = agent?.Templates?.FirstOrDefault(x => x.Name == options.TemplateName)?.Content ?? string.Empty;
- instruction = BuildInstruction(template, options?.Data ?? []);
+ var template = agent?.Templates?.FirstOrDefault(x => x.Name.IsEqualTo(options.TemplateName));
+ instruction = BuildInstruction(template?.Content ?? string.Empty, options?.Data ?? []);
+ var templateLlmConfig = template?.LlmConfig;
+ if (templateLlmConfig?.IsValid == true)
+ {
+ llmConfig = new AgentLlmConfig
+ {
+ Provider = templateLlmConfig.Provider,
+ Model = templateLlmConfig.Model,
+ MaxOutputTokens = templateLlmConfig.MaxOutputTokens,
+ ReasoningEffortLevel = templateLlmConfig.ReasoningEffortLevel
+ };
+ }
}
}
@@ -75,7 +87,7 @@ private async Task BuildInnerAgent(InstructOptions? options)
Id = agent?.Id ?? Guid.Empty.ToString(),
Name = agent?.Name ?? "Unknown",
Instruction = instruction,
- LlmConfig = agent?.LlmConfig ?? new()
+ LlmConfig = llmConfig ?? agent?.LlmConfig ?? new()
};
}
diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs
index 43a5bf659..2ab0b1f2b 100644
--- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs
+++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs
@@ -425,7 +425,8 @@ private async Task UpdateAgentTemplates(string agentId, List temp
return;
}
- var templateDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId, AGENT_TEMPLATES_FOLDER);
+ var baseDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId);
+ var templateDir = Path.Combine(baseDir, AGENT_TEMPLATES_FOLDER);
DeleteBeforeCreateDirectory(templateDir);
foreach (var template in templates)
@@ -433,6 +434,18 @@ private async Task UpdateAgentTemplates(string agentId, List temp
var file = Path.Combine(templateDir, $"{template.Name}.{_agentSettings.TemplateFormat}");
await File.WriteAllTextAsync(file, template.Content);
}
+
+ // Save template configs
+ var configFile = Path.Combine(baseDir, AGENT_TEMPLATE_CONFIG_FILE);
+ var configs = templates.Select(t => new AgentTemplateConfig
+ {
+ Name = t.Name,
+ ResponseFormat = t.ResponseFormat,
+ LlmConfig = t.LlmConfig
+ }).ToList();
+
+ var configJson = JsonSerializer.Serialize(configs, _options);
+ await File.WriteAllTextAsync(configFile, configJson);
}
private async Task UpdateAgentResponses(string agentId, List responses)
@@ -710,6 +723,50 @@ public async Task GetAgentTemplate(string agentId, string templateName)
return string.Empty;
}
+ public async Task GetAgentTemplateDetail(string agentId, string templateName)
+ {
+ var template = new AgentTemplate { Name = templateName };
+
+ if (string.IsNullOrWhiteSpace(agentId)
+ || string.IsNullOrWhiteSpace(templateName))
+ {
+ return template;
+ }
+
+ var baseDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId);
+ var dir = Path.Combine(baseDir, AGENT_TEMPLATES_FOLDER);
+ if (!Directory.Exists(dir))
+ {
+ return template;
+ }
+
+ // Get template content
+ foreach (var file in Directory.EnumerateFiles(dir))
+ {
+ var fileName = file.Split(Path.DirectorySeparatorChar).Last();
+ var splitIdx = fileName.LastIndexOf(".");
+ var name = fileName.Substring(0, splitIdx);
+ var extension = fileName.Substring(splitIdx + 1);
+ if (name.IsEqualTo(templateName) && extension.IsEqualTo(_agentSettings.TemplateFormat))
+ {
+ template.Content = await File.ReadAllTextAsync(file);
+ break;
+ }
+ }
+
+ // Get template configs
+ var (configs, _) = GetAgentTemplateConfigs(baseDir);
+ var configFile = Path.Combine(baseDir, AGENT_TEMPLATE_CONFIG_FILE);
+ var found = configs?.FirstOrDefault(x => x.Name.IsEqualTo(templateName));
+ if (found != null)
+ {
+ template.ResponseFormat = found.ResponseFormat;
+ template.LlmConfig = found.LlmConfig;
+ }
+
+ return template;
+ }
+
public async Task PatchAgentTemplate(string agentId, AgentTemplate template)
{
if (string.IsNullOrEmpty(agentId) || template == null)
@@ -717,7 +774,8 @@ public async Task PatchAgentTemplate(string agentId, AgentTemplate templat
return false;
}
- var dir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId, AGENT_TEMPLATES_FOLDER);
+ var baseDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId);
+ var dir = Path.Combine(baseDir, AGENT_TEMPLATES_FOLDER);
if (!Directory.Exists(dir))
{
return false;
@@ -736,6 +794,28 @@ public async Task PatchAgentTemplate(string agentId, AgentTemplate templat
}
await File.WriteAllTextAsync(foundTemplate, template.Content);
+
+ // Update template config
+ var (configs, configFile) = GetAgentTemplateConfigs(baseDir);
+
+ var existingConfig = configs.FirstOrDefault(x => x.Name.IsEqualTo(template.Name));
+ if (existingConfig != null)
+ {
+ existingConfig.ResponseFormat = template.ResponseFormat;
+ existingConfig.LlmConfig = template.LlmConfig;
+ }
+ else
+ {
+ configs.Add(new AgentTemplateConfig
+ {
+ Name = template.Name,
+ ResponseFormat = template.ResponseFormat,
+ LlmConfig = template.LlmConfig
+ });
+ }
+
+ var updatedJson = JsonSerializer.Serialize(configs, _options);
+ await File.WriteAllTextAsync(configFile, updatedJson);
return true;
}
diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.cs
index 255d80a83..501a2655d 100644
--- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.cs
+++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.cs
@@ -59,6 +59,8 @@ public partial class FileRepository : IBotSharpRepository
private const string CRON_FILE = "cron.json";
private const string INSTRUCTION_LOG_FOLDER = "instruction-logs";
+ private const string AGENT_TEMPLATE_CONFIG_FILE = "template_configs.json";
+
public FileRepository(
IServiceProvider services,
BotSharpDatabaseSettings dbSettings,
@@ -387,6 +389,10 @@ private List FetchTemplates(string fileDir)
var templateDir = Path.Combine(fileDir, AGENT_TEMPLATES_FOLDER);
if (!Directory.Exists(templateDir)) return templates;
+ // Load template configs
+ var (configs, _) = GetAgentTemplateConfigs(fileDir);
+
+ // Load templates
foreach (var file in Directory.GetFiles(templateDir))
{
var fileName = Path.GetFileName(file);
@@ -396,7 +402,14 @@ private List FetchTemplates(string fileDir)
if (extension.Equals(_agentSettings.TemplateFormat, StringComparison.OrdinalIgnoreCase))
{
var content = File.ReadAllText(file);
- templates.Add(new AgentTemplate(name, content));
+ var template = new AgentTemplate(name, content);
+ var config = configs.FirstOrDefault(x => x.Name.IsEqualTo(name));
+ if (config != null)
+ {
+ template.ResponseFormat = config.ResponseFormat;
+ template.LlmConfig = config.LlmConfig;
+ }
+ templates.Add(template);
}
}
@@ -490,5 +503,31 @@ private string[] ParseFileNameByPath(string path, string separator = ".")
var name = path.Split(Path.DirectorySeparatorChar).Last();
return name.Split(separator);
}
+
+ ///
+ /// Get agent template configs: (configs, config file location)
+ ///
+ ///
+ ///
+ private (List, string) GetAgentTemplateConfigs(string baseDir)
+ {
+ var configFile = Path.Combine(baseDir, AGENT_TEMPLATE_CONFIG_FILE);
+ var configs = new List();
+
+ try
+ {
+ if (File.Exists(configFile))
+ {
+ var configJson = File.ReadAllText(configFile);
+ configs = JsonSerializer.Deserialize>(configJson, _options) ?? [];
+ }
+ return (configs, configFile);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error when loading template configs in {configFile}", configFile);
+ return (configs, configFile);
+ }
+ }
#endregion
}
diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01e2fc5c-2c89-4ec7-8470-7688608b496c/template_configs.json b/src/Infrastructure/BotSharp.Core/data/agents/01e2fc5c-2c89-4ec7-8470-7688608b496c/template_configs.json
new file mode 100644
index 000000000..0637a088a
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Core/data/agents/01e2fc5c-2c89-4ec7-8470-7688608b496c/template_configs.json
@@ -0,0 +1 @@
+[]
\ No newline at end of file
diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/Agent/AgentController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/Agent/AgentController.cs
index 79de888ef..1c894ca3f 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/Agent/AgentController.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/Agent/AgentController.cs
@@ -37,7 +37,7 @@ public AgentSettings GetSettings()
{
var pagedAgents = await _agentService.GetAgents(new AgentFilter
{
- AgentIds = new List { id }
+ AgentIds = [id]
});
var foundAgent = pagedAgents.Items.FirstOrDefault();
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Models/AgentTemplateLlmConfigMongoModel.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/AgentTemplateLlmConfigMongoModel.cs
new file mode 100644
index 000000000..6ca7c48f1
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/AgentTemplateLlmConfigMongoModel.cs
@@ -0,0 +1,43 @@
+using BotSharp.Abstraction.Agents.Models;
+
+namespace BotSharp.Plugin.MongoStorage.Models;
+
+public class AgentTemplateLlmConfigMongoModel
+{
+ public string? Provider { get; set; }
+ public string? Model { get; set; }
+ public int? MaxOutputTokens { get; set; }
+ public string? ReasoningEffortLevel { get; set; }
+
+ public static AgentTemplateLlmConfigMongoModel? ToMongoModel(AgentTemplateLlmConfig? config)
+ {
+ if (config == null)
+ {
+ return null;
+ }
+
+ return new AgentTemplateLlmConfigMongoModel
+ {
+ Provider = config.Provider,
+ Model = config.Model,
+ MaxOutputTokens = config.MaxOutputTokens,
+ ReasoningEffortLevel = config.ReasoningEffortLevel
+ };
+ }
+
+ public static AgentTemplateLlmConfig? ToDomainModel(AgentTemplateLlmConfigMongoModel? config)
+ {
+ if (config == null)
+ {
+ return null;
+ }
+
+ return new AgentTemplateLlmConfig
+ {
+ Provider = config.Provider,
+ Model = config.Model,
+ MaxOutputTokens = config.MaxOutputTokens,
+ ReasoningEffortLevel = config.ReasoningEffortLevel
+ };
+ }
+}
\ No newline at end of file
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Models/AgentTemplateMongoElement.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/AgentTemplateMongoElement.cs
index 6021ef3c4..ca95e6185 100644
--- a/src/Plugins/BotSharp.Plugin.MongoStorage/Models/AgentTemplateMongoElement.cs
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/AgentTemplateMongoElement.cs
@@ -6,14 +6,18 @@ namespace BotSharp.Plugin.MongoStorage.Models;
public class AgentTemplateMongoElement
{
public string Name { get; set; } = default!;
- public string Content { get; set; } = default!;
+ public string Content { get; set; } = string.Empty;
+ public string? ResponseFormat { get; set; }
+ public AgentTemplateLlmConfigMongoModel? LlmConfig { get; set; }
public static AgentTemplateMongoElement ToMongoElement(AgentTemplate template)
{
return new AgentTemplateMongoElement
{
Name = template.Name,
- Content = template.Content
+ Content = template.Content,
+ ResponseFormat = template.ResponseFormat,
+ LlmConfig = AgentTemplateLlmConfigMongoModel.ToMongoModel(template.LlmConfig)
};
}
@@ -22,7 +26,9 @@ public static AgentTemplate ToDomainElement(AgentTemplateMongoElement mongoTempl
return new AgentTemplate
{
Name = mongoTemplate.Name,
- Content = mongoTemplate.Content
+ Content = mongoTemplate.Content,
+ ResponseFormat = mongoTemplate.ResponseFormat,
+ LlmConfig = AgentTemplateLlmConfigMongoModel.ToDomainModel(mongoTemplate.LlmConfig)
};
}
}
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs
index c1e20f5d6..a18bf7f79 100644
--- a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs
@@ -553,6 +553,24 @@ public async Task GetAgentTemplate(string agentId, string templateName)
return agent.Templates?.FirstOrDefault(x => x.Name.IsEqualTo(templateName))?.Content ?? string.Empty;
}
+ public async Task GetAgentTemplateDetail(string agentId, string templateName)
+ {
+ var filter = Builders.Filter.Eq(x => x.Id, agentId);
+ var agent = await _dc.Agents.Find(filter).FirstOrDefaultAsync();
+ if (agent == null)
+ {
+ return new AgentTemplate { Name = templateName };
+ }
+
+ var foundTemplate = agent.Templates?.FirstOrDefault(x => x.Name.IsEqualTo(templateName));
+ if (foundTemplate == null)
+ {
+ return new AgentTemplate { Name = templateName };
+ }
+
+ return AgentTemplateMongoElement.ToDomainElement(foundTemplate);
+ }
+
public async Task PatchAgentTemplate(string agentId, AgentTemplate template)
{
if (string.IsNullOrEmpty(agentId) || template == null)
@@ -574,6 +592,8 @@ public async Task PatchAgentTemplate(string agentId, AgentTemplate templat
}
foundTemplate.Content = template.Content;
+ foundTemplate.ResponseFormat = template.ResponseFormat;
+ foundTemplate.LlmConfig = AgentTemplateLlmConfigMongoModel.ToMongoModel(template.LlmConfig);
var update = Builders.Update.Set(x => x.Templates, agent.Templates);
await _dc.Agents.UpdateOneAsync(filter, update);
return true;
diff --git a/tests/BotSharp.LLM.Tests/Core/TestAgentService.cs b/tests/BotSharp.LLM.Tests/Core/TestAgentService.cs
index 5e702fea9..487e72f24 100644
--- a/tests/BotSharp.LLM.Tests/Core/TestAgentService.cs
+++ b/tests/BotSharp.LLM.Tests/Core/TestAgentService.cs
@@ -132,5 +132,10 @@ public ResponseFormatType GetTemplateResponseFormat(Agent agent, string template
{
return ResponseFormatType.Text;
}
+
+ public Task GetAgentTemplateDetail(string agentId, string templateName)
+ {
+ return Task.FromResult(new AgentTemplate { Name = templateName });
+ }
}
}
\ No newline at end of file