refine repository for agent code script

This commit is contained in:
Jicheng Lu 2025-10-06 01:27:18 -05:00
parent 74d0c96e2f
commit 5be85d3f4b
29 changed files with 494 additions and 385 deletions

View file

@ -0,0 +1,7 @@
namespace BotSharp.Abstraction.Agents.Enums;
public static class AgentCodeScriptType
{
public const string Src = "src";
public const string Test = "test";
}

View file

@ -1,6 +1,6 @@
namespace BotSharp.Abstraction.Agents.Enums;
public class AgentFuncVisMode
public static class AgentFuncVisMode
{
public const string Manual = "manual";
public const string Auto = "auto";

View file

@ -1,6 +1,6 @@
namespace BotSharp.Abstraction.Agents.Enums;
public class AgentRole
public static class AgentRole
{
public const string System = "system";
public const string Assistant = "assistant";

View file

@ -1,6 +1,6 @@
namespace BotSharp.Abstraction.Agents.Enums;
public class AgentType
public static class AgentType
{
/// <summary>
/// Routing agent

View file

@ -1,6 +1,6 @@
namespace BotSharp.Abstraction.Agents.Enums;
public class BuiltInAgentId
public static class BuiltInAgentId
{
/// <summary>
/// A routing agent can be used as a base router.

View file

@ -1,18 +1,29 @@
namespace BotSharp.Abstraction.Agents.Models;
public class AgentCodeScript
public class AgentCodeScript : AgentCodeScriptBase
{
public string Id { get; set; }
public string AgentId { get; set; }
public string Name { get; set; }
public string Content { get; set; }
public string AgentId { get; set; } = null!;
public AgentCodeScript()
public AgentCodeScript() : base()
{
}
public override string ToString()
{
return Name;
return $"{CodePath}";
}
}
public class AgentCodeScriptBase
{
public string Name { get; set; } = null!;
public string Content { get; set; } = null!;
/// <summary>
/// Code script type: src, test
/// </summary>
public string ScriptType { get; set; } = null!;
public string CodePath => $"{ScriptType}/{Name}";
}

View file

@ -1,6 +1,6 @@
namespace BotSharp.Abstraction.Conversations.Enums;
public class ConversationChannel
public static class ConversationChannel
{
public const string WebChat = "webchat";
public const string OpenAPI = "openapi";

View file

@ -1,6 +1,6 @@
namespace BotSharp.Abstraction.Conversations.Enums;
public class ConversationStatus
public static class ConversationStatus
{
public const string Open = "open";
public const string Closed = "closed";

View file

@ -1,6 +1,6 @@
namespace BotSharp.Abstraction.Conversations.Enums;
public class StateDataType
public static class StateDataType
{
public const string String = "string";
public const string Boolean = "boolean";

View file

@ -1,6 +1,6 @@
namespace BotSharp.Abstraction.Conversations.Enums;
public class StateSource
public static class StateSource
{
public const string External = "external";
public const string Application = "application";

View file

@ -1,6 +1,6 @@
namespace BotSharp.Abstraction.Infrastructures.Enums;
public class LanguageType
public static class LanguageType
{
public const string UNKNOWN = "Unknown";
public const string ENGLISH = "English";

View file

@ -1,6 +1,6 @@
namespace BotSharp.Abstraction.Infrastructures.Enums;
public class StateConst
public static class StateConst
{
public const string EXPECTED_ACTION_AGENT = "expected_next_action_agent";
public const string EXPECTED_GOAL_AGENT = "expected_user_goal_agent";

View file

@ -5,7 +5,10 @@ namespace BotSharp.Abstraction.Instructs;
public interface IInstructHook : IHookBase
{
Task BeforeCompletion(Agent agent, RoleDialogModel message);
Task AfterCompletion(Agent agent, InstructResult result);
Task OnResponseGenerated(InstructResponseModel response);
Task BeforeCompletion(Agent agent, RoleDialogModel message) => Task.CompletedTask;
Task AfterCompletion(Agent agent, InstructResult result) => Task.CompletedTask;
Task OnResponseGenerated(InstructResponseModel response) => Task.CompletedTask;
Task BeforeCodeExecution(Agent agent, RoleDialogModel message, CodeInstructContext context) => Task.CompletedTask;
Task AfterCodeExecution(Agent agent, InstructResult result) => Task.CompletedTask;
}

View file

@ -0,0 +1,6 @@
namespace BotSharp.Abstraction.Instructs.Models;
public class CodeInstructContext
{
public List<KeyValue> Arguments { get; set; } = [];
}

View file

@ -0,0 +1,12 @@
namespace BotSharp.Abstraction.Repositories.Filters;
public class AgentCodeScriptFilter
{
public List<string>? ScriptNames { get; set; }
public List<string>? ScriptTypes { get; set; }
public static AgentCodeScriptFilter Empty()
{
return new AgentCodeScriptFilter();
}
}

View file

@ -107,15 +107,15 @@ public interface IBotSharpRepository : IHaveServiceProvider
#endregion
#region Agent Code
List<AgentCodeScript> GetAgentCodeScripts(string agentId, List<string>? scriptNames = null)
List<AgentCodeScript> GetAgentCodeScripts(string agentId, AgentCodeScriptFilter? filter = null)
=> throw new NotImplementedException();
string? GetAgentCodeScript(string agentId, string scriptName)
string? GetAgentCodeScript(string agentId, string scriptName, string scriptType = AgentCodeScriptType.Src)
=> throw new NotImplementedException();
bool UpdateAgentCodeScripts(string agentId, List<AgentCodeScript> scripts)
=> throw new NotImplementedException();
bool BulkInsertAgentCodeScripts(string agentId, List<AgentCodeScript> scripts)
=> throw new NotImplementedException();
bool DeleteAgentCodeScripts(string agentId, List<string>? scriptNames)
bool DeleteAgentCodeScripts(string agentId, List<AgentCodeScript>? scripts = null)
=> throw new NotImplementedException();
#endregion

View file

@ -1,6 +1,6 @@
namespace BotSharp.Abstraction.Routing.Enums;
public class RoutingMode
public static class RoutingMode
{
public const string Eager = "eager";
public const string Lazy = "lazy";

View file

@ -1,6 +1,6 @@
namespace BotSharp.Abstraction.Routing.Enums;
public class RuleType
public static class RuleType
{
/// <summary>
/// Fallback to redirect agent

View file

@ -1,7 +1,7 @@
/// <summary>
/// Agent task status
/// </summary>
public class TaskStatus
public static class TaskStatus
{
public const string Scheduled = "scheduled";
public const string New = "new";

View file

@ -229,12 +229,22 @@ public partial class AgentService
}
var agentId = fileDir.Split(Path.DirectorySeparatorChar).Last();
scripts = Directory.GetFiles(codeDir).Select(file => new AgentCodeScript
foreach (var folder in Directory.EnumerateDirectories(codeDir))
{
var scriptType = folder.Split(Path.DirectorySeparatorChar).Last();
foreach (var file in Directory.EnumerateFiles(folder))
{
scripts.Add(new AgentCodeScript
{
AgentId = agentId,
Name = Path.GetFileName(file),
ScriptType = scriptType,
Content = File.ReadAllText(file)
}).ToList();
});
}
}
return scripts;
}
}

View file

@ -40,9 +40,12 @@ public partial class InstructService
}
var provider = string.Empty;
var model = string.Empty;
var prompt = string.Empty;
// Run code template
var codeResponse = await GetCodeResponse(agent, message, templateName, codeOptions);
if (codeResponse != null)
{
return codeResponse;
}
// Before completion hooks
@ -63,16 +66,11 @@ public partial class InstructService
}
// Run code template
var (text, isCodeComplete) = await GetCodeResponse(agentId, templateName, codeOptions);
if (isCodeComplete)
{
response.Text = text;
}
else
{
var provider = string.Empty;
var model = string.Empty;
// Render prompt
prompt = string.IsNullOrEmpty(templateName) ?
var prompt = string.IsNullOrEmpty(templateName) ?
agentService.RenderInstruction(agent) :
agentService.RenderTemplate(agent, templateName);
@ -115,14 +113,11 @@ public partial class InstructService
});
response.Text = result.Content;
}
}
// After completion hooks
foreach (var hook in hooks)
{
await hook.AfterCompletion(agent, response);
if (!isCodeComplete)
{
await hook.OnResponseGenerated(new InstructResponseModel
{
AgentId = agentId,
@ -134,25 +129,31 @@ public partial class InstructService
CompletionText = response.Text
});
}
}
return response;
}
/// <summary>
/// Get code response => return: (response text, whether code execution is completed)
/// Get code response
/// </summary>
/// <param name="agentId"></param>
/// <param name="agent"></param>
/// <param name="message"></param>
/// <param name="templateName"></param>
/// <param name="codeOptions"></param>
/// <returns></returns>
private async Task<(string?, bool)> GetCodeResponse(string agentId, string templateName, CodeInstructOptions? codeOptions)
private async Task<InstructResult?> GetCodeResponse(Agent agent, RoleDialogModel message, string templateName, CodeInstructOptions? codeOptions)
{
InstructResult? response = null;
if (agent == null)
{
return response;
}
var state = _services.GetRequiredService<IConversationStateService>();
var db = _services.GetRequiredService<IBotSharpRepository>();
var isComplete = false;
var response = string.Empty;
var hooks = _services.GetHooks<IInstructHook>(agent.Id);
var codeProvider = codeOptions?.CodeInterpretProvider.IfNullOrEmptyAs("botsharp-py-interpreter");
var codeInterpreter = _services.GetServices<ICodeInterpretService>()
@ -161,9 +162,9 @@ public partial class InstructService
if (codeInterpreter == null)
{
#if DEBUG
_logger.LogWarning($"No code interpreter found. (Agent: {agentId}, Code interpreter: {codeProvider})");
_logger.LogWarning($"No code interpreter found. (Agent: {agent.Id}, Code interpreter: {codeProvider})");
#endif
return (response, isComplete);
return response;
}
// Get code script name
@ -180,19 +181,19 @@ public partial class InstructService
if (string.IsNullOrEmpty(scriptName))
{
#if DEBUG
_logger.LogWarning($"Empty code script name. (Agent: {agentId}, {scriptName})");
_logger.LogWarning($"Empty code script name. (Agent: {agent.Id}, {scriptName})");
#endif
return (response, isComplete);
return response;
}
// Get code script
var codeScript = db.GetAgentCodeScript(agentId, scriptName);
var codeScript = db.GetAgentCodeScript(agent.Id, scriptName, scriptType: AgentCodeScriptType.Src);
if (string.IsNullOrWhiteSpace(codeScript))
{
#if DEBUG
_logger.LogWarning($"Empty code script. (Agent: {agentId}, {scriptName})");
_logger.LogWarning($"Empty code script. (Agent: {agent.Id}, {scriptName})");
#endif
return (response, isComplete);
return response;
}
// Get code arguments
@ -202,14 +203,55 @@ public partial class InstructService
arguments = state.GetStates().Select(x => new KeyValue(x.Key, x.Value)).ToList();
}
var context = new CodeInstructContext
{
Arguments = arguments
};
// Before code execution
foreach (var hook in hooks)
{
await hook.BeforeCodeExecution(agent, message, context);
// Interrupted by hook
if (message.StopCompletion)
{
return new InstructResult
{
MessageId = message.MessageId,
Text = message.Content
};
}
}
// Run code script
var result = await codeInterpreter.RunCode(codeScript, options: new()
{
Arguments = arguments
Arguments = context.Arguments
});
response = result?.Result?.ToString();
isComplete = true;
return (response, isComplete);
response = new InstructResult
{
MessageId = message.MessageId,
Text = result?.Result?.ToString()
};
// After code execution
foreach (var hook in hooks)
{
await hook.AfterCodeExecution(agent, response);
await hook.OnResponseGenerated(new InstructResponseModel
{
AgentId = agent.Id,
Provider = codeInterpreter.Provider,
Model = string.Empty,
TemplateName = scriptName,
UserMessage = string.Empty,
SystemInstruction = string.Empty,
CompletionText = response.Text
});
}
return response;
}
}

View file

@ -1,161 +0,0 @@
using System.IO;
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)
|| string.IsNullOrWhiteSpace(scriptName))
{
return null;
}
var dir = BuildAgentCodeDir(agentId);
if (!Directory.Exists(dir))
{
return null;
}
foreach (var file in Directory.GetFiles(dir))
{
var fileName = Path.GetFileName(file);
if (scriptName.IsEqualTo(fileName))
{
return File.ReadAllText(file);
}
}
return string.Empty;
}
public bool UpdateAgentCodeScripts(string agentId, List<AgentCodeScript> scripts)
{
if (string.IsNullOrWhiteSpace(agentId) || scripts.IsNullOrEmpty())
{
return false;
}
var dir = BuildAgentCodeDir(agentId);
if (!Directory.Exists(dir))
{
return false;
}
var dict = scripts.DistinctBy(x => x.Name).ToDictionary(x => x.Name, x => x);
var files = Directory.GetFiles(dir).Where(x => dict.Keys.Contains(Path.GetFileName(x))).ToList();
foreach (var file in files)
{
if (dict.TryGetValue(Path.GetFileName(file), out var script))
{
File.WriteAllText(file, 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
#region Private methods
private string BuildAgentCodeDir(string agentId)
{
return Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId, AGENT_CODES_FOLDER);
}
#endregion
}

View file

@ -0,0 +1,157 @@
using System.IO;
namespace BotSharp.Core.Repository;
public partial class FileRepository
{
#region Code
public List<AgentCodeScript> GetAgentCodeScripts(string agentId, AgentCodeScriptFilter? filter = null)
{
if (string.IsNullOrWhiteSpace(agentId))
{
return [];
}
var dir = BuildAgentCodeScriptDir(agentId);
if (!Directory.Exists(dir))
{
return [];
}
filter ??= AgentCodeScriptFilter.Empty();
var results = new List<AgentCodeScript>();
foreach (var folder in Directory.EnumerateDirectories(dir))
{
var scriptType = folder.Split(Path.DirectorySeparatorChar).Last();
if (filter.ScriptTypes != null && !filter.ScriptTypes.Contains(scriptType))
{
continue;
}
foreach (var file in Directory.EnumerateFiles(folder))
{
var fileName = Path.GetFileName(file);
if (filter.ScriptNames != null && !filter.ScriptNames.Contains(fileName))
{
continue;
}
results.Add(new AgentCodeScript
{
AgentId = agentId,
Name = fileName,
ScriptType = scriptType,
Content = File.ReadAllText(file)
});
}
}
return results;
}
public string? GetAgentCodeScript(string agentId, string scriptName, string scriptType = AgentCodeScriptType.Src)
{
if (string.IsNullOrWhiteSpace(agentId)
|| string.IsNullOrWhiteSpace(scriptName)
|| string.IsNullOrWhiteSpace(scriptType))
{
return null;
}
var dir = BuildAgentCodeScriptDir(agentId, scriptType);
if (!Directory.Exists(dir))
{
return null;
}
var foundFile = Directory.GetFiles(dir).FirstOrDefault(file => scriptName.IsEqualTo(Path.GetFileName(file)));
if (!string.IsNullOrEmpty(foundFile))
{
return File.ReadAllText(foundFile);
}
return string.Empty;
}
public bool UpdateAgentCodeScripts(string agentId, List<AgentCodeScript> scripts)
{
if (string.IsNullOrWhiteSpace(agentId) || scripts.IsNullOrEmpty())
{
return false;
}
foreach (var script in scripts)
{
if (string.IsNullOrWhiteSpace(script.Name)
|| string.IsNullOrWhiteSpace(script.ScriptType))
{
continue;
}
var dir = BuildAgentCodeScriptDir(agentId, script.ScriptType);
if (!Directory.Exists(dir))
{
continue;
}
var file = Path.Combine(dir, script.Name);
File.WriteAllText(file, script.Content);
}
return true;
}
public bool BulkInsertAgentCodeScripts(string agentId, List<AgentCodeScript> scripts)
{
return UpdateAgentCodeScripts(agentId, scripts);
}
public bool DeleteAgentCodeScripts(string agentId, List<AgentCodeScript>? scripts = null)
{
if (string.IsNullOrWhiteSpace(agentId))
{
return false;
}
var dir = BuildAgentCodeScriptDir(agentId);
if (!Directory.Exists(dir))
{
return false;
}
if (scripts == null)
{
Directory.Delete(dir, true);
return true;
}
else if (!scripts.Any())
{
return false;
}
var dict = scripts.DistinctBy(x => x.CodePath).ToDictionary(x => x.CodePath, x => x);
foreach (var pair in dict)
{
var file = Path.Combine(dir, pair.Value.ScriptType, pair.Value.Name);
if (File.Exists(file))
{
File.Delete(file);
}
}
return true;
}
#endregion
#region Private methods
private string BuildAgentCodeScriptDir(string agentId, string? scirptType = null)
{
var dir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId, AGENT_CODES_FOLDER);
if (!string.IsNullOrWhiteSpace(scirptType))
{
dir = Path.Combine(dir, scirptType);
}
return dir;
}
#endregion
}

View file

@ -2,6 +2,7 @@ using BotSharp.Abstraction.Instructs.Models;
using BotSharp.Abstraction.Instructs.Settings;
using BotSharp.Abstraction.Loggers.Models;
using BotSharp.Abstraction.Users;
using BotSharp.Abstraction.Utilities;
namespace BotSharp.Logger.Hooks;
@ -39,7 +40,9 @@ public class InstructionLogHook : InstructHookBase
var state = _services.GetRequiredService<IConversationStateService>();
var user = db.GetUserById(_user.Id);
var templateName = response.TemplateName ?? state.GetState("instruct_template_name") ?? null;
var templateName = response.TemplateName
.IfNullOrEmptyAs(state.GetState("instruct_template_name"))
.IfNullOrEmptyAs(null);
db.SaveInstructionLogs(new List<InstructionLogModel>
{

View file

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

View file

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

View file

@ -594,7 +594,7 @@ 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.AgentCodeScripts.DeleteMany(Builders<AgentCodeScriptDocument>.Filter.Empty);
_dc.Agents.DeleteMany(Builders<AgentDocument>.Filter.Empty);
return true;
}
@ -614,12 +614,12 @@ 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);
var agentCodeFilter = Builders<AgentCodeScriptDocument>.Filter.Eq(x => x.AgentId, agentId);
_dc.UserAgents.DeleteMany(userAgentFilter);
_dc.RoleAgents.DeleteMany(roleAgentFilter);
_dc.AgentTasks.DeleteMany(agentTaskFilter);
_dc.AgentCodes.DeleteMany(agentCodeFilter);
_dc.AgentCodeScripts.DeleteMany(agentCodeFilter);
_dc.Agents.DeleteOne(agentFilter);
return true;
}

View file

@ -1,113 +0,0 @@
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 UpdateAgentCodeScripts(string agentId, List<AgentCodeScript> scripts)
{
if (string.IsNullOrWhiteSpace(agentId) || scripts.IsNullOrEmpty())
{
return false;
}
var builder = Builders<AgentCodeDocument>.Filter;
var ops = scripts.Where(x => !string.IsNullOrWhiteSpace(x.Name))
.Select(x => new UpdateOneModel<AgentCodeDocument>(
builder.And(new List<FilterDefinition<AgentCodeDocument>>
{
builder.Eq(y => y.AgentId, agentId),
builder.Eq(y => y.Name, x.Name)
}),
Builders<AgentCodeDocument>.Update.Set(y => y.Content, x.Content)
))
.ToList();
var result = _dc.AgentCodes.BulkWrite(ops, new BulkWriteOptions { IsOrdered = false });
return result.ModifiedCount > 0 || result.MatchedCount > 0;
}
public bool BulkInsertAgentCodeScripts(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 DeleteAgentCodeScripts(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

@ -0,0 +1,129 @@
using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Repositories.Filters;
namespace BotSharp.Plugin.MongoStorage.Repository;
public partial class MongoRepository
{
#region Code
public List<AgentCodeScript> GetAgentCodeScripts(string agentId, AgentCodeScriptFilter? filter = null)
{
if (string.IsNullOrWhiteSpace(agentId))
{
return [];
}
filter ??= AgentCodeScriptFilter.Empty();
var builder = Builders<AgentCodeScriptDocument>.Filter;
var filters = new List<FilterDefinition<AgentCodeScriptDocument>>()
{
builder.Eq(x => x.AgentId, agentId)
};
if (!filter.ScriptNames.IsNullOrEmpty())
{
filters.Add(builder.In(x => x.Name, filter.ScriptNames));
}
if (!filter.ScriptTypes.IsNullOrEmpty())
{
filters.Add(builder.In(x => x.ScriptType, filter.ScriptTypes));
}
var found = _dc.AgentCodeScripts.Find(builder.And(filters)).ToList();
return found.Select(x => AgentCodeScriptDocument.ToDomainModel(x)).ToList();
}
public string? GetAgentCodeScript(string agentId, string scriptName, string scriptType = AgentCodeScriptType.Src)
{
if (string.IsNullOrWhiteSpace(agentId)
|| string.IsNullOrWhiteSpace(scriptName)
|| string.IsNullOrWhiteSpace(scriptType))
{
return null;
}
var builder = Builders<AgentCodeScriptDocument>.Filter;
var filters = new List<FilterDefinition<AgentCodeScriptDocument>>()
{
builder.Eq(x => x.AgentId, agentId),
builder.Eq(x => x.Name, scriptName),
builder.Eq(x => x.ScriptType, scriptType)
};
var found = _dc.AgentCodeScripts.Find(builder.And(filters)).FirstOrDefault();
return found?.Content;
}
public bool UpdateAgentCodeScripts(string agentId, List<AgentCodeScript> scripts)
{
if (string.IsNullOrWhiteSpace(agentId) || scripts.IsNullOrEmpty())
{
return false;
}
var builder = Builders<AgentCodeScriptDocument>.Filter;
var ops = scripts.Where(x => !string.IsNullOrWhiteSpace(x.Name))
.Select(x => new UpdateOneModel<AgentCodeScriptDocument>(
builder.And(new List<FilterDefinition<AgentCodeScriptDocument>>
{
builder.Eq(y => y.AgentId, agentId),
builder.Eq(y => y.Name, x.Name),
builder.Eq(y => y.ScriptType, x.ScriptType)
}),
Builders<AgentCodeScriptDocument>.Update.Set(y => y.Content, x.Content)
))
.ToList();
var result = _dc.AgentCodeScripts.BulkWrite(ops, new BulkWriteOptions { IsOrdered = false });
return result.ModifiedCount > 0 || result.MatchedCount > 0;
}
public bool BulkInsertAgentCodeScripts(string agentId, List<AgentCodeScript> scripts)
{
if (string.IsNullOrWhiteSpace(agentId) || scripts.IsNullOrEmpty())
{
return false;
}
var docs = scripts.Select(x =>
{
var script = AgentCodeScriptDocument.ToMongoModel(x);
script.AgentId = agentId;
script.Id = x.Id.IfNullOrEmptyAs(Guid.NewGuid().ToString());
return script;
}).ToList();
_dc.AgentCodeScripts.InsertMany(docs);
return true;
}
public bool DeleteAgentCodeScripts(string agentId, List<AgentCodeScript>? scripts = null)
{
if (string.IsNullOrWhiteSpace(agentId))
{
return false;
}
DeleteResult deleted;
if (scripts != null)
{
var scriptPaths = scripts.Select(x => x.CodePath);
var exprFilter = new BsonDocument("$expr", new BsonDocument("$in", new BsonArray
{
new BsonDocument("$concat", new BsonArray { "$ScriptType", "/", "$Name" }),
new BsonArray(scriptPaths)
}));
var filterDef = new BsonDocumentFilterDefinition<AgentCodeScriptDocument>(exprFilter);
deleted = _dc.AgentCodeScripts.DeleteMany(filterDef);
}
else
{
deleted = _dc.AgentCodeScripts.DeleteMany(Builders<AgentCodeScriptDocument>.Filter.Empty);
}
return deleted.DeletedCount > 0;
}
#endregion
}