complete db on code scripts

This commit is contained in:
Jicheng Lu 2025-09-30 17:28:35 -05:00
parent 75d0cf1ae1
commit 82d2311018
15 changed files with 337 additions and 165 deletions

View file

@ -59,7 +59,6 @@ public interface IAgentService
/// <param name="agent"></param>
/// <returns></returns>
Task<string> PatchAgentTemplate(Agent agent);
Task<string> UpdateAgentFromFile(string id);
string GetDataDir();
string GetAgentDataDir(string agentId);

View file

@ -2,6 +2,8 @@ namespace BotSharp.Abstraction.Agents.Models;
public class AgentCodeScript
{
public string Id { get; set; }
public string AgentId { get; set; }
public string Name { get; set; }
public string Content { get; set; }
@ -9,12 +11,6 @@ public class AgentCodeScript
{
}
public AgentCodeScript(string name, string content)
{
Name = name;
Content = content;
}
public override string ToString()
{
return Name;

View file

@ -98,21 +98,24 @@ public interface IBotSharpRepository : IHaveServiceProvider
=> throw new NotImplementedException();
void InsertAgentTask(AgentTask task)
=> throw new NotImplementedException();
void BulkInsertAgentTasks(List<AgentTask> tasks)
void BulkInsertAgentTasks(string agentId, List<AgentTask> tasks)
=> throw new NotImplementedException();
void UpdateAgentTask(AgentTask task, AgentTaskField field)
=> throw new NotImplementedException();
bool DeleteAgentTask(string agentId, List<string> taskIds)
=> throw new NotImplementedException();
bool DeleteAgentTasks()
bool DeleteAgentTasks(string agentId, List<string>? taskIds = null)
=> throw new NotImplementedException();
#endregion
#region Agent Code
List<AgentCodeScript> GetAgentCodeScripts(string agentId, List<string>? scriptNames = null)
=> throw new NotImplementedException();
string? GetAgentCodeScript(string agentId, string scriptName)
=> throw new NotImplementedException();
bool PatchAgentCodeScript(string agentId, AgentCodeScript script)
bool UpdateAgentCodeScript(string agentId, AgentCodeScript script)
=> throw new NotImplementedException();
bool BulkInsertAgentCodeScripts(string agentId, List<AgentCodeScript> scripts)
=> throw new NotImplementedException();
bool DeleteAgentCodeScripts(string agentId, List<string>? scriptNames)
=> throw new NotImplementedException();
#endregion

View file

@ -218,4 +218,28 @@ public partial class AgentService
task.Content = content.Substring(suffix.Length).Trim();
return task;
}
private List<AgentCodeScript> GetCodeScriptsFromFile(string fileDir)
{
var scripts = new List<AgentCodeScript>();
var codeDir = Path.Combine(fileDir, "codes");
if (!Directory.Exists(codeDir))
{
return scripts;
}
var agentId = fileDir.Split(Path.DirectorySeparatorChar).Last();
foreach (var file in Directory.GetFiles(codeDir))
{
var script = new AgentCodeScript
{
AgentId = agentId,
Name = Path.GetFileName(file),
Content = File.ReadAllText(file)
};
scripts.Add(script);
}
return scripts;
}
}

View file

@ -60,13 +60,16 @@ public partial class AgentService
.SetSamples(samples);
var tasks = GetTasksFromFile(dir);
var codeScripts = GetCodeScriptsFromFile(dir);
var isAgentDeleted = _db.DeleteAgent(agent.Id);
if (isAgentDeleted)
{
await Task.Delay(100);
_db.BulkInsertAgents(new List<Agent> { agent });
_db.BulkInsertAgentTasks(tasks);
_db.BulkInsertAgents([agent]);
_db.BulkInsertAgentTasks(agent.Id, tasks);
_db.BulkInsertAgentCodeScripts(agent.Id, codeScripts);
refreshedAgents.Add(agent.Name);
_logger.LogInformation($"Agent {agent.Name} has been migrated.");
}

View file

@ -1,8 +1,5 @@
using BotSharp.Abstraction.Repositories.Enums;
using BotSharp.Abstraction.Repositories.Settings;
using BotSharp.Abstraction.Users.Enums;
using BotSharp.Abstraction.Users.Models;
using System.IO;
namespace BotSharp.Core.Agents.Services;
@ -13,7 +10,7 @@ public partial class AgentService
if (agent == null || string.IsNullOrEmpty(agent.Id)) return;
var userService = _services.GetRequiredService<IUserService>();
var auth = await userService.GetUserAuthorizations(new List<string> { agent.Id });
var auth = await userService.GetUserAuthorizations([agent.Id]);
var allowEdit = auth.IsAgentActionAllowed(agent.Id, UserAction.Edit);
if (!allowEdit)
@ -57,81 +54,6 @@ public partial class AgentService
await Task.CompletedTask;
}
public async Task<string> UpdateAgentFromFile(string id)
{
string updateResult;
var dbSettings = _services.GetRequiredService<BotSharpDatabaseSettings>();
var agentSettings = _services.GetRequiredService<AgentSettings>();
if (dbSettings.Default == RepositoryEnum.FileRepository)
{
updateResult = $"Invalid database repository setting: {dbSettings.Default}";
_logger.LogWarning(updateResult);
return updateResult;
}
var agent = _db.GetAgent(id);
if (agent == null)
{
updateResult = $"Cannot find agent ${id}";
_logger.LogError(updateResult);
return updateResult;
}
var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
dbSettings.FileRepository,
agentSettings.DataDir);
var clonedAgent = Agent.Clone(agent);
var foundAgent = GetAgentFileById(agent.Id, filePath);
if (foundAgent == null)
{
updateResult = $"Cannot find agent {agent.Name} in file directory: {filePath}";
_logger.LogError(updateResult);
return updateResult;
}
try
{
clonedAgent.SetId(foundAgent.Id)
.SetName(foundAgent.Name)
.SetType(foundAgent.Type)
.SetRoutingMode(foundAgent.Mode)
.SetFuncVisMode(foundAgent.FuncVisMode)
.SetIsPublic(foundAgent.IsPublic)
.SetDisabled(foundAgent.Disabled)
.SetDescription(foundAgent.Description)
.SetMergeUtility(foundAgent.MergeUtility)
.SetProfiles(foundAgent.Profiles)
.SetLabels(foundAgent.Labels)
.SetRoutingRules(foundAgent.RoutingRules)
.SetInstruction(foundAgent.Instruction)
.SetChannelInstructions(foundAgent.ChannelInstructions)
.SetTemplates(foundAgent.Templates)
.SetFunctions(foundAgent.Functions)
.SetResponses(foundAgent.Responses)
.SetSamples(foundAgent.Samples)
.SetUtilities(foundAgent.Utilities)
.SetMcpTools(foundAgent.McpTools)
.SetKnowledgeBases(foundAgent.KnowledgeBases)
.SetRules(foundAgent.Rules)
.SetLlmConfig(foundAgent.LlmConfig);
_db.UpdateAgent(clonedAgent, AgentField.All);
Utilities.ClearCache();
updateResult = $"Agent {agent.Name} has been migrated!";
_logger.LogInformation(updateResult);
return updateResult;
}
catch (Exception ex)
{
updateResult = $"Failed to migrate agent {agent.Name} in file directory {filePath}.\r\nError: {ex.Message}";
_logger.LogError(updateResult);
return updateResult;
}
}
public async Task<string> PatchAgentTemplate(Agent agent)
{
@ -184,31 +106,4 @@ public partial class AgentService
return patchResult;
}
private Agent? GetAgentFileById(string agentId, string filePath)
{
if (!Directory.Exists(filePath)) return null;
foreach (var dir in Directory.GetDirectories(filePath))
{
var agentJson = File.ReadAllText(Path.Combine(dir, "agent.json"));
var agent = JsonSerializer.Deserialize<Agent>(agentJson, _options);
if (agent != null && agent.Id == agentId)
{
var (defaultInstruction, channelInstructions) = GetInstructionsFromFile(dir);
var functions = GetFunctionsFromFile(dir);
var responses = GetResponsesFromFile(dir);
var templates = GetTemplatesFromFile(dir);
var samples = GetSamplesFromFile(dir);
return agent.SetInstruction(defaultInstruction)
.SetChannelInstructions(channelInstructions)
.SetTemplates(templates)
.SetFunctions(functions)
.SetResponses(responses)
.SetSamples(samples);
}
}
return null;
}
}

View file

@ -5,6 +5,39 @@ namespace BotSharp.Core.Repository;
public partial class FileRepository
{
#region Code
public List<AgentCodeScript> GetAgentCodeScripts(string agentId, List<string>? scriptNames = null)
{
if (string.IsNullOrWhiteSpace(agentId))
{
return [];
}
var dir = BuildAgentCodeDir(agentId);
if (!Directory.Exists(dir))
{
return [];
}
var results = new List<AgentCodeScript>();
foreach (var file in Directory.GetFiles(dir))
{
var fileName = Path.GetFileName(file);
if (scriptNames != null || !scriptNames.Contains(fileName))
{
continue;
}
var script = new AgentCodeScript
{
AgentId = agentId,
Name = fileName,
Content = File.ReadAllText(file)
};
results.Add(script);
}
return results;
}
public string? GetAgentCodeScript(string agentId, string scriptName)
{
if (string.IsNullOrWhiteSpace(agentId)
@ -13,7 +46,7 @@ public partial class FileRepository
return null;
}
var dir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId, AGENT_CODES_FOLDER);
var dir = BuildAgentCodeDir(agentId);
if (!Directory.Exists(dir))
{
return null;
@ -30,14 +63,14 @@ public partial class FileRepository
return string.Empty;
}
public bool PatchAgentCodeScript(string agentId, AgentCodeScript script)
public bool UpdateAgentCodeScript(string agentId, AgentCodeScript script)
{
if (string.IsNullOrEmpty(agentId) || script == null)
if (string.IsNullOrWhiteSpace(agentId) || script == null)
{
return false;
}
var dir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId, AGENT_CODES_FOLDER);
var dir = BuildAgentCodeDir(agentId);
if (!Directory.Exists(dir))
{
return false;
@ -57,5 +90,71 @@ public partial class FileRepository
File.WriteAllText(found, script.Content);
return true;
}
public bool BulkInsertAgentCodeScripts(string agentId, List<AgentCodeScript> scripts)
{
if (string.IsNullOrWhiteSpace(agentId) || scripts.IsNullOrEmpty())
{
return false;
}
var dir = BuildAgentCodeDir(agentId);
if (!Directory.Exists(dir))
{
return false;
}
foreach (var script in scripts)
{
if (string.IsNullOrWhiteSpace(script.Name))
{
continue;
}
var path = Path.Combine(dir, script.Name);
File.WriteAllText(path, script.Content);
}
return true;
}
public bool DeleteAgentCodeScripts(string agentId, List<string>? scriptNames)
{
if (string.IsNullOrWhiteSpace(agentId))
{
return false;
}
var dir = BuildAgentCodeDir(agentId);
if (!Directory.Exists(dir))
{
return false;
}
if (scriptNames == null)
{
Directory.Delete(dir, true);
return true;
}
else if (!scriptNames.Any())
{
return false;
}
foreach (var file in Directory.GetFiles(dir))
{
var fileName = Path.GetFileName(file);
if (scriptNames.Contains(fileName))
{
File.Delete(file);
}
}
return true;
}
#endregion
private string BuildAgentCodeDir(string agentId)
{
return Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId, AGENT_CODES_FOLDER);
}
}

View file

@ -137,7 +137,7 @@ public partial class FileRepository
File.WriteAllText(taskFile, fileContent);
}
public void BulkInsertAgentTasks(List<AgentTask> tasks)
public void BulkInsertAgentTasks(string agentId, List<AgentTask> tasks)
{
}
@ -194,13 +194,25 @@ public partial class FileRepository
File.WriteAllText(taskFile, fileContent);
}
public bool DeleteAgentTask(string agentId, List<string> taskIds)
public bool DeleteAgentTasks(string agentId, List<string>? taskIds = null)
{
var agentDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId);
if (!Directory.Exists(agentDir) || taskIds.IsNullOrEmpty()) return false;
if (!Directory.Exists(agentDir))
{
return false;
}
var taskDir = Path.Combine(agentDir, AGENT_TASKS_FOLDER);
if (!Directory.Exists(taskDir)) return false;
if (!Directory.Exists(taskDir))
{
return false;
}
if (taskIds == null)
{
Directory.Delete(taskDir, true);
return true;
}
var deletedTasks = new List<string>();
foreach (var taskId in taskIds)
@ -215,11 +227,6 @@ public partial class FileRepository
return deletedTasks.Any();
}
public bool DeleteAgentTasks()
{
return false;
}
private string? FindTaskFileById(string taskDir, string taskId)
{
if (!Directory.Exists(taskDir) || string.IsNullOrEmpty(taskId)) return null;

View file

@ -91,7 +91,7 @@ public class AgentTaskService : IAgentTaskService
public async Task<bool> DeleteTask(string agentId, string taskId)
{
var db = _services.GetRequiredService<IBotSharpRepository>();
var isDeleted = db.DeleteAgentTask(agentId, new List<string> { taskId });
var isDeleted = db.DeleteAgentTasks(agentId, new List<string> { taskId });
return await Task.FromResult(isDeleted);
}
}

View file

@ -115,12 +115,6 @@ public class AgentController : ControllerBase
return await _agentService.RefreshAgents(request?.AgentIds);
}
[HttpPut("/agent/file/{agentId}")]
public async Task<string> UpdateAgentFromFile([FromRoute] string agentId)
{
return await _agentService.UpdateAgentFromFile(agentId);
}
[HttpPut("/agent/{agentId}")]
public async Task UpdateAgent([FromRoute] string agentId, [FromBody] AgentUpdateModel agent)
{

View file

@ -0,0 +1,32 @@
using BotSharp.Abstraction.Agents.Models;
namespace BotSharp.Plugin.MongoStorage.Collections;
public class AgentCodeDocument : MongoBase
{
public string AgentId { get; set; } = default!;
public string Name { get; set; } = default!;
public string Content { get; set; } = default!;
public static AgentCodeDocument ToMongoModel(AgentCodeScript script)
{
return new AgentCodeDocument
{
Id = script.Id,
AgentId = script.AgentId,
Name = script.Name,
Content = script.Content
};
}
public static AgentCodeScript ToDomainModel(AgentCodeDocument script)
{
return new AgentCodeScript
{
Id = script.Id,
AgentId = script.AgentId,
Name = script.Name,
Content = script.Content
};
}
}

View file

@ -160,6 +160,9 @@ public class MongoDbContext
public IMongoCollection<AgentTaskDocument> AgentTasks
=> CreateAgentTaskIndex();
public IMongoCollection<AgentCodeDocument> AgentCodes
=> GetCollectionOrCreate<AgentCodeDocument>("AgentCodes");
public IMongoCollection<ConversationDocument> Conversations
=> CreateConversationIndex();

View file

@ -2,6 +2,7 @@ using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Functions.Models;
using BotSharp.Abstraction.Repositories.Filters;
using BotSharp.Abstraction.Routing.Models;
using MongoDB.Driver;
namespace BotSharp.Plugin.MongoStorage.Repository;
@ -593,6 +594,8 @@ public partial class MongoRepository
{
_dc.UserAgents.DeleteMany(Builders<UserAgentDocument>.Filter.Empty);
_dc.RoleAgents.DeleteMany(Builders<RoleAgentDocument>.Filter.Empty);
_dc.AgentTasks.DeleteMany(Builders<AgentTaskDocument>.Filter.Empty);
_dc.AgentCodes.DeleteMany(Builders<AgentCodeDocument>.Filter.Empty);
_dc.Agents.DeleteMany(Builders<AgentDocument>.Filter.Empty);
return true;
}
@ -612,11 +615,13 @@ public partial class MongoRepository
var userAgentFilter = Builders<UserAgentDocument>.Filter.Eq(x => x.AgentId, agentId);
var roleAgentFilter = Builders<RoleAgentDocument>.Filter.Eq(x => x.AgentId, agentId);
var agentTaskFilter = Builders<AgentTaskDocument>.Filter.Eq(x => x.AgentId, agentId);
var agentCodeFilter = Builders<AgentCodeDocument>.Filter.Eq(x => x.AgentId, agentId);
_dc.Agents.DeleteOne(agentFilter);
_dc.UserAgents.DeleteMany(userAgentFilter);
_dc.RoleAgents.DeleteMany(roleAgentFilter);
_dc.AgentTasks.DeleteMany(agentTaskFilter);
_dc.AgentCodes.DeleteMany(agentCodeFilter);
_dc.Agents.DeleteOne(agentFilter);
return true;
}
catch

View file

@ -0,0 +1,116 @@
using BotSharp.Abstraction.Agents.Models;
namespace BotSharp.Plugin.MongoStorage.Repository;
public partial class MongoRepository
{
#region Code
public List<AgentCodeScript> GetAgentCodeScripts(string agentId, List<string>? scriptNames = null)
{
if (string.IsNullOrWhiteSpace(agentId))
{
return [];
}
var builder = Builders<AgentCodeDocument>.Filter;
var filters = new List<FilterDefinition<AgentCodeDocument>>()
{
builder.Eq(x => x.AgentId, agentId)
};
if (!scriptNames.IsNullOrEmpty())
{
filters.Add(builder.In(x => x.Name, scriptNames));
}
var found = _dc.AgentCodes.Find(builder.And(filters)).ToList();
return found.Select(x => AgentCodeDocument.ToDomainModel(x)).ToList();
}
public string? GetAgentCodeScript(string agentId, string scriptName)
{
if (string.IsNullOrWhiteSpace(agentId)
|| string.IsNullOrWhiteSpace(scriptName))
{
return null;
}
var builder = Builders<AgentCodeDocument>.Filter;
var filters = new List<FilterDefinition<AgentCodeDocument>>()
{
builder.Eq(x => x.AgentId, agentId),
builder.Eq(x => x.Name, scriptName)
};
var found = _dc.AgentCodes.Find(builder.And(filters)).FirstOrDefault();
return found?.Content;
}
public bool UpdateAgentCodeScript(string agentId, AgentCodeScript script)
{
if (string.IsNullOrWhiteSpace(agentId) || script == null)
{
return false;
}
var builder = Builders<AgentCodeDocument>.Filter;
var filters = new List<FilterDefinition<AgentCodeDocument>>()
{
builder.Eq(x => x.AgentId, agentId),
builder.Eq(x => x.Name, script.Name)
};
var filterDef = builder.And(filters);
var found = _dc.AgentCodes.Find(filterDef).FirstOrDefault();
if (found == null)
{
return false;
}
var update = Builders<AgentCodeDocument>.Update.Set(x => x.Content, script.Content);
_dc.AgentCodes.UpdateOne(filterDef, update);
return true;
}
public bool InsertAgentCodeScripts(string agentId, List<AgentCodeScript> scripts)
{
if (string.IsNullOrWhiteSpace(agentId) || scripts.IsNullOrEmpty())
{
return false;
}
var docs = scripts.Select(x =>
{
var script = AgentCodeDocument.ToMongoModel(x);
script.AgentId = agentId;
script.Id = !string.IsNullOrEmpty(x.Id) ? x.Id : Guid.NewGuid().ToString();
return script;
}).ToList();
_dc.AgentCodes.InsertMany(docs);
return true;
}
public bool BulkInsertAgentCodeScripts(string agentId, List<string>? scriptNames)
{
if (string.IsNullOrWhiteSpace(agentId))
{
return false;
}
var filterDef = Builders<AgentCodeDocument>.Filter.Empty;
if (scriptNames != null)
{
var builder = Builders<AgentCodeDocument>.Filter;
var filters = new List<FilterDefinition<AgentCodeDocument>>
{
builder.In(x => x.Name, scriptNames)
};
filterDef = builder.And(filters);
}
var deleted = _dc.AgentCodes.DeleteMany(filterDef);
return deleted.DeletedCount > 0;
}
#endregion
}

View file

@ -1,5 +1,6 @@
using BotSharp.Abstraction.Repositories.Filters;
using BotSharp.Abstraction.Tasks.Models;
using MongoDB.Driver;
namespace BotSharp.Plugin.MongoStorage.Repository;
@ -86,13 +87,17 @@ public partial class MongoRepository
_dc.AgentTasks.InsertOne(taskDoc);
}
public void BulkInsertAgentTasks(List<AgentTask> tasks)
public void BulkInsertAgentTasks(string agentId, List<AgentTask> tasks)
{
if (tasks.IsNullOrEmpty()) return;
if (string.IsNullOrWhiteSpace(agentId) || tasks.IsNullOrEmpty())
{
return;
}
var taskDocs = tasks.Select(x =>
{
var task = AgentTaskDocument.ToMongoModel(x);
task.AgentId = agentId;
task.Id = !string.IsNullOrEmpty(x.Id) ? x.Id : Guid.NewGuid().ToString();
return task;
}).ToList();
@ -138,30 +143,21 @@ public partial class MongoRepository
_dc.AgentTasks.ReplaceOne(filter, taskDoc);
}
public bool DeleteAgentTask(string agentId, List<string> taskIds)
public bool DeleteAgentTasks(string agentId, List<string>? taskIds = null)
{
if (taskIds.IsNullOrEmpty()) return false;
var builder = Builders<AgentTaskDocument>.Filter;
var filters = new List<FilterDefinition<AgentTaskDocument>>
var filterDef = Builders<AgentTaskDocument>.Filter.Empty;
if (taskIds != null)
{
builder.In(x => x.Id, taskIds)
};
var taskDeleted = _dc.AgentTasks.DeleteMany(builder.And(filters));
var builder = Builders<AgentTaskDocument>.Filter;
var filters = new List<FilterDefinition<AgentTaskDocument>>
{
builder.In(x => x.Id, taskIds)
};
filterDef = builder.And(filters);
}
var taskDeleted = _dc.AgentTasks.DeleteMany(filterDef);
return taskDeleted.DeletedCount > 0;
}
public bool DeleteAgentTasks()
{
try
{
_dc.AgentTasks.DeleteMany(Builders<AgentTaskDocument>.Filter.Empty);
return true;
}
catch
{
return false;
}
}
#endregion
}