Merge pull request #287 from iceljc/features/add-agent-task-mongo

Features/add agent task mongo
This commit is contained in:
Haiping 2024-02-04 15:59:49 -06:00 committed by GitHub
commit 620bd02d37
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 675 additions and 118 deletions

View file

@ -18,3 +18,12 @@ public enum AgentField
Sample,
LlmConfig
}
public enum AgentTaskField
{
All = 1,
Name,
Description,
Enabled,
Content
}

View file

@ -4,4 +4,5 @@ public class AgentTaskFilter
{
public Pagination Pager { get; set; } = new Pagination();
public string? AgentId { get; set; }
public bool? Enabled { get; set; }
}

View file

@ -1,6 +1,7 @@
using BotSharp.Abstraction.Plugins.Models;
using BotSharp.Abstraction.Repositories.Filters;
using BotSharp.Abstraction.Repositories.Models;
using BotSharp.Abstraction.Tasks.Models;
using BotSharp.Abstraction.Users.Models;
namespace BotSharp.Abstraction.Repositories;
@ -34,6 +35,14 @@ public interface IBotSharpRepository
string GetAgentTemplate(string agentId, string templateName);
#endregion
#region Agent Task
PagedItems<AgentTask> GetAgentTasks(AgentTaskFilter filter);
AgentTask? GetAgentTask(string agentId, string taskId);
void InsertAgentTask(AgentTask task);
void UpdateAgentTask(AgentTask task, AgentTaskField field);
bool DeleteAgentTask(string agentId, string taskId);
#endregion
#region Conversation
void CreateNewConversation(Conversation conversation);
bool DeleteConversation(string conversationId);
@ -49,9 +58,7 @@ public interface IBotSharpRepository
List<Conversation> GetLastConversations();
bool TruncateConversation(string conversationId, string messageId);
#endregion
#region Statistics
void IncrementConversationCount();
#endregion
#region Execution Log
void AddExecutionLogs(string conversationId, List<string> logs);
List<string> GetExecutionLogs(string conversationId);
@ -60,4 +67,8 @@ public interface IBotSharpRepository
#region LLM Completion Log
void SaveLlmCompletionLog(LlmCompletionLog log);
#endregion
#region Statistics
void IncrementConversationCount();
#endregion
}

View file

@ -6,4 +6,12 @@ namespace BotSharp.Abstraction.Tasks;
public interface IAgentTaskService
{
Task<PagedItems<AgentTask>> GetTasks(AgentTaskFilter filter);
Task<AgentTask?> GetTask(string agentId, string taskId);
Task CreateTask(AgentTask task);
Task UpdateTask(AgentTask task, AgentTaskField field);
Task<bool> DeleteTask(string agentId, string taskId);
}

View file

@ -10,9 +10,17 @@ public class AgentTask
public DateTime CreatedDateTime { get; set; }
public DateTime UpdatedDateTime { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.Always)]
public string AgentId { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.Always)]
public Agent Agent { get; set; }
public AgentTask()
{
}
public AgentTask(string id, string name, string? description = null)
{
Id = id;

View file

@ -13,5 +13,5 @@ public class Pagination
public class PagedItems<T>
{
public int Count { get; set; }
public IEnumerable<T> Items { get; set; }
public IEnumerable<T> Items { get; set; } = new List<T>();
}

View file

@ -3,6 +3,7 @@ using BotSharp.Abstraction.Plugins.Models;
using BotSharp.Abstraction.Repositories;
using BotSharp.Abstraction.Repositories.Filters;
using BotSharp.Abstraction.Repositories.Models;
using BotSharp.Abstraction.Tasks.Models;
using BotSharp.Abstraction.Users.Models;
using Microsoft.EntityFrameworkCore.Infrastructure;
@ -119,6 +120,32 @@ public class BotSharpDbContext : Database, IBotSharpRepository
}
#endregion
#region Agent Task
public PagedItems<AgentTask> GetAgentTasks(AgentTaskFilter filter)
{
throw new NotImplementedException();
}
public AgentTask? GetAgentTask(string agentId, string taskId)
{
throw new NotImplementedException();
}
public void InsertAgentTask(AgentTask task)
{
throw new NotImplementedException();
}
public void UpdateAgentTask(AgentTask task, AgentTaskField field)
{
throw new NotImplementedException();
}
public bool DeleteAgentTask(string agentId, string taskId)
{
throw new NotImplementedException();
}
#endregion
#region Conversation
public void CreateNewConversation(Conversation conversation)
@ -184,13 +211,7 @@ public class BotSharpDbContext : Database, IBotSharpRepository
throw new NotImplementedException();
}
#endregion
#region Stats
public void IncrementConversationCount()
{
throw new NotImplementedException();
}
#endregion
#region User
public User? GetUserByEmail(string email)
=> throw new NotImplementedException();
@ -205,7 +226,6 @@ public class BotSharpDbContext : Database, IBotSharpRepository
=> throw new NotImplementedException();
#endregion
#region Execution Log
public void AddExecutionLogs(string conversationId, List<string> logs)
{
@ -224,4 +244,11 @@ public class BotSharpDbContext : Database, IBotSharpRepository
throw new NotImplementedException();
}
#endregion
#region Stats
public void IncrementConversationCount()
{
throw new NotImplementedException();
}
#endregion
}

View file

@ -1,9 +1,9 @@
using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Evaluations.Settings;
using BotSharp.Abstraction.Functions.Models;
using BotSharp.Abstraction.Repositories.Filters;
using BotSharp.Abstraction.Routing.Models;
using BotSharp.Abstraction.Routing.Settings;
using BotSharp.Abstraction.Tasks.Models;
using Microsoft.Extensions.Logging;
using System.IO;
namespace BotSharp.Core.Repository
@ -326,12 +326,11 @@ namespace BotSharp.Core.Repository
var functions = FetchFunctions(dir);
var samples = FetchSamples(dir);
var templates = FetchTemplates(dir);
var tasks = FetchTasks(dir);
var responses = FetchResponses(dir);
return record.SetInstruction(instruction)
.SetFunctions(functions)
.SetSamples(samples)
.SetTemplates(templates)
.SetSamples(samples)
.SetResponses(responses);
}
@ -406,6 +405,7 @@ namespace BotSharp.Core.Repository
return string.Empty;
}
public void BulkInsertAgents(List<Agent> agents)
{
}

View file

@ -0,0 +1,228 @@
using BotSharp.Abstraction.Repositories.Filters;
using BotSharp.Abstraction.Tasks.Models;
using System.IO;
using System.Threading.Tasks;
namespace BotSharp.Core.Repository;
public partial class FileRepository
{
#region Task
public PagedItems<AgentTask> GetAgentTasks(AgentTaskFilter filter)
{
var tasks = new List<AgentTask>();
var pager = filter.Pager ?? new Pagination();
var skipCount = 0;
var takeCount = 0;
var totalCount = 0;
var matched = true;
var dir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir);
if (!Directory.Exists(dir)) return new PagedItems<AgentTask>();
foreach (var agentDir in Directory.GetDirectories(dir))
{
var taskDir = Path.Combine(agentDir, "tasks");
if (!Directory.Exists(taskDir)) continue;
var agentId = agentDir.Split(Path.DirectorySeparatorChar).Last();
matched = true;
if (filter?.AgentId != null)
{
matched = agentId == filter.AgentId;
}
if (!matched) continue;
var curTasks = new List<AgentTask>();
foreach (var taskFile in Directory.GetFiles(taskDir))
{
var task = ParseAgentTask(taskFile);
if (task == null) continue;
matched = true;
if (filter?.Enabled != null)
{
matched = matched && task.Enabled == filter.Enabled;
}
if (!matched) continue;
totalCount++;
if (takeCount >= pager.Size) continue;
if (skipCount < pager.Offset)
{
skipCount++;
}
else
{
curTasks.Add(task);
takeCount++;
}
}
if (curTasks.IsNullOrEmpty()) continue;
var agent = ParseAgent(agentDir);
curTasks.ForEach(t =>
{
t.AgentId = agentId;
t.Agent = agent;
});
tasks.AddRange(curTasks);
}
return new PagedItems<AgentTask>
{
Items = tasks,
Count = totalCount
};
}
public AgentTask? GetAgentTask(string agentId, string taskId)
{
var agentDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId);
if (!Directory.Exists(agentDir)) return null;
var taskDir = Path.Combine(agentDir, "tasks");
if (!Directory.Exists(taskDir)) return null;
var taskFile = FindTaskFileById(taskDir, taskId);
if (taskFile == null) return null;
var task = ParseAgentTask(taskFile);
if (task == null) return null;
var agent = ParseAgent(agentDir);
task.AgentId = agentId;
task.Agent = agent;
return task;
}
public void InsertAgentTask(AgentTask task)
{
if (task == null || string.IsNullOrEmpty(task.AgentId)) return;
var agentDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, task.AgentId);
if (!Directory.Exists(agentDir)) return;
var taskDir = Path.Combine(agentDir, "tasks");
if (!Directory.Exists(taskDir))
{
Directory.CreateDirectory(taskDir);
}
var fileName = $"{Guid.NewGuid()}.liquid";
var taskFile = Path.Combine(taskDir, fileName);
var model = new AgentTaskFileModel
{
Name = task.Name,
Description = task.Description,
Enabled = task.Enabled,
CreatedDateTime = DateTime.UtcNow,
UpdatedDateTime = DateTime.UtcNow
};
var fileContent = BuildAgentTaskFileContent(model, task.Content);
File.WriteAllText(taskFile, fileContent);
}
public void UpdateAgentTask(AgentTask task, AgentTaskField field)
{
if (task == null || string.IsNullOrEmpty(task.Id)) return;
var agentDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, task.AgentId);
if (!Directory.Exists(agentDir)) return;
var taskDir = Path.Combine(agentDir, "tasks");
if (!Directory.Exists(taskDir)) return;
var taskFile = FindTaskFileById(taskDir, task.Id);
if (string.IsNullOrEmpty(taskFile)) return;
var parsedTask = ParseAgentTask(taskFile);
if (parsedTask == null) return;
var model = new AgentTaskFileModel
{
Name = parsedTask.Name,
Description = parsedTask.Description,
Enabled = parsedTask.Enabled,
CreatedDateTime = parsedTask.CreatedDateTime,
UpdatedDateTime = DateTime.UtcNow
};
var content = parsedTask.Content;
switch (field)
{
case AgentTaskField.Name:
model.Name = task.Name;
break;
case AgentTaskField.Description:
model.Description = task.Description;
break;
case AgentTaskField.Enabled:
model.Enabled = task.Enabled;
break;
case AgentTaskField.Content:
content = task.Content;
break;
case AgentTaskField.All:
model.Name = task.Name;
model.Description = task.Description;
model.Enabled = task.Enabled;
content = task.Content;
break;
}
var fileContent = BuildAgentTaskFileContent(model, content);
File.WriteAllText(taskFile, fileContent);
}
public bool DeleteAgentTask(string agentId, string taskId)
{
var agentDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId);
if (!Directory.Exists(agentDir)) return false;
var taskDir = Path.Combine(agentDir, "tasks");
if (!Directory.Exists(taskDir)) return false;
var taskFile = FindTaskFileById(taskDir, taskId);
if (string.IsNullOrWhiteSpace(taskFile)) return false;
File.Delete(taskFile);
return true;
}
private string? FindTaskFileById(string taskDir, string taskId)
{
if (!Directory.Exists(taskDir) || string.IsNullOrEmpty(taskId)) return null;
var taskFile = Directory.GetFiles(taskDir).FirstOrDefault(file =>
{
var fileName = file.Split(Path.DirectorySeparatorChar).Last();
var id = fileName.Split('.').First();
return id.IsEqualTo(taskId);
});
return taskFile;
}
private string BuildAgentTaskFileContent(AgentTaskFileModel fileModel, string taskContent)
{
return $"{AGENT_TASK_PREFIX}\n{JsonSerializer.Serialize(fileModel, _options)}\n{AGENT_TASK_SUFFIX}\n\n{taskContent}";
}
#endregion
}
internal class AgentTaskFileModel
{
public string Name { get; set; }
public string? Description { get; set; }
public bool Enabled { get; set; }
public DateTime CreatedDateTime { get; set; }
public DateTime UpdatedDateTime { get; set; }
}

View file

@ -35,9 +35,9 @@ namespace BotSharp.Core.Repository
{
Key = x.Key,
Values = new List<StateValue>
{
new StateValue { Data = x.Value, UpdateTime = DateTime.UtcNow }
}
{
new StateValue { Data = x.Value, UpdateTime = DateTime.UtcNow }
}
}).ToList();
File.WriteAllText(stateFile, JsonSerializer.Serialize(initialStates, _options));
}

View file

@ -33,6 +33,8 @@ public partial class FileRepository : IBotSharpRepository
private const string STATE_FILE = "state.json";
private const string EXECUTION_LOG_FILE = "execution.log";
private const string PLUGIN_CONFIG_FILE = "config.json";
private const string AGENT_TASK_PREFIX = "#metadata";
private const string AGENT_TASK_SUFFIX = "/metadata";
public FileRepository(
IServiceProvider services,
@ -116,9 +118,8 @@ public partial class FileRepository : IBotSharpRepository
if (agent != null)
{
agent = agent.SetInstruction(FetchInstruction(d))
.SetTemplates(FetchTemplates(d))
.SetTasks(FetchTasks(d))
.SetFunctions(FetchFunctions(d))
.SetTemplates(FetchTemplates(d))
.SetResponses(FetchResponses(d))
.SetSamples(FetchSamples(d));
_agents.Add(agent);
@ -236,19 +237,10 @@ public partial class FileRepository : IBotSharpRepository
foreach (var file in Directory.GetFiles(taskDir))
{
var fileName = file.Split(Path.DirectorySeparatorChar).Last();
var id = fileName.Split('.').First();
var data = File.ReadAllText(file);
var metadata = Regex.Match(data, @"#metadata.+/metadata", RegexOptions.Singleline);
var task = ParseAgentTask(file);
if (task == null) continue;
if (metadata.Success)
{
var task = metadata.Value.JsonContent<AgentTask>();
task.Id = id;
var content = Regex.Match(data, @"/metadata.+", RegexOptions.Singleline).Value;
task.Content = content.Substring(9).Trim();
tasks.Add(task);
}
tasks.Add(task);
}
return tasks;
@ -273,6 +265,51 @@ public partial class FileRepository : IBotSharpRepository
return responses;
}
private Agent? ParseAgent(string agentDir)
{
if (string.IsNullOrEmpty(agentDir)) return null;
var agentJson = File.ReadAllText(Path.Combine(agentDir, AGENT_FILE));
if (string.IsNullOrEmpty(agentJson)) return null;
var agent = JsonSerializer.Deserialize<Agent>(agentJson, _options);
if (agent == null) return null;
var instruction = FetchInstruction(agentDir);
var functions = FetchFunctions(agentDir);
var samples = FetchSamples(agentDir);
var templates = FetchTemplates(agentDir);
var responses = FetchResponses(agentDir);
return agent.SetInstruction(instruction)
.SetFunctions(functions)
.SetTemplates(templates)
.SetSamples(samples)
.SetResponses(responses);
}
private AgentTask? ParseAgentTask(string taskFile)
{
if (string.IsNullOrWhiteSpace(taskFile)) return null;
var fileName = taskFile.Split(Path.DirectorySeparatorChar).Last();
var id = fileName.Split('.').First();
var data = File.ReadAllText(taskFile);
var pattern = $@"{AGENT_TASK_PREFIX}.+{AGENT_TASK_SUFFIX}";
var metaData = Regex.Match(data, pattern, RegexOptions.Singleline);
if (!metaData.Success) return null;
var task = metaData.Value.JsonContent<AgentTask>();
if (task == null) return null;
task.Id = id;
pattern = $@"{AGENT_TASK_SUFFIX}.+";
var content = Regex.Match(data, pattern, RegexOptions.Singleline).Value;
task.Content = content.Substring(AGENT_TASK_SUFFIX.Length).Trim();
return task;
}
private string[] ParseFileNameByPath(string path, string separator = ".")
{
var name = path.Split(Path.DirectorySeparatorChar).Last();

View file

@ -1,3 +1,4 @@
using BotSharp.Abstraction.Repositories;
using BotSharp.Abstraction.Repositories.Filters;
using BotSharp.Abstraction.Tasks;
using BotSharp.Abstraction.Tasks.Models;
@ -14,23 +15,36 @@ public class AgentTaskService : IAgentTaskService
public async Task<PagedItems<AgentTask>> GetTasks(AgentTaskFilter filter)
{
var agentService = _services.GetRequiredService<IAgentService>();
var agents = await agentService.GetAgents(new AgentFilter());
var tasks = new List<AgentTask>();
foreach (var agent in agents.Items)
{
if (filter.AgentId != null && filter.AgentId != agent.Id)
{
continue;
}
agent.Tasks.ForEach(x => x.Agent = agent);
tasks.AddRange(agent.Tasks);
}
var db = _services.GetRequiredService<IBotSharpRepository>();
var pagedTasks = db.GetAgentTasks(filter);
return await Task.FromResult(pagedTasks);
}
return new PagedItems<AgentTask>
{
Items = tasks.Skip(filter.Pager.Offset).Take(filter.Pager.Size),
Count = tasks.Count,
};
public async Task<AgentTask?> GetTask(string agentId, string taskId)
{
var db = _services.GetRequiredService<IBotSharpRepository>();
var task = db.GetAgentTask(agentId, taskId);
return await Task.FromResult(task);
}
public async Task CreateTask(AgentTask task)
{
var db = _services.GetRequiredService<IBotSharpRepository>();
db.InsertAgentTask(task);
await Task.CompletedTask;
}
public async Task UpdateTask(AgentTask task, AgentTaskField field)
{
var db = _services.GetRequiredService<IBotSharpRepository>();
db.UpdateAgentTask(task, field);
await Task.CompletedTask;
}
public async Task<bool> DeleteTask(string agentId, string taskId)
{
var db = _services.GetRequiredService<IBotSharpRepository>();
var isDeleted = db.DeleteAgentTask(agentId, taskId);
return await Task.FromResult(isDeleted);
}
}

View file

@ -1,6 +1,4 @@
using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Tasks;
using BotSharp.Abstraction.Tasks.Models;
namespace BotSharp.OpenAPI.Controllers;
@ -8,30 +6,64 @@ namespace BotSharp.OpenAPI.Controllers;
[ApiController]
public class AgentTaskController : ControllerBase
{
private readonly IAgentService _agentService;
private readonly IAgentTaskService _agentTaskService;
private readonly IServiceProvider _services;
public AgentTaskController(IAgentService agentService, IServiceProvider services)
public AgentTaskController(IAgentTaskService agentTaskService, IServiceProvider services)
{
_agentService = agentService;
_agentTaskService = agentTaskService;
_services = services;
}
[HttpGet("/agent/task/{id}")]
public async Task<AgentViewModel> GetAgentTask([FromRoute] string id)
[HttpGet("/agent/{agentId}/task/{taskId}")]
public async Task<AgentTaskViewModel?> GetAgentTask([FromRoute] string agentId, [FromRoute] string taskId)
{
throw new NotImplementedException("");
var task = await _agentTaskService.GetTask(agentId, taskId);
if (task == null) return null;
return AgentTaskViewModel.From(task);
}
[HttpGet("/agent/tasks")]
public async Task<PagedItems<AgentTaskViewModel>> GetAgents([FromQuery] AgentTaskFilter filter)
{
var taskService = _services.GetRequiredService<IAgentTaskService>();
var tasks = await taskService.GetTasks(filter);
var tasks = await _agentTaskService.GetTasks(filter);
return new PagedItems<AgentTaskViewModel>
{
Items = tasks.Items.Select(x => AgentTaskViewModel.From(x)),
Count = tasks.Count
};
}
[HttpPost("/agent/{agentId}/task")]
public async Task CreateAgentTask([FromRoute] string agentId, [FromBody] AgentTaskCreateModel task)
{
var agentTask = task.ToAgentTask();
agentTask.AgentId = agentId;
await _agentTaskService.CreateTask(agentTask);
}
[HttpPut("/agent/{agentId}/task/{taskId}")]
public async Task UpdateAgentTask([FromRoute] string agentId, [FromRoute] string taskId, [FromBody] AgentTaskUpdateModel task)
{
var agentTask = task.ToAgentTask();
agentTask.AgentId = agentId;
agentTask.Id = taskId;
await _agentTaskService.UpdateTask(agentTask, AgentTaskField.All);
}
[HttpPatch("/agent/{agentId}/task/{taskId}/{field}")]
public async Task PatchAgentTaskByField([FromRoute] string agentId, [FromRoute] string taskId, [FromRoute] AgentTaskField field, [FromBody] AgentTaskUpdateModel task)
{
var agentTask = task.ToAgentTask();
agentTask.AgentId = agentId;
agentTask.Id = taskId;
await _agentTaskService.UpdateTask(agentTask, field);
}
[HttpDelete("/agent/{agentId}/task/{taskId}")]
public async Task<bool> DeleteAgentTask([FromRoute] string agentId, [FromRoute] string taskId)
{
return await _agentTaskService.DeleteTask(agentId, taskId);
}
}

View file

@ -0,0 +1,22 @@
using BotSharp.Abstraction.Tasks.Models;
namespace BotSharp.OpenAPI.ViewModels.Agents;
public class AgentTaskCreateModel
{
public string Name { get; set; }
public string? Description { get; set; }
public string Content { get; set; }
public bool Enabled { get; set; }
public AgentTask ToAgentTask()
{
return new AgentTask
{
Name = Name,
Description = Description,
Content = Content,
Enabled = Enabled
};
}
}

View file

@ -0,0 +1,22 @@
using BotSharp.Abstraction.Tasks.Models;
namespace BotSharp.OpenAPI.ViewModels.Agents;
public class AgentTaskUpdateModel
{
public string? Name { get; set; }
public string? Description { get; set; }
public string? Content { get; set; }
public bool Enabled { get; set; }
public AgentTask ToAgentTask()
{
return new AgentTask
{
Name = Name,
Description = Description,
Content = Content,
Enabled = Enabled
};
}
}

View file

@ -28,8 +28,8 @@ public class AgentTaskViewModel
Description = task.Description,
Content = task.Content,
Enabled = task.Enabled,
AgentId = task.Agent.Id,
AgentName = task.Agent.Name,
AgentId = task.AgentId,
AgentName = task.Agent?.Name,
CreatedDateTime = task.CreatedDateTime,
UpdatedDateTime = task.UpdatedDateTime
};

View file

@ -0,0 +1,12 @@
namespace BotSharp.Plugin.MongoStorage.Collections;
public class AgentTaskDocument : MongoBase
{
public string Name { get; set; }
public string? Description { get; set; }
public string Content { get; set; }
public bool Enabled { get; set; }
public string AgentId { get; set; }
public DateTime CreatedTime { get; set; }
public DateTime UpdatedTime { get; set; }
}

View file

@ -31,6 +31,9 @@ public class MongoDbContext
public IMongoCollection<AgentDocument> Agents
=> Database.GetCollection<AgentDocument>($"{_collectionPrefix}_Agents");
public IMongoCollection<AgentTaskDocument> AgentTasks
=> Database.GetCollection<AgentTaskDocument>($"{_collectionPrefix}_AgentTasks");
public IMongoCollection<ConversationDocument> Conversations
=> Database.GetCollection<ConversationDocument>($"{_collectionPrefix}_Conversations");

View file

@ -1,9 +1,11 @@
using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Conversations.Models;
using BotSharp.Abstraction.Evaluations.Settings;
using BotSharp.Abstraction.Functions.Models;
using BotSharp.Abstraction.Repositories.Filters;
using BotSharp.Abstraction.Routing.Models;
using BotSharp.Abstraction.Routing.Settings;
using BotSharp.Abstraction.Tasks.Models;
using BotSharp.Plugin.MongoStorage.Collections;
using BotSharp.Plugin.MongoStorage.Models;
@ -261,33 +263,7 @@ public partial class MongoRepository
var agent = _dc.Agents.AsQueryable().FirstOrDefault(x => x.Id == agentId);
if (agent == null) return null;
return new Agent
{
Id = agent.Id,
Name = agent.Name,
IconUrl = agent.IconUrl,
Description = agent.Description,
Instruction = agent.Instruction,
Templates = !agent.Templates.IsNullOrEmpty() ? agent.Templates
.Select(t => AgentTemplateMongoElement.ToDomainElement(t))
.ToList() : new List<AgentTemplate>(),
Functions = !agent.Functions.IsNullOrEmpty() ? agent.Functions
.Select(f => FunctionDefMongoElement.ToDomainElement(f))
.ToList() : new List<FunctionDef>(),
Responses = !agent.Responses.IsNullOrEmpty() ? agent.Responses
.Select(r => AgentResponseMongoElement.ToDomainElement(r))
.ToList() : new List<AgentResponse>(),
Samples = agent.Samples ?? new List<string>(),
IsPublic = agent.IsPublic,
Disabled = agent.Disabled,
Type = agent.Type,
InheritAgentId = agent.InheritAgentId,
Profiles = agent.Profiles,
RoutingRules = !agent.RoutingRules.IsNullOrEmpty() ? agent.RoutingRules
.Select(r => RoutingRuleMongoElement.ToDomainElement(agent.Id, agent.Name, r))
.ToList() : new List<RoutingRule>(),
LlmConfig = AgentLlmConfigMongoElement.ToDomainElement(agent.LlmConfig)
};
return TransformAgentDocument(agent);
}
public List<Agent> GetAgents(AgentFilter filter)
@ -323,33 +299,7 @@ public partial class MongoRepository
var agentDocs = _dc.Agents.Find(builder.And(filters)).ToList();
return agentDocs.Select(x => new Agent
{
Id = x.Id,
Name = x.Name,
IconUrl = x.IconUrl,
Description = x.Description,
Instruction = x.Instruction,
Templates = !x.Templates.IsNullOrEmpty() ? x.Templates
.Select(t => AgentTemplateMongoElement.ToDomainElement(t))
.ToList() : new List<AgentTemplate>(),
Functions = !x.Functions.IsNullOrEmpty() ? x.Functions
.Select(f => FunctionDefMongoElement.ToDomainElement(f))
.ToList() : new List<FunctionDef>(),
Responses = !x.Responses.IsNullOrEmpty() ? x.Responses
.Select(r => AgentResponseMongoElement.ToDomainElement(r))
.ToList() : new List<AgentResponse>(),
Samples = x.Samples ?? new List<string>(),
IsPublic = x.IsPublic,
Disabled = x.Disabled,
Type = x.Type,
InheritAgentId = x.InheritAgentId,
Profiles = x.Profiles,
RoutingRules = !x.RoutingRules.IsNullOrEmpty() ? x.RoutingRules
.Select(r => RoutingRuleMongoElement.ToDomainElement(x.Id, x.Name, r))
.ToList() : new List<RoutingRule>(),
LlmConfig = AgentLlmConfigMongoElement.ToDomainElement(x.LlmConfig)
}).ToList();
return agentDocs.Select(x => TransformAgentDocument(x)).ToList();
}
public List<Agent> GetAgentsByUser(string userId)
@ -453,4 +403,37 @@ public partial class MongoRepository
}
}
private Agent TransformAgentDocument(AgentDocument? agentDoc)
{
if (agentDoc == null) return new Agent();
return new Agent
{
Id = agentDoc.Id,
Name = agentDoc.Name,
IconUrl = agentDoc.IconUrl,
Description = agentDoc.Description,
Instruction = agentDoc.Instruction,
Templates = !agentDoc.Templates.IsNullOrEmpty() ? agentDoc.Templates
.Select(t => AgentTemplateMongoElement.ToDomainElement(t))
.ToList() : new List<AgentTemplate>(),
Functions = !agentDoc.Functions.IsNullOrEmpty() ? agentDoc.Functions
.Select(f => FunctionDefMongoElement.ToDomainElement(f))
.ToList() : new List<FunctionDef>(),
Responses = !agentDoc.Responses.IsNullOrEmpty() ? agentDoc.Responses
.Select(r => AgentResponseMongoElement.ToDomainElement(r))
.ToList() : new List<AgentResponse>(),
Samples = agentDoc.Samples ?? new List<string>(),
IsPublic = agentDoc.IsPublic,
Disabled = agentDoc.Disabled,
Type = agentDoc.Type,
InheritAgentId = agentDoc.InheritAgentId,
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

@ -0,0 +1,140 @@
using BotSharp.Abstraction.Repositories.Filters;
using BotSharp.Abstraction.Tasks.Models;
using BotSharp.Plugin.MongoStorage.Collections;
namespace BotSharp.Plugin.MongoStorage.Repository;
public partial class MongoRepository
{
#region Task
public PagedItems<AgentTask> GetAgentTasks(AgentTaskFilter filter)
{
var pager = filter.Pager ?? new Pagination();
var builder = Builders<AgentTaskDocument>.Filter;
var filters = new List<FilterDefinition<AgentTaskDocument>>() { builder.Empty };
if (!string.IsNullOrEmpty(filter.AgentId))
{
filters.Add(builder.Eq(x => x.AgentId, filter.AgentId));
}
if (filter.Enabled.HasValue)
{
filters.Add(builder.Eq(x => x.Enabled, filter.Enabled.Value));
}
var filterDef = builder.And(filters);
var sortDef = Builders<AgentTaskDocument>.Sort.Descending(x => x.CreatedTime);
var totalTasks = _dc.AgentTasks.CountDocuments(filterDef);
var taskDocs = _dc.AgentTasks.Find(filterDef).Sort(sortDef).Skip(pager.Offset).Limit(pager.Size).ToList();
var agentIds = taskDocs.Select(x => x.AgentId).Distinct().ToList();
var agents = GetAgents(new AgentFilter { AgentIds = agentIds });
var tasks = taskDocs.Select(x => new AgentTask
{
Id = x.Id,
Name = x.Name,
Description = x.Description,
Enabled = x.Enabled,
AgentId = x.AgentId,
Content = x.Content,
CreatedDateTime = x.CreatedTime,
UpdatedDateTime = x.UpdatedTime,
Agent = agents.FirstOrDefault(a => a.Id == x.AgentId)
}).ToList();
return new PagedItems<AgentTask>
{
Items = tasks,
Count = (int)totalTasks
};
}
public AgentTask? GetAgentTask(string agentId, string taskId)
{
if (string.IsNullOrEmpty(taskId)) return null;
var taskDoc = _dc.AgentTasks.AsQueryable().FirstOrDefault(x => x.Id == taskId);
if (taskDoc == null) return null;
var agentDoc = _dc.Agents.AsQueryable().FirstOrDefault(x => x.Id == taskDoc.AgentId);
var agent = TransformAgentDocument(agentDoc);
var task = new AgentTask
{
Id = taskDoc.Id,
Name = taskDoc.Name,
Description = taskDoc.Description,
Enabled = taskDoc.Enabled,
AgentId = taskDoc.AgentId,
Content = taskDoc.Content,
CreatedDateTime = taskDoc.CreatedTime,
UpdatedDateTime = taskDoc.UpdatedTime,
Agent = agent
};
return task;
}
public void InsertAgentTask(AgentTask task)
{
var taskDoc = new AgentTaskDocument
{
Id = Guid.NewGuid().ToString(),
Name = task.Name,
Description = task.Description,
Enabled = task.Enabled,
AgentId = task.AgentId,
Content = task.Content,
CreatedTime = DateTime.UtcNow,
UpdatedTime = DateTime.UtcNow
};
_dc.AgentTasks.InsertOne(taskDoc);
}
public void UpdateAgentTask(AgentTask task, AgentTaskField field)
{
if (task == null || string.IsNullOrEmpty(task.Id)) return;
var filter = Builders<AgentTaskDocument>.Filter.Eq(x => x.Id, task.Id);
var taskDoc = _dc.AgentTasks.Find(filter).FirstOrDefault();
if (taskDoc == null) return;
switch (field)
{
case AgentTaskField.Name:
taskDoc.Name = task.Name;
break;
case AgentTaskField.Description:
taskDoc.Description = task.Description;
break;
case AgentTaskField.Enabled:
taskDoc.Enabled = task.Enabled;
break;
case AgentTaskField.Content:
taskDoc.Content = task.Content;
break;
case AgentTaskField.All:
taskDoc.Name = task.Name;
taskDoc.Description = task.Description;
taskDoc.Enabled = task.Enabled;
taskDoc.Content = task.Content;
break;
}
taskDoc.UpdatedTime = DateTime.UtcNow;
_dc.AgentTasks.ReplaceOne(filter, taskDoc);
}
public bool DeleteAgentTask(string agentId, string taskId)
{
if (string.IsNullOrEmpty(taskId)) return false;
var filter = Builders<AgentTaskDocument>.Filter.Eq(x => x.Id, taskId);
var taskDeleted = _dc.AgentTasks.DeleteOne(filter);
return taskDeleted.DeletedCount > 0;
}
#endregion
}

View file

@ -217,9 +217,9 @@ public partial class MongoRepository
if (!string.IsNullOrEmpty(filter.UserId)) filters.Add(builder.Eq(x => x.UserId, filter.UserId));
var filterDef = builder.And(filters);
var sortDefinition = Builders<ConversationDocument>.Sort.Descending(x => x.CreatedTime);
var sortDef = Builders<ConversationDocument>.Sort.Descending(x => x.CreatedTime);
var pager = filter?.Pager ?? new Pagination();
var conversationDocs = _dc.Conversations.Find(filterDef).Sort(sortDefinition).Skip(pager.Offset).Limit(pager.Size).ToList();
var conversationDocs = _dc.Conversations.Find(filterDef).Sort(sortDef).Skip(pager.Offset).Limit(pager.Size).ToList();
var count = _dc.Conversations.CountDocuments(filterDef);
foreach (var conv in conversationDocs)