diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs
index c52f2d958..b45ff557a 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs
@@ -1,4 +1,6 @@
using BotSharp.Abstraction.Agents.Options;
+using BotSharp.Abstraction.Coding.Models;
+using BotSharp.Abstraction.Coding.Options;
using BotSharp.Abstraction.Functions.Models;
using BotSharp.Abstraction.Plugins.Models;
using BotSharp.Abstraction.Repositories.Filters;
@@ -51,7 +53,7 @@ public interface IAgentService
/// Original agent information
Task GetAgent(string id);
- Task DeleteAgent(string id);
+ Task DeleteAgent(string id, AgentDeleteOptions? options = null);
Task UpdateAgent(Agent agent, AgentField updateField);
///
@@ -75,4 +77,10 @@ Task> GetAgentCodeScripts(string agentId, AgentCodeScriptF
Task UpdateAgentCodeScripts(string agentId, List codeScripts, AgentCodeScriptUpdateOptions? options = null)
=> Task.FromResult(false);
+
+ Task DeleteAgentCodeScripts(string agentId, List? codeScripts = null)
+ => Task.FromResult(false);
+
+ Task GenerateCodeScript(string agentId, string text, CodeProcessOptions? options = null)
+ => Task.FromResult(new CodeGenerationResult());
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentRule.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentRule.cs
index 87a08a894..75c0985a8 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentRule.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentRule.cs
@@ -3,11 +3,11 @@ namespace BotSharp.Abstraction.Agents.Models;
public class AgentRule
{
[JsonPropertyName("trigger_name")]
- public string TriggerName { get; set; }
+ public string TriggerName { get; set; } = string.Empty;
[JsonPropertyName("disabled")]
public bool Disabled { get; set; }
[JsonPropertyName("criteria")]
- public string Criteria { get; set; }
+ public string Criteria { get; set; } = string.Empty;
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Options/AgentCodeScriptUpdateOptions.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Options/AgentCodeScriptUpdateOptions.cs
index 476e42fc9..153694e9d 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/Options/AgentCodeScriptUpdateOptions.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Options/AgentCodeScriptUpdateOptions.cs
@@ -4,5 +4,6 @@ namespace BotSharp.Abstraction.Agents.Options;
public class AgentCodeScriptUpdateOptions : AgentCodeScriptDbUpdateOptions
{
+ [JsonPropertyName("delete_if_not_included")]
public bool DeleteIfNotIncluded { get; set; }
-}
+}
\ No newline at end of file
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Options/AgentDeleteOptions.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Options/AgentDeleteOptions.cs
new file mode 100644
index 000000000..5df6737c7
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Options/AgentDeleteOptions.cs
@@ -0,0 +1,14 @@
+namespace BotSharp.Abstraction.Agents.Options;
+
+public class AgentDeleteOptions
+{
+ [JsonPropertyName("delete_role_agents")]
+ public bool DeleteRoleAgents { get; set; }
+
+ [JsonPropertyName("delete_user_agents")]
+ public bool DeleteUserAgents { get; set; }
+
+ [JsonPropertyName("to_delete_code_scripts")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public List? ToDeleteCodeScripts { get; set; }
+}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Chart/IBotSharpChartService.cs b/src/Infrastructure/BotSharp.Abstraction/Chart/IBotSharpChartService.cs
deleted file mode 100644
index 0e1cab8c4..000000000
--- a/src/Infrastructure/BotSharp.Abstraction/Chart/IBotSharpChartService.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using BotSharp.Abstraction.Chart.Models;
-using BotSharp.Abstraction.Chart.Options;
-
-namespace BotSharp.Abstraction.Chart;
-
-public interface IBotSharpChartService
-{
- public string Provider { get; }
-
- Task GetConversationChartData(string conversationId, string messageId, ChartDataOptions options)
- => throw new NotImplementedException();
-
- Task GetConversationChartCode(string conversationId, string messageId, ChartCodeOptions options)
- => throw new NotImplementedException();
-}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Chart/IChartProcessor.cs b/src/Infrastructure/BotSharp.Abstraction/Chart/IChartProcessor.cs
new file mode 100644
index 000000000..7f8cfd4d8
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/Chart/IChartProcessor.cs
@@ -0,0 +1,12 @@
+using BotSharp.Abstraction.Chart.Models;
+using BotSharp.Abstraction.Chart.Options;
+
+namespace BotSharp.Abstraction.Chart;
+
+public interface IChartProcessor
+{
+ public string Provider { get; }
+
+ Task GetConversationChartDataAsync(string conversationId, string messageId, ChartDataOptions? options = null)
+ => throw new NotImplementedException();
+}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Chart/Models/ChartCodeResult.cs b/src/Infrastructure/BotSharp.Abstraction/Chart/Models/ChartCodeResult.cs
deleted file mode 100644
index 143ba218d..000000000
--- a/src/Infrastructure/BotSharp.Abstraction/Chart/Models/ChartCodeResult.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace BotSharp.Abstraction.Chart.Models;
-
-public class ChartCodeResult
-{
- public string Code { get; set; }
- public string Language { get; set; }
-}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Coding/ICodeProcessor.cs b/src/Infrastructure/BotSharp.Abstraction/Coding/ICodeProcessor.cs
index 1fe083f01..0ca0c54d3 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Coding/ICodeProcessor.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Coding/ICodeProcessor.cs
@@ -1,3 +1,4 @@
+using BotSharp.Abstraction.Coding.Models;
using BotSharp.Abstraction.Coding.Options;
using BotSharp.Abstraction.Coding.Responses;
@@ -7,6 +8,23 @@ public interface ICodeProcessor
{
string Provider { get; }
+ ///
+ /// Run code script
+ ///
+ /// The code scirpt to run
+ /// Code script execution options
+ ///
+ ///
Task RunAsync(string codeScript, CodeInterpretOptions? options = null)
=> throw new NotImplementedException();
+
+ ///
+ /// Generate code script
+ ///
+ /// User requirement to generate code script
+ /// Code script generation options
+ ///
+ ///
+ Task GenerateCodeScriptAsync(string text, CodeGenerationOptions? options = null)
+ => throw new NotImplementedException();
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Coding/Models/CodeGenerationResult.cs b/src/Infrastructure/BotSharp.Abstraction/Coding/Models/CodeGenerationResult.cs
new file mode 100644
index 000000000..83544f985
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/Coding/Models/CodeGenerationResult.cs
@@ -0,0 +1,7 @@
+namespace BotSharp.Abstraction.Coding.Models;
+
+public class CodeGenerationResult : ResponseBase
+{
+ public string Content { get; set; }
+ public string Language { get; set; }
+}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Coding/Options/CodeGenerationOptions.cs b/src/Infrastructure/BotSharp.Abstraction/Coding/Options/CodeGenerationOptions.cs
new file mode 100644
index 000000000..be6437041
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/Coding/Options/CodeGenerationOptions.cs
@@ -0,0 +1,32 @@
+namespace BotSharp.Abstraction.Coding.Options;
+
+public class CodeGenerationOptions : LlmConfigBase
+{
+ ///
+ /// Agent id to get instruction
+ ///
+ [JsonPropertyName("agent_id")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? AgentId { get; set; }
+
+ ///
+ /// Template (prompt) name
+ ///
+ [JsonPropertyName("template_name")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? TemplateName { get; set; }
+
+ ///
+ /// The programming language
+ ///
+ [JsonPropertyName("language")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? Language { get; set; } = "python";
+
+ ///
+ /// Data that can be used to fill in the prompt
+ ///
+ [JsonPropertyName("data")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public Dictionary? Data { get; set; }
+}
\ No newline at end of file
diff --git a/src/Infrastructure/BotSharp.Abstraction/Coding/Options/CodeProcessOptions.cs b/src/Infrastructure/BotSharp.Abstraction/Coding/Options/CodeProcessOptions.cs
new file mode 100644
index 000000000..343447b6b
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/Coding/Options/CodeProcessOptions.cs
@@ -0,0 +1,28 @@
+namespace BotSharp.Abstraction.Coding.Options;
+
+public class CodeProcessOptions : CodeGenerationOptions
+{
+ ///
+ /// Code processor provider
+ ///
+ [JsonPropertyName("processor")]
+ public string? Processor { get; set; }
+
+ ///
+ /// Whether to save the generated code script to db
+ ///
+ [JsonPropertyName("save_to_db")]
+ public bool SaveToDb { get; set; }
+
+ ///
+ /// Code script name (e.g., demo.py)
+ ///
+ [JsonPropertyName("script_name")]
+ public string? ScriptName { get; set; }
+
+ ///
+ /// Code script type (i.e., src, test)
+ ///
+ [JsonPropertyName("script_type")]
+ public string? ScriptType { get; set; } = AgentCodeScriptType.Src;
+}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Coding/Responses/CodeInterpretResponse.cs b/src/Infrastructure/BotSharp.Abstraction/Coding/Responses/CodeInterpretResponse.cs
index a07c7a1fe..ef1881c11 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Coding/Responses/CodeInterpretResponse.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Coding/Responses/CodeInterpretResponse.cs
@@ -1,8 +1,6 @@
namespace BotSharp.Abstraction.Coding.Responses;
-public class CodeInterpretResponse
+public class CodeInterpretResponse : ResponseBase
{
public string Result { get; set; } = string.Empty;
- public bool Success { get; set; }
- public string? ErrorMsg { get; set; }
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Files/Options/SelectFileOptions.cs b/src/Infrastructure/BotSharp.Abstraction/Files/Options/SelectFileOptions.cs
index 2f8d348ea..2c769cb8d 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Files/Options/SelectFileOptions.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Files/Options/SelectFileOptions.cs
@@ -13,7 +13,7 @@ public class SelectFileOptions : LlmConfigBase
public string? TemplateName { get; set; }
///
- /// Description that user provides to select files
+ /// User description to select files
///
public string? Description { get; set; }
diff --git a/src/Infrastructure/BotSharp.Abstraction/Files/Responses/FileHandleResponse.cs b/src/Infrastructure/BotSharp.Abstraction/Files/Responses/FileHandleResponse.cs
index 6957ed0fc..67de6eb7d 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Files/Responses/FileHandleResponse.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Files/Responses/FileHandleResponse.cs
@@ -1,8 +1,6 @@
namespace BotSharp.Abstraction.Files.Responses;
-public class FileHandleResponse
+public class FileHandleResponse : ResponseBase
{
public string Result { get; set; } = string.Empty;
- public bool Success { get; set; }
- public string? ErrorMsg { get; set; }
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Instructs/Contexts/CodeInstructContext.cs b/src/Infrastructure/BotSharp.Abstraction/Instructs/Contexts/CodeInstructContext.cs
index d6dae85f6..77e37efaa 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Instructs/Contexts/CodeInstructContext.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Instructs/Contexts/CodeInstructContext.cs
@@ -3,5 +3,6 @@ namespace BotSharp.Abstraction.Instructs.Contexts;
public class CodeInstructContext
{
public string CodeScript { get; set; }
+ public string ScriptType { get; set; }
public List Arguments { get; set; } = [];
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Instructs/Options/CodeInstructOptions.cs b/src/Infrastructure/BotSharp.Abstraction/Instructs/Options/CodeInstructOptions.cs
index 2ea99275f..182196753 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Instructs/Options/CodeInstructOptions.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Instructs/Options/CodeInstructOptions.cs
@@ -2,14 +2,30 @@ namespace BotSharp.Abstraction.Instructs.Options;
public class CodeInstructOptions
{
+ ///
+ /// Code processor provider
+ ///
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("processor")]
public string? Processor { get; set; }
+ ///
+ /// Code script name
+ ///
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [JsonPropertyName("code_script_name")]
- public string? CodeScriptName { get; set; }
+ [JsonPropertyName("script_name")]
+ public string? ScriptName { get; set; }
+ ///
+ /// Code script name
+ ///
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("script_type")]
+ public string? ScriptType { get; set; }
+
+ ///
+ /// Arguments
+ ///
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("arguments")]
public List? Arguments { get; set; }
diff --git a/src/Infrastructure/BotSharp.Abstraction/Instructs/Options/FileInstructOptions.cs b/src/Infrastructure/BotSharp.Abstraction/Instructs/Options/FileInstructOptions.cs
index 6e6ac1fd1..b673589db 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Instructs/Options/FileInstructOptions.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Instructs/Options/FileInstructOptions.cs
@@ -2,6 +2,9 @@ namespace BotSharp.Abstraction.Instructs.Options;
public class FileInstructOptions
{
+ ///
+ /// File processor provider
+ ///
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("processor")]
public string? Processor { get; set; }
diff --git a/src/Infrastructure/BotSharp.Abstraction/MLTasks/Filters/LlmConfigFilter.cs b/src/Infrastructure/BotSharp.Abstraction/MLTasks/Filters/LlmConfigFilter.cs
new file mode 100644
index 000000000..89ec04103
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/MLTasks/Filters/LlmConfigFilter.cs
@@ -0,0 +1,13 @@
+using BotSharp.Abstraction.MLTasks.Settings;
+
+namespace BotSharp.Abstraction.MLTasks.Filters;
+
+public class LlmConfigFilter
+{
+ public List? Providers { get; set; }
+ public List? ModelIds { get; set; }
+ public List? ModelNames { get; set; }
+ public List? ModelTypes { get; set; }
+ public List? ModelCapabilities { get; set; }
+ public bool? MultiModal { get; set; }
+}
diff --git a/src/Infrastructure/BotSharp.Abstraction/MLTasks/ILlmProviderService.cs b/src/Infrastructure/BotSharp.Abstraction/MLTasks/ILlmProviderService.cs
index f70a9496e..da8a8f534 100644
--- a/src/Infrastructure/BotSharp.Abstraction/MLTasks/ILlmProviderService.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/MLTasks/ILlmProviderService.cs
@@ -1,12 +1,13 @@
+using BotSharp.Abstraction.MLTasks.Filters;
using BotSharp.Abstraction.MLTasks.Settings;
namespace BotSharp.Abstraction.MLTasks;
public interface ILlmProviderService
{
- LlmModelSetting GetSetting(string provider, string model);
+ LlmModelSetting? GetSetting(string provider, string model);
List GetProviders();
- LlmModelSetting GetProviderModel(string provider, string id, bool? multiModal = null, LlmModelType? modelType = null, bool imageGenerate = false);
+ LlmModelSetting? GetProviderModel(string provider, string id, bool? multiModal = null, LlmModelType? modelType = null, IEnumerable? capabilities = null);
List GetProviderModels(string provider);
- List GetLlmConfigs(LlmConfigOptions? options = null);
+ List GetLlmConfigs(LlmConfigFilter? filter = null);
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/MLTasks/Settings/LlmConfigOptions.cs b/src/Infrastructure/BotSharp.Abstraction/MLTasks/Settings/LlmConfigOptions.cs
deleted file mode 100644
index eae417a41..000000000
--- a/src/Infrastructure/BotSharp.Abstraction/MLTasks/Settings/LlmConfigOptions.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace BotSharp.Abstraction.MLTasks.Settings;
-
-public class LlmConfigOptions
-{
- public LlmModelType? Type { get; set; }
- public bool? MultiModal { get; set; }
- public bool? ImageGeneration { get; set; }
-}
diff --git a/src/Infrastructure/BotSharp.Abstraction/MLTasks/Settings/LlmModelSetting.cs b/src/Infrastructure/BotSharp.Abstraction/MLTasks/Settings/LlmModelSetting.cs
index 3249b9eb4..ff2c1d3e6 100644
--- a/src/Infrastructure/BotSharp.Abstraction/MLTasks/Settings/LlmModelSetting.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/MLTasks/Settings/LlmModelSetting.cs
@@ -31,17 +31,13 @@ public class LlmModelSetting
public string ApiKey { get; set; } = null!;
public string? Endpoint { get; set; }
public LlmModelType Type { get; set; } = LlmModelType.Chat;
+ public List Capabilities { get; set; } = [];
///
- /// If true, allow sending images/vidoes to this model
+ /// If true, allow sending images/videos to this model
///
public bool MultiModal { get; set; }
- ///
- /// If true, allow generating images
- ///
- public bool ImageGeneration { get; set; }
-
///
/// Settings for embedding
///
@@ -173,10 +169,29 @@ public class LlmCostSetting
public enum LlmModelType
{
+ All = 0,
Text = 1,
Chat = 2,
Image = 3,
Embedding = 4,
Audio = 5,
Realtime = 6,
+ Web = 7
}
+
+public enum LlmModelCapability
+{
+ All = 0,
+ Text = 1,
+ Chat = 2,
+ ImageReading = 3,
+ ImageGeneration = 4,
+ ImageEdit = 5,
+ ImageVariation = 6,
+ Embedding = 7,
+ AudioTranscription = 8,
+ AudioGeneration = 9,
+ Realtime = 10,
+ WebSearch = 11,
+ PdfReading = 12
+}
\ No newline at end of file
diff --git a/src/Infrastructure/BotSharp.Abstraction/Models/ResponseBase.cs b/src/Infrastructure/BotSharp.Abstraction/Models/ResponseBase.cs
new file mode 100644
index 000000000..cb381aebe
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/Models/ResponseBase.cs
@@ -0,0 +1,11 @@
+namespace BotSharp.Abstraction.Models;
+
+public class ResponseBase
+{
+ [JsonPropertyName("success")]
+ public bool Success { get; set; }
+
+ [JsonPropertyName("error_message")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? ErrorMsg { get; set; }
+}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Repositories/Filters/AgentCodeScriptFilter.cs b/src/Infrastructure/BotSharp.Abstraction/Repositories/Filters/AgentCodeScriptFilter.cs
index 530bb4aa5..14848d717 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Repositories/Filters/AgentCodeScriptFilter.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Repositories/Filters/AgentCodeScriptFilter.cs
@@ -7,6 +7,6 @@ public class AgentCodeScriptFilter
public static AgentCodeScriptFilter Empty()
{
- return new AgentCodeScriptFilter();
+ return new();
}
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs
index 31b1da97a..52f43fb6b 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs
@@ -1,3 +1,4 @@
+using BotSharp.Abstraction.Agents.Options;
using BotSharp.Abstraction.Knowledges.Filters;
using BotSharp.Abstraction.Loggers.Models;
using BotSharp.Abstraction.Plugins.Models;
@@ -81,7 +82,7 @@ void BulkInsertUserAgents(List userAgents)
=> throw new NotImplementedException();
bool DeleteAgents()
=> throw new NotImplementedException();
- bool DeleteAgent(string agentId)
+ bool DeleteAgent(string agentId, AgentDeleteOptions? options = null)
=> throw new NotImplementedException();
List GetAgentResponses(string agentId, string prefix, string intent)
=> throw new NotImplementedException();
diff --git a/src/Infrastructure/BotSharp.Abstraction/Repositories/Options/AgentCodeScriptDbUpdateOptions.cs b/src/Infrastructure/BotSharp.Abstraction/Repositories/Options/AgentCodeScriptDbUpdateOptions.cs
index 5f6045129..2dde049bf 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Repositories/Options/AgentCodeScriptDbUpdateOptions.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Repositories/Options/AgentCodeScriptDbUpdateOptions.cs
@@ -2,5 +2,6 @@ namespace BotSharp.Abstraction.Repositories.Options;
public class AgentCodeScriptDbUpdateOptions
{
+ [JsonPropertyName("is_upsert")]
public bool IsUpsert { get; set; }
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Utilities/ObjectExtensions.cs b/src/Infrastructure/BotSharp.Abstraction/Utilities/ObjectExtensions.cs
index bed3b71ab..a36516c8a 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Utilities/ObjectExtensions.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Utilities/ObjectExtensions.cs
@@ -6,7 +6,7 @@ namespace BotSharp.Abstraction.Utilities;
public static class ObjectExtensions
{
- private static readonly JsonSerializerOptions DefaultJsonOptions = new()
+ private static readonly JsonSerializerOptions _defaultJsonOptions = new()
{
PropertyNameCaseInsensitive = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
@@ -14,28 +14,55 @@ public static class ObjectExtensions
ReferenceHandler = ReferenceHandler.IgnoreCycles
};
- public static T? DeepClone(this T? obj, Action? modifier = null, BotSharpOptions? options = null) where T : class
+ public static T? DeepClone(this T? inputObj, Action? modifier = null, BotSharpOptions? options = null) where T : class
{
- if (obj == null)
+ if (inputObj == null)
{
return null;
}
try
{
- var json = JsonSerializer.Serialize(obj, options?.JsonSerializerOptions ?? DefaultJsonOptions);
- var newObj = JsonSerializer.Deserialize(json, options?.JsonSerializerOptions ?? DefaultJsonOptions);
- if (modifier != null && newObj != null)
+ var json = JsonSerializer.Serialize(inputObj, options?.JsonSerializerOptions ?? _defaultJsonOptions);
+ var outputObj = JsonSerializer.Deserialize(json, options?.JsonSerializerOptions ?? _defaultJsonOptions);
+ if (modifier != null && outputObj != null)
{
- modifier(newObj);
+ modifier(outputObj);
}
- return newObj;
+ return outputObj;
}
catch (Exception ex)
{
- Console.WriteLine($"DeepClone Error in {nameof(DeepClone)}: {ex}");
+ Console.WriteLine($"DeepClone Error in {nameof(DeepClone)} for {typeof(T).Name}: {ex}");
return null;
}
}
+
+ public static TOutput? DeepClone(this TInput? inputObj, Action? modifier = null, BotSharpOptions? options = null)
+ where TInput : class
+ where TOutput : class
+ {
+ if (inputObj == null)
+ {
+ return null;
+ }
+
+ try
+ {
+ var json = JsonSerializer.Serialize(inputObj, options?.JsonSerializerOptions ?? _defaultJsonOptions);
+ var outputObj = JsonSerializer.Deserialize(json, options?.JsonSerializerOptions ?? _defaultJsonOptions);
+ if (modifier != null && outputObj != null)
+ {
+ modifier(outputObj);
+ }
+
+ return outputObj;
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"DeepClone Error in {nameof(DeepClone)} for {typeof(TInput).Name} and {typeof(TOutput).Name}: {ex}");
+ return null;
+ }
+ }
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Utilities/StringExtensions.cs b/src/Infrastructure/BotSharp.Abstraction/Utilities/StringExtensions.cs
index 8e2fd9bbf..e26f663d1 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Utilities/StringExtensions.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Utilities/StringExtensions.cs
@@ -11,12 +11,18 @@ public static class StringExtensions
public static string SubstringMax(this string str, int maxLength)
{
if (string.IsNullOrEmpty(str))
+ {
return str;
+ }
if (str.Length > maxLength)
+ {
return str.Substring(0, maxLength);
+ }
else
+ {
return str;
+ }
}
public static string[] SplitByNewLine(this string input)
@@ -39,14 +45,20 @@ public static string RemoveNewLine(this string input)
public static bool IsEqualTo(this string? str1, string? str2, StringComparison option = StringComparison.OrdinalIgnoreCase)
{
- if (str1 == null) return str2 == null;
+ if (str1 == null)
+ {
+ return str2 == null;
+ }
return str1.Equals(str2, option);
}
public static string CleanStr(this string? str)
{
- if (string.IsNullOrWhiteSpace(str)) return string.Empty;
+ if (string.IsNullOrWhiteSpace(str))
+ {
+ return string.Empty;
+ }
return str.Replace(" ", "").Replace("\t", "").Replace("\n", "").Replace("\r", "");
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Models/VectorSearchParamModel.cs b/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Models/VectorSearchParamModel.cs
new file mode 100644
index 000000000..8e14b05ca
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Models/VectorSearchParamModel.cs
@@ -0,0 +1,7 @@
+namespace BotSharp.Abstraction.VectorStorage.Models;
+
+public class VectorSearchParamModel
+{
+ [JsonPropertyName("exact_search")]
+ public bool? ExactSearch { get; set; }
+}
diff --git a/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Options/VectorSearchOptions.cs b/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Options/VectorSearchOptions.cs
index 1e0141a86..4ba0c81c8 100644
--- a/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Options/VectorSearchOptions.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Options/VectorSearchOptions.cs
@@ -10,6 +10,7 @@ public class VectorSearchOptions
public int? Limit { get; set; } = 5;
public float? Confidence { get; set; } = 0.5f;
public bool WithVector { get; set; }
+ public VectorSearchParamModel? SearchParam { get; set; }
public static VectorSearchOptions Default()
{
diff --git a/src/Infrastructure/BotSharp.Core.Crontab/Services/CrontabWatcher.cs b/src/Infrastructure/BotSharp.Core.Crontab/Services/CrontabWatcher.cs
index 288458430..ccd89cf45 100644
--- a/src/Infrastructure/BotSharp.Core.Crontab/Services/CrontabWatcher.cs
+++ b/src/Infrastructure/BotSharp.Core.Crontab/Services/CrontabWatcher.cs
@@ -36,7 +36,8 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
await RunCronChecker(scope.ServiceProvider);
await Task.Delay(1000, stoppingToken);
});
- if (isLocked == false)
+
+ if (!isLocked)
{
await Task.Delay(1000, stoppingToken);
}
diff --git a/src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs b/src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs
index 41e13da4c..449db38da 100644
--- a/src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs
+++ b/src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs
@@ -5,6 +5,7 @@
using BotSharp.Abstraction.Templating;
using BotSharp.Abstraction.Users.Enums;
using BotSharp.Core.Agents.Hooks;
+using BotSharp.Core.Coding;
using Microsoft.Extensions.Configuration;
namespace BotSharp.Core.Agents;
@@ -48,6 +49,8 @@ public void RegisterDI(IServiceCollection services, IConfiguration config)
render.RegisterType(typeof(AgentSettings));
return settingService.Bind("Agent");
});
+
+ services.AddSingleton();
}
public bool AttachMenu(List menu)
@@ -57,9 +60,10 @@ public bool AttachMenu(List menu)
{
SubMenu = new List
{
+ new PluginMenuDef("Agents", link: "page/agent"), // icon: "bx bx-bot",
new PluginMenuDef("Routing", link: "page/agent/router"), // icon: "bx bx-map-pin"
- new PluginMenuDef("Evaluating", link: "page/agent/evaluator") { Roles = new List { UserRole.Root, UserRole.Admin } }, // icon: "bx bx-task"
- new PluginMenuDef("Agents", link: "page/agent"), // icon: "bx bx-bot"
+ new PluginMenuDef("Evaluating", link: "page/agent/evaluator") { Roles = [UserRole.Root, UserRole.Admin] }, // icon: "bx bx-task"
+ new PluginMenuDef("Coding", link: "page/agent/code-scripts") { Roles = [UserRole.Root, UserRole.Admin] },
}
});
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Hooks/BasicAgentHook.cs b/src/Infrastructure/BotSharp.Core/Agents/Hooks/BasicAgentHook.cs
index a8bafdd25..cadeb3b47 100644
--- a/src/Infrastructure/BotSharp.Core/Agents/Hooks/BasicAgentHook.cs
+++ b/src/Infrastructure/BotSharp.Core/Agents/Hooks/BasicAgentHook.cs
@@ -70,12 +70,18 @@ public override void OnAgentUtilityLoaded(Agent agent)
foreach (var utility in innerUtilities)
{
var isVisible = agentService.RenderVisibility(utility.VisibilityExpression, renderDict);
- if (!isVisible || utility.Items.IsNullOrEmpty()) continue;
+ if (!isVisible || utility.Items.IsNullOrEmpty())
+ {
+ continue;
+ }
foreach (var item in utility.Items)
{
isVisible = agentService.RenderVisibility(item.VisibilityExpression, renderDict);
- if (!isVisible) continue;
+ if (!isVisible)
+ {
+ continue;
+ }
if (item.FunctionName?.StartsWith(UTIL_PREFIX) == true)
{
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CodeScripts.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CodeScripts.cs
deleted file mode 100644
index 5c7c8bc00..000000000
--- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CodeScripts.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-using BotSharp.Abstraction.Agents.Options;
-
-namespace BotSharp.Core.Agents.Services;
-
-public partial class AgentService
-{
- public async Task> GetAgentCodeScripts(string agentId, AgentCodeScriptFilter? filter = null)
- {
- var db = _services.GetRequiredService();
- var scripts = db.GetAgentCodeScripts(agentId, filter);
- return await Task.FromResult(scripts);
- }
-
- public async Task GetAgentCodeScript(string agentId, string scriptName, string scriptType = AgentCodeScriptType.Src)
- {
- var db = _services.GetRequiredService();
- var script = db.GetAgentCodeScript(agentId, scriptName, scriptType);
- return await Task.FromResult(script);
- }
-
- public async Task UpdateAgentCodeScripts(string agentId, List codeScripts, AgentCodeScriptUpdateOptions? options = null)
- {
- if (string.IsNullOrWhiteSpace(agentId) || codeScripts.IsNullOrEmpty())
- {
- return false;
- }
-
- var db = _services.GetRequiredService();
-
- var toDeleteScripts = new List();
- if (options?.DeleteIfNotIncluded == true)
- {
- var curDbScripts = await GetAgentCodeScripts(agentId);
- var codePaths = codeScripts.Select(x => x.CodePath).ToList();
- toDeleteScripts = curDbScripts.Where(x => !codePaths.Contains(x.CodePath)).ToList();
- }
-
- var updateResult = db.UpdateAgentCodeScripts(agentId, codeScripts, options);
- if (!toDeleteScripts.IsNullOrEmpty())
- {
- db.DeleteAgentCodeScripts(agentId, toDeleteScripts);
- }
-
- return updateResult;
- }
-}
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.Coding.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.Coding.cs
new file mode 100644
index 000000000..aee641c8c
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.Coding.cs
@@ -0,0 +1,110 @@
+using BotSharp.Abstraction.Agents.Options;
+using BotSharp.Abstraction.Coding;
+using BotSharp.Abstraction.Coding.Options;
+
+namespace BotSharp.Core.Agents.Services;
+
+public partial class AgentService
+{
+ public async Task> GetAgentCodeScripts(string agentId, AgentCodeScriptFilter? filter = null)
+ {
+ var db = _services.GetRequiredService();
+ var scripts = db.GetAgentCodeScripts(agentId, filter);
+ return await Task.FromResult(scripts);
+ }
+
+ public async Task GetAgentCodeScript(string agentId, string scriptName, string scriptType = AgentCodeScriptType.Src)
+ {
+ var db = _services.GetRequiredService();
+ var script = db.GetAgentCodeScript(agentId, scriptName, scriptType);
+ return await Task.FromResult(script);
+ }
+
+ public async Task UpdateAgentCodeScripts(string agentId, List codeScripts, AgentCodeScriptUpdateOptions? options = null)
+ {
+ if (string.IsNullOrWhiteSpace(agentId))
+ {
+ return false;
+ }
+
+ codeScripts ??= new();
+ var db = _services.GetRequiredService();
+
+ if (options?.DeleteIfNotIncluded == true && codeScripts.IsNullOrEmpty())
+ {
+ // Delete all code scripts in this agent
+ db.DeleteAgentCodeScripts(agentId);
+ return true;
+ }
+
+ var toDeleteScripts = new List();
+ if (options?.DeleteIfNotIncluded == true)
+ {
+ var curDbScripts = await GetAgentCodeScripts(agentId);
+ var codePaths = codeScripts.Select(x => x.CodePath).ToList();
+ toDeleteScripts = curDbScripts.Where(x => !codePaths.Contains(x.CodePath)).ToList();
+ }
+
+ var updateResult = db.UpdateAgentCodeScripts(agentId, codeScripts, options);
+ if (!toDeleteScripts.IsNullOrEmpty())
+ {
+ db.DeleteAgentCodeScripts(agentId, toDeleteScripts);
+ }
+
+ return updateResult;
+ }
+
+ public async Task DeleteAgentCodeScripts(string agentId, List? codeScripts = null)
+ {
+ if (string.IsNullOrWhiteSpace(agentId))
+ {
+ return false;
+ }
+
+ var db = _services.GetRequiredService();
+ var deleted = db.DeleteAgentCodeScripts(agentId, codeScripts);
+ return await Task.FromResult(deleted);
+ }
+
+ public async Task GenerateCodeScript(string agentId, string text, CodeProcessOptions? options = null)
+ {
+ if (string.IsNullOrWhiteSpace(agentId))
+ {
+ return new CodeGenerationResult
+ {
+ ErrorMsg = "Agent id cannot be empty."
+ };
+ }
+
+ var processor = options?.Processor ?? "botsharp-py-interpreter";
+ var codeProcessor = _services.GetServices().FirstOrDefault(x => x.Provider.IsEqualTo(processor));
+ if (codeProcessor == null)
+ {
+ var errorMsg = $"Unable to find code processor {processor}.";
+ _logger.LogWarning(errorMsg);
+ return new CodeGenerationResult
+ {
+ ErrorMsg = errorMsg
+ };
+ }
+
+ var result = await codeProcessor.GenerateCodeScriptAsync(text, options);
+ if (result.Success && options?.SaveToDb == true)
+ {
+ var db = _services.GetRequiredService();
+ var scripts = new List
+ {
+ new AgentCodeScript
+ {
+ Name = options?.ScriptName ?? $"{Guid.NewGuid()}.py",
+ Content = result.Content,
+ ScriptType = options?.ScriptType ?? AgentCodeScriptType.Src
+ }
+ };
+ var saved = db.UpdateAgentCodeScripts(agentId, scripts, new() { IsUpsert = true });
+ result.Success = saved;
+ }
+
+ return result;
+ }
+}
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.DeleteAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.DeleteAgent.cs
index 6783bf916..5237dbdc9 100644
--- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.DeleteAgent.cs
+++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.DeleteAgent.cs
@@ -1,3 +1,4 @@
+using BotSharp.Abstraction.Agents.Options;
using BotSharp.Abstraction.Users.Enums;
using BotSharp.Abstraction.Users.Models;
@@ -5,7 +6,7 @@ namespace BotSharp.Core.Agents.Services;
public partial class AgentService
{
- public async Task DeleteAgent(string id)
+ public async Task DeleteAgent(string id, AgentDeleteOptions? options = null)
{
var userService = _services.GetRequiredService();
var auth = await userService.GetUserAuthorizations(new List { id });
@@ -15,7 +16,7 @@ public async Task DeleteAgent(string id)
return false;
}
- var deleted = _db.DeleteAgent(id);
+ var deleted = _db.DeleteAgent(id, options);
return await Task.FromResult(deleted);
}
}
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.RefreshAgents.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.RefreshAgents.cs
index 045c71cf5..266f69935 100644
--- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.RefreshAgents.cs
+++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.RefreshAgents.cs
@@ -62,7 +62,13 @@ public async Task RefreshAgents(IEnumerable? agentIds = null)
var tasks = GetTasksFromFile(dir);
var codeScripts = GetCodeScriptsFromFile(dir);
- var isAgentDeleted = _db.DeleteAgent(agent.Id);
+ var isAgentDeleted = _db.DeleteAgent(agent.Id, options: new()
+ {
+ DeleteRoleAgents = false,
+ DeleteUserAgents = false,
+ ToDeleteCodeScripts = codeScripts
+ });
+
if (isAgentDeleted)
{
await Task.Delay(100);
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.Rendering.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.Rendering.cs
index 55980e963..83e83ef5a 100644
--- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.Rendering.cs
+++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.Rendering.cs
@@ -155,7 +155,7 @@ public bool RenderVisibility(string? visibilityExpression, IDictionary();
- var copy = new Dictionary(dict);
+ var copy = dict != null ? new Dictionary(dict) : [];
var result = render.Render(visibilityExpression, new Dictionary
{
{ "states", copy }
diff --git a/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.Audio.cs b/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.Audio.cs
index a62744a51..0cd8a8c70 100644
--- a/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.Audio.cs
+++ b/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.Audio.cs
@@ -15,7 +15,10 @@ public bool SaveSpeechFile(string conversationId, string fileName, BinaryData da
}
var filePath = Path.Combine(dir, fileName);
- if (File.Exists(filePath)) return false;
+ if (File.Exists(filePath))
+ {
+ return false;
+ }
using var fs = File.Create(filePath);
using var ds = data.ToStream();
diff --git a/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.Common.cs b/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.Common.cs
index 80a10deeb..afed03f54 100644
--- a/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.Common.cs
+++ b/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.Common.cs
@@ -40,7 +40,10 @@ public BinaryData GetFileBytes(string fileStorageUrl)
public bool SaveFileStreamToPath(string filePath, Stream stream)
{
- if (string.IsNullOrEmpty(filePath)) return false;
+ if (string.IsNullOrEmpty(filePath))
+ {
+ return false;
+ }
using (var fileStream = new FileStream(filePath, FileMode.Create))
{
diff --git a/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.Conversation.cs b/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.Conversation.cs
index e4f5fc5c9..23135e8c9 100644
--- a/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.Conversation.cs
+++ b/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.Conversation.cs
@@ -34,9 +34,9 @@ public async Task> GetMessageFileScreenshotsAsync(
continue;
}
- foreach (var subDir in Directory.GetDirectories(dir))
+ foreach (var subDir in Directory.EnumerateDirectories(dir))
{
- var file = Directory.GetFiles(subDir).FirstOrDefault();
+ var file = Directory.EnumerateFiles(subDir).FirstOrDefault();
if (file == null)
{
continue;
@@ -79,7 +79,7 @@ public IEnumerable GetMessageFiles(string conversationId, IEnu
var sources = options?.Sources != null
? options.Sources
- : Directory.GetDirectories(baseDir).Select(x => x.Split(Path.DirectorySeparatorChar, StringSplitOptions.RemoveEmptyEntries).Last());
+ : Directory.EnumerateDirectories(baseDir).Select(x => x.Split(Path.DirectorySeparatorChar, StringSplitOptions.RemoveEmptyEntries).Last());
if (sources.IsNullOrEmpty())
{
continue;
@@ -93,11 +93,11 @@ public IEnumerable GetMessageFiles(string conversationId, IEnu
continue;
}
- foreach (var subDir in Directory.GetDirectories(dir))
+ foreach (var subDir in Directory.EnumerateDirectories(dir))
{
var fileIndex = subDir.Split(Path.DirectorySeparatorChar, StringSplitOptions.RemoveEmptyEntries).Last();
- foreach (var file in Directory.GetFiles(subDir))
+ foreach (var file in Directory.EnumerateFiles(subDir))
{
var contentType = FileUtility.GetFileContentType(file);
if (options?.ContentTypes != null && !options.ContentTypes.Contains(contentType))
@@ -143,7 +143,7 @@ public string GetMessageFile(string conversationId, string messageId, string sou
return string.Empty;
}
- var found = Directory.GetFiles(dir).FirstOrDefault(f => Path.GetFileNameWithoutExtension(f).IsEqualTo(fileName));
+ var found = Directory.EnumerateFiles(dir).FirstOrDefault(f => Path.GetFileNameWithoutExtension(f).IsEqualTo(fileName));
return found;
}
@@ -308,9 +308,9 @@ private async Task> GetScreenshotsAsync(string fil
var contentType = FileUtility.GetFileContentType(file);
var screenshotDir = Path.Combine(parentDir, SCREENSHOT_FILE_FOLDER);
- if (ExistDirectory(screenshotDir) && !Directory.GetFiles(screenshotDir).IsNullOrEmpty())
+ if (ExistDirectory(screenshotDir))
{
- foreach (var screenshot in Directory.GetFiles(screenshotDir))
+ foreach (var screenshot in Directory.EnumerateFiles(screenshotDir))
{
var fileName = Path.GetFileNameWithoutExtension(screenshot);
var fileExtension = Path.GetExtension(screenshot).Substring(1);
diff --git a/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.KnowledgeBase.cs b/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.KnowledgeBase.cs
index 8fc6bb0ac..72170fea0 100644
--- a/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.KnowledgeBase.cs
+++ b/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.KnowledgeBase.cs
@@ -46,7 +46,10 @@ public bool DeleteKnowledgeFile(string collectionName, string vectorStoreProvide
}
var dir = BuildKnowledgeCollectionFileDir(collectionName, vectorStoreProvider);
- if (!ExistDirectory(dir)) return false;
+ if (!ExistDirectory(dir))
+ {
+ return false;
+ }
if (fileId == null)
{
diff --git a/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.User.cs b/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.User.cs
index 9384bd837..6935a1ad2 100644
--- a/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.User.cs
+++ b/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.User.cs
@@ -10,7 +10,10 @@ public string GetUserAvatar()
var user = db.GetUserById(_user.Id);
var dir = GetUserAvatarDir(user?.Id);
- if (!ExistDirectory(dir)) return string.Empty;
+ if (!ExistDirectory(dir))
+ {
+ return string.Empty;
+ }
var found = Directory.GetFiles(dir).FirstOrDefault() ?? string.Empty;
return found;
@@ -18,7 +21,10 @@ public string GetUserAvatar()
public bool SaveUserAvatar(FileDataModel file)
{
- if (file == null || string.IsNullOrEmpty(file.FileData)) return false;
+ if (file == null || string.IsNullOrEmpty(file.FileData))
+ {
+ return false;
+ }
try
{
@@ -26,7 +32,10 @@ public bool SaveUserAvatar(FileDataModel file)
var user = db.GetUserById(_user.Id);
var dir = GetUserAvatarDir(user?.Id);
- if (string.IsNullOrEmpty(dir)) return false;
+ if (string.IsNullOrEmpty(dir))
+ {
+ return false;
+ }
if (Directory.Exists(dir))
{
diff --git a/src/Infrastructure/BotSharp.Core/Infrastructures/CompletionProvider.cs b/src/Infrastructure/BotSharp.Core/Infrastructures/CompletionProvider.cs
index 60645bcf2..b5d989298 100644
--- a/src/Infrastructure/BotSharp.Core/Infrastructures/CompletionProvider.cs
+++ b/src/Infrastructure/BotSharp.Core/Infrastructures/CompletionProvider.cs
@@ -5,7 +5,8 @@ namespace BotSharp.Core.Infrastructures;
public class CompletionProvider
{
- public static object GetCompletion(IServiceProvider services,
+ public static object GetCompletion(
+ IServiceProvider services,
string? provider = null,
string? model = null,
AgentLlmConfig? agentConfig = null)
@@ -42,7 +43,8 @@ public static object GetCompletion(IServiceProvider services,
}
}
- public static IChatCompletion GetChatCompletion(IServiceProvider services,
+ public static IChatCompletion GetChatCompletion(
+ IServiceProvider services,
string? provider = null,
string? model = null,
string? modelId = null,
@@ -66,7 +68,8 @@ public static IChatCompletion GetChatCompletion(IServiceProvider services,
return completer;
}
- public static ITextCompletion GetTextCompletion(IServiceProvider services,
+ public static ITextCompletion GetTextCompletion(
+ IServiceProvider services,
string? provider = null,
string? model = null,
AgentLlmConfig? agentConfig = null)
@@ -86,15 +89,16 @@ public static ITextCompletion GetTextCompletion(IServiceProvider services,
return completer;
}
- public static IImageCompletion GetImageCompletion(IServiceProvider services,
+ public static IImageCompletion GetImageCompletion(
+ IServiceProvider services,
string? provider = null,
string? model = null,
string? modelId = null,
- bool imageGenerate = false)
+ IEnumerable? capabilities = null)
{
var completions = services.GetServices();
(provider, model) = GetProviderAndModel(services, provider: provider,
- model: model, modelId: modelId, imageGenerate: imageGenerate);
+ model: model, modelId: modelId, capabilities: capabilities);
var completer = completions.FirstOrDefault(x => x.Provider == provider);
if (completer == null)
@@ -107,7 +111,8 @@ public static IImageCompletion GetImageCompletion(IServiceProvider services,
return completer;
}
- public static ITextEmbedding GetTextEmbedding(IServiceProvider services,
+ public static ITextEmbedding GetTextEmbedding(
+ IServiceProvider services,
string? provider = null,
string? model = null)
{
@@ -166,7 +171,8 @@ public static IAudioSynthesis GetAudioSynthesizer(
return completer;
}
- public static IRealTimeCompletion GetRealTimeCompletion(IServiceProvider services,
+ public static IRealTimeCompletion GetRealTimeCompletion(
+ IServiceProvider services,
string? provider = null,
string? model = null,
string? modelId = null,
@@ -176,7 +182,7 @@ public static IRealTimeCompletion GetRealTimeCompletion(IServiceProvider service
var completions = services.GetServices();
(provider, model) = GetProviderAndModel(services, provider: provider, model: model, modelId: modelId,
multiModal: multiModal,
- modelType: LlmModelType.Realtime,
+ modelType: LlmModelType.Realtime,
agentConfig: agentConfig);
var completer = completions.FirstOrDefault(x => x.Provider == provider);
@@ -190,13 +196,14 @@ public static IRealTimeCompletion GetRealTimeCompletion(IServiceProvider service
return completer;
}
- private static (string, string) GetProviderAndModel(IServiceProvider services,
+ private static (string, string) GetProviderAndModel(
+ IServiceProvider services,
string? provider = null,
string? model = null,
string? modelId = null,
bool? multiModal = null,
LlmModelType? modelType = null,
- bool imageGenerate = false,
+ IEnumerable? capabilities = null,
AgentLlmConfig? agentConfig = null)
{
var agentSetting = services.GetRequiredService();
@@ -220,9 +227,9 @@ private static (string, string) GetProviderAndModel(IServiceProvider services,
var modelIdentity = state.ContainsState("model_id") ? state.GetState("model_id") : modelId;
var llmProviderService = services.GetRequiredService();
model = llmProviderService.GetProviderModel(provider, modelIdentity,
- multiModal: multiModal,
+ multiModal: multiModal,
modelType: modelType,
- imageGenerate: imageGenerate)?.Name;
+ capabilities: capabilities)?.Name;
}
}
diff --git a/src/Infrastructure/BotSharp.Core/Infrastructures/LlmProviderService.cs b/src/Infrastructure/BotSharp.Core/Infrastructures/LlmProviderService.cs
index 95cfd9c04..3445d3c00 100644
--- a/src/Infrastructure/BotSharp.Core/Infrastructures/LlmProviderService.cs
+++ b/src/Infrastructure/BotSharp.Core/Infrastructures/LlmProviderService.cs
@@ -1,4 +1,5 @@
using BotSharp.Abstraction.MLTasks;
+using BotSharp.Abstraction.MLTasks.Filters;
using BotSharp.Abstraction.MLTasks.Settings;
using BotSharp.Abstraction.Settings;
@@ -40,14 +41,12 @@ public List GetProviderModels(string provider)
{
var settingService = _services.GetRequiredService();
return settingService.Bind>($"LlmProviders")
- .FirstOrDefault(x => x.Provider.Equals(provider))
- ?.Models ?? new List();
+ .FirstOrDefault(x => x.Provider.Equals(provider))?.Models ?? [];
}
- public LlmModelSetting GetProviderModel(string provider, string id, bool? multiModal = null, LlmModelType? modelType = null, bool imageGenerate = false)
+ public LlmModelSetting? GetProviderModel(string provider, string id, bool? multiModal = null, LlmModelType? modelType = null, IEnumerable? capabilities = null)
{
- var models = GetProviderModels(provider)
- .Where(x => x.Id == id);
+ var models = GetProviderModels(provider).Where(x => x.Id == id);
if (multiModal.HasValue)
{
@@ -59,7 +58,15 @@ public LlmModelSetting GetProviderModel(string provider, string id, bool? multiM
models = models.Where(x => x.Type == modelType.Value);
}
- models = models.Where(x => x.ImageGeneration == imageGenerate);
+ if (capabilities != null)
+ {
+ models = models.Where(x => x.Capabilities != null && capabilities.Any(y => x.Capabilities.Contains(y)));
+ }
+
+ if (models.IsNullOrEmpty())
+ {
+ return null;
+ }
var random = new Random();
var index = random.Next(0, models.Count());
@@ -72,14 +79,14 @@ public LlmModelSetting GetProviderModel(string provider, string id, bool? multiM
var settings = _services.GetRequiredService>();
var providerSetting = settings.FirstOrDefault(p =>
p.Provider.Equals(provider, StringComparison.CurrentCultureIgnoreCase));
+
if (providerSetting == null)
{
_logger.LogError($"Can't find provider settings for {provider}");
return null;
}
- var modelSetting = providerSetting.Models.FirstOrDefault(m =>
- m.Name.Equals(model, StringComparison.CurrentCultureIgnoreCase));
+ var modelSetting = providerSetting.Models.FirstOrDefault(m => m.Name.Equals(model, StringComparison.CurrentCultureIgnoreCase));
if (modelSetting == null)
{
_logger.LogError($"Can't find model settings for {provider}.{model}");
@@ -95,42 +102,67 @@ public LlmModelSetting GetProviderModel(string provider, string id, bool? multiM
m.Group.Equals(modelSetting.Group, StringComparison.CurrentCultureIgnoreCase))
.ToList();
- // pick one model randomly
- var random = new Random();
- var index = random.Next(0, models.Count());
- modelSetting = models.ElementAt(index);
+ if (!models.IsNullOrEmpty())
+ {
+ // pick one model randomly
+ var random = new Random();
+ var index = random.Next(0, models.Count());
+ modelSetting = models.ElementAt(index);
+ }
}
return modelSetting;
}
- public List GetLlmConfigs(LlmConfigOptions? options = null)
+ public List GetLlmConfigs(LlmConfigFilter? filter = null)
{
var settingService = _services.GetRequiredService();
var providers = settingService.Bind>($"LlmProviders");
var configs = new List();
+ var comparer = StringComparer.OrdinalIgnoreCase;
+
+ if (providers.IsNullOrEmpty())
+ {
+ return configs;
+ }
- if (providers.IsNullOrEmpty()) return configs;
+ if (filter == null)
+ {
+ return providers ?? [];
+ }
- if (options == null) return providers ?? [];
+ if (filter.Providers != null)
+ {
+ providers = providers.Where(x => filter.Providers.Contains(x.Provider, comparer)).ToList();
+ }
foreach (var provider in providers)
{
- var models = provider.Models ?? [];
- if (options.Type.HasValue)
+ IEnumerable models = provider.Models ?? [];
+ if (filter.ModelTypes != null)
+ {
+ models = models.Where(x => filter.ModelTypes.Contains(x.Type));
+ }
+
+ if (filter.ModelIds != null)
+ {
+ models = models.Where(x => filter.ModelIds.Contains(x.Id, comparer));
+ }
+
+ if (filter.ModelNames != null)
{
- models = models.Where(x => x.Type == options.Type.Value).ToList();
+ models = models.Where(x => filter.ModelNames.Contains(x.Name, comparer));
}
- if (options.MultiModal.HasValue)
+ if (filter.ModelCapabilities != null)
{
- models = models.Where(x => x.MultiModal == options.MultiModal.Value).ToList();
+ models = models.Where(x => x.Capabilities != null && filter.ModelCapabilities.Any(y => x.Capabilities.Contains(y)));
}
- if (options.ImageGeneration.HasValue)
+ if (filter.MultiModal.HasValue)
{
- models = models.Where(x => x.ImageGeneration == options.ImageGeneration.Value).ToList();
+ models = models.Where(x => x.MultiModal == filter.MultiModal.Value);
}
if (models.IsNullOrEmpty())
@@ -138,7 +170,7 @@ public List GetLlmConfigs(LlmConfigOptions? options = null)
continue;
}
- provider.Models = models;
+ provider.Models = models.ToList();
configs.Add(provider);
}
diff --git a/src/Infrastructure/BotSharp.Core/Instructs/Services/InstructService.Execute.cs b/src/Infrastructure/BotSharp.Core/Instructs/Services/InstructService.Execute.cs
index 43accacce..8960ecf63 100644
--- a/src/Infrastructure/BotSharp.Core/Instructs/Services/InstructService.Execute.cs
+++ b/src/Infrastructure/BotSharp.Core/Instructs/Services/InstructService.Execute.cs
@@ -193,9 +193,9 @@ await hook.OnResponseGenerated(new InstructResponseModel
// Get code script name
var scriptName = string.Empty;
- if (!string.IsNullOrEmpty(codeOptions?.CodeScriptName))
+ if (!string.IsNullOrEmpty(codeOptions?.ScriptName))
{
- scriptName = codeOptions.CodeScriptName;
+ scriptName = codeOptions.ScriptName;
}
else if (!string.IsNullOrEmpty(templateName))
{
@@ -211,7 +211,8 @@ await hook.OnResponseGenerated(new InstructResponseModel
}
// Get code script
- var codeScript = await agentService.GetAgentCodeScript(agent.Id, scriptName, scriptType: AgentCodeScriptType.Src);
+ var scriptType = codeOptions?.ScriptType ?? AgentCodeScriptType.Src;
+ var codeScript = await agentService.GetAgentCodeScript(agent.Id, scriptName, scriptType);
if (string.IsNullOrWhiteSpace(codeScript))
{
#if DEBUG
@@ -230,6 +231,7 @@ await hook.OnResponseGenerated(new InstructResponseModel
var context = new CodeInstructContext
{
CodeScript = codeScript,
+ ScriptType = scriptType,
Arguments = arguments
};
diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs
index bd2599526..c6b1e3a45 100644
--- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs
+++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs
@@ -1,3 +1,4 @@
+using BotSharp.Abstraction.Agents.Options;
using BotSharp.Abstraction.Routing.Models;
using System.IO;
using System.Text.RegularExpressions;
@@ -91,10 +92,16 @@ public void UpdateAgent(Agent agent, AgentField field)
#region Update Agent Fields
private void UpdateAgentName(string agentId, string name)
{
- if (string.IsNullOrWhiteSpace(name)) return;
+ if (string.IsNullOrWhiteSpace(name))
+ {
+ return;
+ }
var (agent, agentFile) = GetAgentFromFile(agentId);
- if (agent == null) return;
+ if (agent == null)
+ {
+ return;
+ }
agent.Name = name;
agent.UpdatedDateTime = DateTime.UtcNow;
@@ -104,10 +111,16 @@ private void UpdateAgentName(string agentId, string name)
private void UpdateAgentDescription(string agentId, string description)
{
- if (string.IsNullOrWhiteSpace(description)) return;
+ if (string.IsNullOrWhiteSpace(description))
+ {
+ return;
+ }
var (agent, agentFile) = GetAgentFromFile(agentId);
- if (agent == null) return;
+ if (agent == null)
+ {
+ return;
+ }
agent.Description = description;
agent.UpdatedDateTime = DateTime.UtcNow;
@@ -118,7 +131,10 @@ private void UpdateAgentDescription(string agentId, string description)
private void UpdateAgentIsPublic(string agentId, bool isPublic)
{
var (agent, agentFile) = GetAgentFromFile(agentId);
- if (agent == null) return;
+ if (agent == null)
+ {
+ return;
+ }
agent.IsPublic = isPublic;
agent.UpdatedDateTime = DateTime.UtcNow;
@@ -129,7 +145,10 @@ private void UpdateAgentIsPublic(string agentId, bool isPublic)
private void UpdateAgentDisabled(string agentId, bool disabled)
{
var (agent, agentFile) = GetAgentFromFile(agentId);
- if (agent == null) return;
+ if (agent == null)
+ {
+ return;
+ }
agent.Disabled = disabled;
agent.UpdatedDateTime = DateTime.UtcNow;
@@ -140,7 +159,10 @@ private void UpdateAgentDisabled(string agentId, bool disabled)
private void UpdateAgentType(string agentId, string type)
{
var (agent, agentFile) = GetAgentFromFile(agentId);
- if (agent == null) return;
+ if (agent == null)
+ {
+ return;
+ }
agent.Type = type;
agent.UpdatedDateTime = DateTime.UtcNow;
@@ -151,7 +173,10 @@ private void UpdateAgentType(string agentId, string type)
private void UpdateAgentRoutingMode(string agentId, string? mode)
{
var (agent, agentFile) = GetAgentFromFile(agentId);
- if (agent == null) return;
+ if (agent == null)
+ {
+ return;
+ }
agent.Mode = mode;
agent.UpdatedDateTime = DateTime.UtcNow;
@@ -162,7 +187,10 @@ private void UpdateAgentRoutingMode(string agentId, string? mode)
private void UpdateAgentFuncVisMode(string agentId, string? visMode)
{
var (agent, agentFile) = GetAgentFromFile(agentId);
- if (agent == null) return;
+ if (agent == null)
+ {
+ return;
+ }
agent.FuncVisMode = visMode;
agent.UpdatedDateTime = DateTime.UtcNow;
@@ -173,7 +201,10 @@ private void UpdateAgentFuncVisMode(string agentId, string? visMode)
private void UpdateAgentInheritAgentId(string agentId, string? inheritAgentId)
{
var (agent, agentFile) = GetAgentFromFile(agentId);
- if (agent == null) return;
+ if (agent == null)
+ {
+ return;
+ }
agent.InheritAgentId = inheritAgentId;
agent.UpdatedDateTime = DateTime.UtcNow;
@@ -183,10 +214,16 @@ private void UpdateAgentInheritAgentId(string agentId, string? inheritAgentId)
private void UpdateAgentProfiles(string agentId, List profiles)
{
- if (profiles == null) return;
+ if (profiles == null)
+ {
+ return;
+ }
var (agent, agentFile) = GetAgentFromFile(agentId);
- if (agent == null) return;
+ if (agent == null)
+ {
+ return;
+ }
agent.Profiles = profiles;
agent.UpdatedDateTime = DateTime.UtcNow;
@@ -196,10 +233,16 @@ private void UpdateAgentProfiles(string agentId, List profiles)
public bool UpdateAgentLabels(string agentId, List labels)
{
- if (labels == null) return false;
+ if (labels == null)
+ {
+ return false;
+ }
var (agent, agentFile) = GetAgentFromFile(agentId);
- if (agent == null) return false;
+ if (agent == null)
+ {
+ return false;
+ }
agent.Labels = labels;
agent.UpdatedDateTime = DateTime.UtcNow;
@@ -210,10 +253,16 @@ public bool UpdateAgentLabels(string agentId, List labels)
private void UpdateAgentUtilities(string agentId, bool mergeUtility, List utilities)
{
- if (utilities == null) return;
+ if (utilities == null)
+ {
+ return;
+ }
var (agent, agentFile) = GetAgentFromFile(agentId);
- if (agent == null) return;
+ if (agent == null)
+ {
+ return;
+ }
agent.MergeUtility = mergeUtility;
agent.Utilities = utilities;
@@ -224,11 +273,16 @@ private void UpdateAgentUtilities(string agentId, bool mergeUtility, List mcptools)
{
- if (mcptools == null) return;
+ if (mcptools == null)
+ {
+ return;
+ }
var (agent, agentFile) = GetAgentFromFile(agentId);
- if (agent == null) return;
-
+ if (agent == null)
+ {
+ return;
+ }
agent.McpTools = mcptools;
agent.UpdatedDateTime = DateTime.UtcNow;
@@ -238,10 +292,16 @@ private void UpdateAgentMcpTools(string agentId, List mcptools)
private void UpdateAgentKnowledgeBases(string agentId, List knowledgeBases)
{
- if (knowledgeBases == null) return;
+ if (knowledgeBases == null)
+ {
+ return;
+ }
var (agent, agentFile) = GetAgentFromFile(agentId);
- if (agent == null) return;
+ if (agent == null)
+ {
+ return;
+ }
agent.KnowledgeBases = knowledgeBases;
agent.UpdatedDateTime = DateTime.UtcNow;
@@ -251,10 +311,16 @@ private void UpdateAgentKnowledgeBases(string agentId, List
private void UpdateAgentRules(string agentId, List rules)
{
- if (rules == null) return;
+ if (rules == null)
+ {
+ return;
+ }
var (agent, agentFile) = GetAgentFromFile(agentId);
- if (agent == null) return;
+ if (agent == null)
+ {
+ return;
+ }
agent.Rules = rules;
agent.UpdatedDateTime = DateTime.UtcNow;
@@ -264,10 +330,16 @@ private void UpdateAgentRules(string agentId, List rules)
private void UpdateAgentRoutingRules(string agentId, List rules)
{
- if (rules == null) return;
+ if (rules == null)
+ {
+ return;
+ }
var (agent, agentFile) = GetAgentFromFile(agentId);
- if (agent == null) return;
+ if (agent == null)
+ {
+ return;
+ }
agent.RoutingRules = rules;
agent.UpdatedDateTime = DateTime.UtcNow;
@@ -277,10 +349,16 @@ private void UpdateAgentRoutingRules(string agentId, List rules)
private void UpdateAgentInstructions(string agentId, string instruction, List channelInstructions)
{
- if (string.IsNullOrWhiteSpace(instruction)) return;
+ if (string.IsNullOrWhiteSpace(instruction))
+ {
+ return;
+ }
var (agent, agentFile) = GetAgentFromFile(agentId);
- if (agent == null) return;
+ if (agent == null)
+ {
+ return;
+ }
var instructionDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId, AGENT_INSTRUCTIONS_FOLDER);
DeleteBeforeCreateDirectory(instructionDir);
@@ -293,7 +371,10 @@ private void UpdateAgentInstructions(string agentId, string instruction, List inputFunctions)
{
- if (inputFunctions == null) return;
+ if (inputFunctions == null)
+ {
+ return;
+ }
var (agent, agentFile) = GetAgentFromFile(agentId);
- if (agent == null) return;
+ if (agent == null)
+ {
+ return;
+ }
var functionDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId, AGENT_FUNCTIONS_FOLDER);
DeleteBeforeCreateDirectory(functionDir);
foreach (var func in inputFunctions)
{
- if (string.IsNullOrWhiteSpace(func.Name)) continue;
+ if (string.IsNullOrWhiteSpace(func.Name))
+ {
+ continue;
+ }
var text = JsonSerializer.Serialize(func, _options);
var file = Path.Combine(functionDir, $"{func.Name}.json");
@@ -324,10 +414,16 @@ private void UpdateAgentFunctions(string agentId, List inputFunctio
private void UpdateAgentTemplates(string agentId, List templates)
{
- if (templates == null) return;
+ if (templates == null)
+ {
+ return;
+ }
var (agent, agentFile) = GetAgentFromFile(agentId);
- if (agent == null) return;
+ if (agent == null)
+ {
+ return;
+ }
var templateDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId, AGENT_TEMPLATES_FOLDER);
DeleteBeforeCreateDirectory(templateDir);
@@ -341,10 +437,16 @@ private void UpdateAgentTemplates(string agentId, List templates)
private void UpdateAgentResponses(string agentId, List responses)
{
- if (responses == null) return;
+ if (responses == null)
+ {
+ return;
+ }
var (agent, agentFile) = GetAgentFromFile(agentId);
- if (agent == null) return;
+ if (agent == null)
+ {
+ return;
+ }
var responseDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId, AGENT_RESPONSES_FOLDER);
DeleteBeforeCreateDirectory(responseDir);
@@ -360,10 +462,16 @@ private void UpdateAgentResponses(string agentId, List responses)
private void UpdateAgentSamples(string agentId, List samples)
{
- if (samples == null) return;
+ if (samples == null)
+ {
+ return;
+ }
var (agent, agentFile) = GetAgentFromFile(agentId);
- if (agent == null) return;
+ if (agent == null)
+ {
+ return;
+ }
var file = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId, AGENT_SAMPLES_FILE);
File.WriteAllLines(file, samples);
@@ -372,7 +480,10 @@ private void UpdateAgentSamples(string agentId, List samples)
private void UpdateAgentLlmConfig(string agentId, AgentLlmConfig? config)
{
var (agent, agentFile) = GetAgentFromFile(agentId);
- if (agent == null) return;
+ if (agent == null)
+ {
+ return;
+ }
agent.LlmConfig = config;
agent.UpdatedDateTime = DateTime.UtcNow;
@@ -383,7 +494,10 @@ private void UpdateAgentLlmConfig(string agentId, AgentLlmConfig? config)
private void UpdateAgentMaxMessageCount(string agentId, int? maxMessageCount)
{
var (agent, agentFile) = GetAgentFromFile(agentId);
- if (agent == null) return;
+ if (agent == null)
+ {
+ return;
+ }
agent.MaxMessageCount = maxMessageCount;
agent.UpdatedDateTime = DateTime.UtcNow;
@@ -394,7 +508,10 @@ private void UpdateAgentMaxMessageCount(string agentId, int? maxMessageCount)
private void UpdateAgentAllFields(Agent inputAgent)
{
var (agent, agentFile) = GetAgentFromFile(inputAgent.Id);
- if (agent == null) return;
+ if (agent == null)
+ {
+ return;
+ }
agent.Name = inputAgent.Name;
agent.Type = inputAgent.Type;
@@ -429,9 +546,12 @@ public List GetAgentResponses(string agentId, string prefix, string inte
{
var responses = new List();
var dir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId, AGENT_RESPONSES_FOLDER);
- if (!Directory.Exists(dir)) return responses;
+ if (!Directory.Exists(dir))
+ {
+ return responses;
+ }
- foreach (var file in Directory.GetFiles(dir))
+ foreach (var file in Directory.EnumerateFiles(dir))
{
if (file.Split(Path.DirectorySeparatorChar)
.Last()
@@ -447,17 +567,26 @@ public List GetAgentResponses(string agentId, string prefix, string inte
public Agent? GetAgent(string agentId, bool basicsOnly = false)
{
var agentDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir);
- var dir = Directory.GetDirectories(agentDir).FirstOrDefault(x => x.Split(Path.DirectorySeparatorChar).Last() == agentId);
+ var dir = Directory.EnumerateDirectories(agentDir).FirstOrDefault(x => x.Split(Path.DirectorySeparatorChar).Last() == agentId);
if (!string.IsNullOrEmpty(dir))
{
var json = File.ReadAllText(Path.Combine(dir, AGENT_FILE));
- if (string.IsNullOrEmpty(json)) return null;
+ if (string.IsNullOrEmpty(json))
+ {
+ return null;
+ }
var record = JsonSerializer.Deserialize(json, _options);
- if (record == null) return null;
+ if (record == null)
+ {
+ return null;
+ }
- if (basicsOnly) return record;
+ if (basicsOnly)
+ {
+ return record;
+ }
var (defaultInstruction, channelInstructions) = FetchInstructions(dir);
var functions = FetchFunctions(dir);
@@ -529,14 +658,20 @@ join u in Users on ua.UserId equals u.Id
where ua.UserId == userId || u.ExternalId == userId
select ua).ToList();
- if (found.IsNullOrEmpty()) return [];
+ if (found.IsNullOrEmpty())
+ {
+ return [];
+ }
var agentIds = found.Select(x => x.AgentId).Distinct().ToList();
var agents = GetAgents(new AgentFilter { AgentIds = agentIds });
foreach (var item in found)
{
var agent = agents.FirstOrDefault(x => x.Id == item.AgentId);
- if (agent == null) continue;
+ if (agent == null)
+ {
+ continue;
+ }
item.Agent = agent;
}
@@ -554,9 +689,12 @@ public string GetAgentTemplate(string agentId, string templateName)
}
var dir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId, AGENT_TEMPLATES_FOLDER);
- if (!Directory.Exists(dir)) return string.Empty;
+ if (!Directory.Exists(dir))
+ {
+ return string.Empty;
+ }
- foreach (var file in Directory.GetFiles(dir))
+ foreach (var file in Directory.EnumerateFiles(dir))
{
var fileName = file.Split(Path.DirectorySeparatorChar).Last();
var splitIdx = fileName.LastIndexOf(".");
@@ -573,19 +711,28 @@ public string GetAgentTemplate(string agentId, string templateName)
public bool PatchAgentTemplate(string agentId, AgentTemplate template)
{
- if (string.IsNullOrEmpty(agentId) || template == null) return false;
+ if (string.IsNullOrEmpty(agentId) || template == null)
+ {
+ return false;
+ }
var dir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId, AGENT_TEMPLATES_FOLDER);
- if (!Directory.Exists(dir)) return false;
+ if (!Directory.Exists(dir))
+ {
+ return false;
+ }
- var foundTemplate = Directory.GetFiles(dir).FirstOrDefault(f =>
+ var foundTemplate = Directory.EnumerateFiles(dir).FirstOrDefault(f =>
{
var fileName = Path.GetFileNameWithoutExtension(f);
var extension = Path.GetExtension(f).Substring(1);
return fileName.IsEqualTo(template.Name) && extension.IsEqualTo(_agentSettings.TemplateFormat);
});
- if (foundTemplate == null) return false;
+ if (foundTemplate == null)
+ {
+ return false;
+ }
File.WriteAllText(foundTemplate, template.Content);
return true;
@@ -593,10 +740,16 @@ public bool PatchAgentTemplate(string agentId, AgentTemplate template)
public bool AppendAgentLabels(string agentId, List labels)
{
- if (labels.IsNullOrEmpty()) return false;
+ if (labels.IsNullOrEmpty())
+ {
+ return false;
+ }
var (agent, agentFile) = GetAgentFromFile(agentId);
- if (agent == null) return false;
+ if (agent == null)
+ {
+ return false;
+ }
var prevLabels = agent.Labels ?? [];
var curLabels = prevLabels.Concat(labels).Distinct().ToList();
@@ -609,13 +762,19 @@ public bool AppendAgentLabels(string agentId, List labels)
public void BulkInsertAgents(List agents)
{
- if (agents.IsNullOrEmpty()) return;
+ if (agents.IsNullOrEmpty())
+ {
+ return;
+ }
var baseDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir);
foreach (var agent in agents)
{
var dir = Path.Combine(baseDir, agent.Id);
- if (Directory.Exists(dir)) continue;
+ if (Directory.Exists(dir))
+ {
+ continue;
+ }
Directory.CreateDirectory(dir);
Thread.Sleep(50);
@@ -638,7 +797,10 @@ public void BulkInsertAgents(List agents)
public void BulkInsertUserAgents(List userAgents)
{
- if (userAgents.IsNullOrEmpty()) return;
+ if (userAgents.IsNullOrEmpty())
+ {
+ return;
+ }
var groups = userAgents.GroupBy(x => x.UserId);
var usersDir = Path.Combine(_dbSettings.FileRepository, USERS_FOLDER);
@@ -646,12 +808,18 @@ public void BulkInsertUserAgents(List userAgents)
foreach (var group in groups)
{
var filtered = group.Where(x => !string.IsNullOrEmpty(x.UserId) && !string.IsNullOrEmpty(x.AgentId)).ToList();
- if (filtered.IsNullOrEmpty()) continue;
+ if (filtered.IsNullOrEmpty())
+ {
+ continue;
+ }
filtered.ForEach(x => x.Id = Guid.NewGuid().ToString());
var userId = filtered.First().UserId;
var userDir = Path.Combine(usersDir, userId);
- if (!Directory.Exists(userDir)) continue;
+ if (!Directory.Exists(userDir))
+ {
+ continue;
+ }
var userAgentFile = Path.Combine(userDir, USER_AGENT_FILE);
var list = new List();
@@ -674,48 +842,72 @@ public bool DeleteAgents()
return false;
}
- public bool DeleteAgent(string agentId)
+ public bool DeleteAgent(string agentId, AgentDeleteOptions? options = null)
{
- if (string.IsNullOrEmpty(agentId)) return false;
+ if (string.IsNullOrEmpty(agentId))
+ {
+ return false;
+ }
try
{
var agentDir = GetAgentDataDir(agentId);
- if (string.IsNullOrEmpty(agentDir)) return false;
+ if (string.IsNullOrEmpty(agentDir))
+ {
+ return false;
+ }
- // Delete user agents
- var usersDir = Path.Combine(_dbSettings.FileRepository, USERS_FOLDER);
- if (Directory.Exists(usersDir))
+ if (options == null || options.DeleteUserAgents)
{
- foreach (var userDir in Directory.GetDirectories(usersDir))
+ // Delete user agents
+ var usersDir = Path.Combine(_dbSettings.FileRepository, USERS_FOLDER);
+ if (Directory.Exists(usersDir))
{
- var userAgentFile = Directory.GetFiles(userDir).FirstOrDefault(x => Path.GetFileName(x) == USER_AGENT_FILE);
- if (string.IsNullOrEmpty(userAgentFile)) continue;
-
- var text = File.ReadAllText(userAgentFile);
- var userAgents = JsonSerializer.Deserialize>(text, _options);
- if (userAgents.IsNullOrEmpty()) continue;
-
- userAgents = userAgents?.Where(x => x.AgentId != agentId)?.ToList() ?? [];
- File.WriteAllText(userAgentFile, JsonSerializer.Serialize(userAgents, _options));
+ foreach (var userDir in Directory.EnumerateDirectories(usersDir))
+ {
+ var userAgentFile = Directory.GetFiles(userDir).FirstOrDefault(x => Path.GetFileName(x) == USER_AGENT_FILE);
+ if (string.IsNullOrEmpty(userAgentFile))
+ {
+ continue;
+ }
+
+ var text = File.ReadAllText(userAgentFile);
+ var userAgents = JsonSerializer.Deserialize>(text, _options);
+ if (userAgents.IsNullOrEmpty())
+ {
+ continue;
+ }
+
+ userAgents = userAgents?.Where(x => x.AgentId != agentId)?.ToList() ?? [];
+ File.WriteAllText(userAgentFile, JsonSerializer.Serialize(userAgents, _options));
+ }
}
}
-
- // Delete role agents
- var rolesDir = Path.Combine(_dbSettings.FileRepository, ROLES_FOLDER);
- if (Directory.Exists(rolesDir))
+
+ if (options == null || options.DeleteRoleAgents)
{
- foreach (var roleDir in Directory.GetDirectories(rolesDir))
+ // Delete role agents
+ var rolesDir = Path.Combine(_dbSettings.FileRepository, ROLES_FOLDER);
+ if (Directory.Exists(rolesDir))
{
- var roleAgentFile = Directory.GetFiles(roleDir).FirstOrDefault(x => Path.GetFileName(x) == ROLE_AGENT_FILE);
- if (string.IsNullOrEmpty(roleAgentFile)) continue;
-
- var text = File.ReadAllText(roleAgentFile);
- var roleAgents = JsonSerializer.Deserialize>(text, _options);
- if (roleAgents.IsNullOrEmpty()) continue;
-
- roleAgents = roleAgents?.Where(x => x.AgentId != agentId)?.ToList() ?? [];
- File.WriteAllText(roleAgentFile, JsonSerializer.Serialize(roleAgents, _options));
+ foreach (var roleDir in Directory.EnumerateDirectories(rolesDir))
+ {
+ var roleAgentFile = Directory.GetFiles(roleDir).FirstOrDefault(x => Path.GetFileName(x) == ROLE_AGENT_FILE);
+ if (string.IsNullOrEmpty(roleAgentFile))
+ {
+ continue;
+ }
+
+ var text = File.ReadAllText(roleAgentFile);
+ var roleAgents = JsonSerializer.Deserialize>(text, _options);
+ if (roleAgents.IsNullOrEmpty())
+ {
+ continue;
+ }
+
+ roleAgents = roleAgents?.Where(x => x.AgentId != agentId)?.ToList() ?? [];
+ File.WriteAllText(roleAgentFile, JsonSerializer.Serialize(roleAgents, _options));
+ }
}
}
diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.AgentCodeScript.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.AgentCodeScript.cs
index b085ad34b..7ebfdc84f 100644
--- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.AgentCodeScript.cs
+++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.AgentCodeScript.cs
@@ -65,7 +65,7 @@ public List GetAgentCodeScripts(string agentId, AgentCodeScript
return null;
}
- var foundFile = Directory.GetFiles(dir).FirstOrDefault(file => scriptName.IsEqualTo(Path.GetFileName(file)));
+ var foundFile = Directory.EnumerateFiles(dir).FirstOrDefault(file => scriptName.IsEqualTo(Path.GetFileName(file)));
if (!string.IsNullOrEmpty(foundFile))
{
return File.ReadAllText(foundFile);
@@ -91,7 +91,14 @@ public bool UpdateAgentCodeScripts(string agentId, List scripts
var dir = BuildAgentCodeScriptDir(agentId, script.ScriptType);
if (!Directory.Exists(dir))
{
- continue;
+ if (options?.IsUpsert == true)
+ {
+ Directory.CreateDirectory(dir);
+ }
+ else
+ {
+ continue;
+ }
}
var file = Path.Combine(dir, script.Name);
@@ -106,7 +113,7 @@ public bool UpdateAgentCodeScripts(string agentId, List scripts
public bool BulkInsertAgentCodeScripts(string agentId, List scripts)
{
- return UpdateAgentCodeScripts(agentId, scripts);
+ return UpdateAgentCodeScripts(agentId, scripts, options: new() { IsUpsert = true });
}
public bool DeleteAgentCodeScripts(string agentId, List? scripts = null)
@@ -117,14 +124,12 @@ public bool DeleteAgentCodeScripts(string agentId, List? script
}
var dir = BuildAgentCodeScriptDir(agentId);
- if (!Directory.Exists(dir))
- {
- return false;
- }
-
if (scripts == null)
{
- Directory.Delete(dir, true);
+ if (Directory.Exists(dir))
+ {
+ Directory.Delete(dir, true);
+ }
return true;
}
else if (!scripts.Any())
@@ -132,6 +137,11 @@ public bool DeleteAgentCodeScripts(string agentId, List? script
return false;
}
+ if (!Directory.Exists(dir))
+ {
+ return false;
+ }
+
var dict = scripts.DistinctBy(x => x.CodePath).ToDictionary(x => x.CodePath, x => x);
foreach (var pair in dict)
{
diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.AgentTask.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.AgentTask.cs
index b3926e66f..b847b0be6 100644
--- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.AgentTask.cs
+++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.AgentTask.cs
@@ -21,12 +21,18 @@ public async ValueTask> GetAgentTasks(AgentTaskFilter filt
var matched = true;
var dir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir);
- if (!Directory.Exists(dir)) return new PagedItems();
+ if (!Directory.Exists(dir))
+ {
+ return new PagedItems();
+ }
- foreach (var agentDir in Directory.GetDirectories(dir))
+ foreach (var agentDir in Directory.EnumerateDirectories(dir))
{
var taskDir = Path.Combine(agentDir, AGENT_TASKS_FOLDER);
- if (!Directory.Exists(taskDir)) continue;
+ if (!Directory.Exists(taskDir))
+ {
+ continue;
+ }
var agentId = agentDir.Split(Path.DirectorySeparatorChar).Last();
@@ -36,13 +42,19 @@ public async ValueTask> GetAgentTasks(AgentTaskFilter filt
matched = agentId == filter.AgentId;
}
- if (!matched) continue;
+ if (!matched)
+ {
+ continue;
+ }
var curTasks = new List();
- foreach (var taskFile in Directory.GetFiles(taskDir))
+ foreach (var taskFile in Directory.EnumerateFiles(taskDir))
{
var task = ParseAgentTask(taskFile);
- if (task == null) continue;
+ if (task == null)
+ {
+ continue;
+ }
matched = true;
if (filter?.Enabled != null)
@@ -55,10 +67,16 @@ public async ValueTask> GetAgentTasks(AgentTaskFilter filt
matched = matched && task.Status == filter.Status;
}
- if (!matched) continue;
+ if (!matched)
+ {
+ continue;
+ }
totalCount++;
- if (takeCount >= pager.Size) continue;
+ if (takeCount >= pager.Size)
+ {
+ continue;
+ }
if (skipCount < pager.Offset)
{
@@ -71,7 +89,10 @@ public async ValueTask> GetAgentTasks(AgentTaskFilter filt
}
}
- if (curTasks.IsNullOrEmpty()) continue;
+ if (curTasks.IsNullOrEmpty())
+ {
+ continue;
+ }
var agent = ParseAgent(agentDir);
curTasks.ForEach(t =>
@@ -92,16 +113,28 @@ public async ValueTask> GetAgentTasks(AgentTaskFilter filt
public AgentTask? GetAgentTask(string agentId, string taskId)
{
var agentDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId);
- if (!Directory.Exists(agentDir)) return null;
+ if (!Directory.Exists(agentDir))
+ {
+ return null;
+ }
var taskDir = Path.Combine(agentDir, AGENT_TASKS_FOLDER);
- if (!Directory.Exists(taskDir)) return null;
+ if (!Directory.Exists(taskDir))
+ {
+ return null;
+ }
var taskFile = FindTaskFileById(taskDir, taskId);
- if (taskFile == null) return null;
+ if (taskFile == null)
+ {
+ return null;
+ }
var task = ParseAgentTask(taskFile);
- if (task == null) return null;
+ if (task == null)
+ {
+ return null;
+ }
var agent = ParseAgent(agentDir);
task.AgentId = agentId;
@@ -111,10 +144,16 @@ public async ValueTask> GetAgentTasks(AgentTaskFilter filt
public void InsertAgentTask(AgentTask task)
{
- if (task == null || string.IsNullOrEmpty(task.AgentId)) return;
+ if (task == null || string.IsNullOrEmpty(task.AgentId))
+ {
+ return;
+ }
var agentDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, task.AgentId);
- if (!Directory.Exists(agentDir)) return;
+ if (!Directory.Exists(agentDir))
+ {
+ return;
+ }
var taskDir = Path.Combine(agentDir, AGENT_TASKS_FOLDER);
if (!Directory.Exists(taskDir))
@@ -144,19 +183,34 @@ public void BulkInsertAgentTasks(string agentId, List tasks)
public void UpdateAgentTask(AgentTask task, AgentTaskField field)
{
- if (task == null || string.IsNullOrEmpty(task.Id)) return;
+ if (task == null || string.IsNullOrEmpty(task.Id))
+ {
+ return;
+ }
var agentDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, task.AgentId);
- if (!Directory.Exists(agentDir)) return;
+ if (!Directory.Exists(agentDir))
+ {
+ return;
+ }
var taskDir = Path.Combine(agentDir, AGENT_TASKS_FOLDER);
- if (!Directory.Exists(taskDir)) return;
+ if (!Directory.Exists(taskDir))
+ {
+ return;
+ }
var taskFile = FindTaskFileById(taskDir, task.Id);
- if (string.IsNullOrEmpty(taskFile)) return;
+ if (string.IsNullOrEmpty(taskFile))
+ {
+ return;
+ }
var parsedTask = ParseAgentTask(taskFile);
- if (parsedTask == null) return;
+ if (parsedTask == null)
+ {
+ return;
+ }
var metaData = new AgentTask
{
@@ -218,7 +272,10 @@ public bool DeleteAgentTasks(string agentId, List? taskIds = null)
foreach (var taskId in taskIds)
{
var taskFile = FindTaskFileById(taskDir, taskId);
- if (string.IsNullOrWhiteSpace(taskFile)) continue;
+ if (string.IsNullOrWhiteSpace(taskFile))
+ {
+ continue;
+ }
File.Delete(taskFile);
deletedTasks.Add(taskId);
@@ -229,9 +286,12 @@ public bool DeleteAgentTasks(string agentId, List? taskIds = null)
private string? FindTaskFileById(string taskDir, string taskId)
{
- if (!Directory.Exists(taskDir) || string.IsNullOrEmpty(taskId)) return null;
+ if (!Directory.Exists(taskDir) || string.IsNullOrEmpty(taskId))
+ {
+ return null;
+ }
- var taskFile = Directory.GetFiles(taskDir).FirstOrDefault(file =>
+ var taskFile = Directory.EnumerateFiles(taskDir).FirstOrDefault(file =>
{
var fileName = file.Split(Path.DirectorySeparatorChar).Last();
var id = fileName.Split('.').First();
diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Conversation.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Conversation.cs
index 68881ea37..a3cece2c1 100644
--- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Conversation.cs
+++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Conversation.cs
@@ -1,6 +1,4 @@
using BotSharp.Abstraction.Loggers.Models;
-using BotSharp.Abstraction.Users.Models;
-using System;
using System.IO;
namespace BotSharp.Core.Repository;
@@ -53,12 +51,18 @@ public void CreateNewConversation(Conversation conversation)
public bool DeleteConversations(IEnumerable conversationIds)
{
- if (conversationIds.IsNullOrEmpty()) return false;
+ if (conversationIds.IsNullOrEmpty())
+ {
+ return false;
+ }
foreach (var conversationId in conversationIds)
{
var convDir = FindConversationDirectory(conversationId);
- if (string.IsNullOrEmpty(convDir)) continue;
+ if (string.IsNullOrEmpty(convDir))
+ {
+ continue;
+ }
Directory.Delete(convDir, true);
}
@@ -161,13 +165,22 @@ public void UpdateConversationTitleAlias(string conversationId, string titleAlia
public bool UpdateConversationTags(string conversationId, List toAddTags, List toDeleteTags)
{
- if (string.IsNullOrEmpty(conversationId)) return false;
+ if (string.IsNullOrEmpty(conversationId))
+ {
+ return false;
+ }
var convDir = FindConversationDirectory(conversationId);
- if (string.IsNullOrEmpty(convDir)) return false;
+ if (string.IsNullOrEmpty(convDir))
+ {
+ return false;
+ }
var convFile = Path.Combine(convDir, CONVERSATION_FILE);
- if (!File.Exists(convFile)) return false;
+ if (!File.Exists(convFile))
+ {
+ return false;
+ }
var json = File.ReadAllText(convFile);
var conv = JsonSerializer.Deserialize(json, _options);
@@ -183,13 +196,22 @@ public bool UpdateConversationTags(string conversationId, List toAddTags
public bool AppendConversationTags(string conversationId, List tags)
{
- if (string.IsNullOrEmpty(conversationId) || tags.IsNullOrEmpty()) return false;
+ if (string.IsNullOrEmpty(conversationId) || tags.IsNullOrEmpty())
+ {
+ return false;
+ }
var convDir = FindConversationDirectory(conversationId);
- if (string.IsNullOrEmpty(convDir)) return false;
+ if (string.IsNullOrEmpty(convDir))
+ {
+ return false;
+ }
var convFile = Path.Combine(convDir, CONVERSATION_FILE);
- if (!File.Exists(convFile)) return false;
+ if (!File.Exists(convFile))
+ {
+ return false;
+ }
var json = File.ReadAllText(convFile);
var conv = JsonSerializer.Deserialize(json, _options);
@@ -204,14 +226,20 @@ public bool AppendConversationTags(string conversationId, List tags)
public bool UpdateConversationMessage(string conversationId, UpdateMessageRequest request)
{
- if (string.IsNullOrEmpty(conversationId)) return false;
+ if (string.IsNullOrEmpty(conversationId))
+ {
+ return false;
+ }
var dialogs = GetConversationDialogs(conversationId);
var candidates = dialogs.Where(x => x.MetaData.MessageId == request.Message.MetaData.MessageId
&& x.MetaData.Role == request.Message.MetaData.Role).ToList();
var found = candidates.Where((_, idx) => idx == request.InnderIndex).FirstOrDefault();
- if (found == null) return false;
+ if (found == null)
+ {
+ return false;
+ }
found.Content = request.Message.Content;
found.RichContent = request.Message.RichContent;
@@ -227,7 +255,10 @@ public bool UpdateConversationMessage(string conversationId, UpdateMessageReques
}
var convDir = FindConversationDirectory(conversationId);
- if (string.IsNullOrEmpty(convDir)) return false;
+ if (string.IsNullOrEmpty(convDir))
+ {
+ return false;
+ }
var dialogFile = Path.Combine(convDir, DIALOG_FILE);
File.WriteAllText(dialogFile, JsonSerializer.Serialize(dialogs, _options));
@@ -309,10 +340,16 @@ public ConversationState GetConversationStates(string conversationId)
[SideCar]
public void UpdateConversationStates(string conversationId, List states)
{
- if (states.IsNullOrEmpty()) return;
+ if (states.IsNullOrEmpty())
+ {
+ return;
+ }
var convDir = FindConversationDirectory(conversationId);
- if (string.IsNullOrEmpty(convDir)) return;
+ if (string.IsNullOrEmpty(convDir))
+ {
+ return;
+ }
var stateFile = Path.Combine(convDir, STATE_FILE);
if (File.Exists(stateFile))
@@ -350,7 +387,10 @@ public void UpdateConversationStatus(string conversationId, string status)
public Conversation GetConversation(string conversationId, bool isLoadStates = false)
{
var convDir = FindConversationDirectory(conversationId);
- if (string.IsNullOrEmpty(convDir)) return null;
+ if (string.IsNullOrEmpty(convDir))
+ {
+ return null;
+ }
var convFile = Path.Combine(convDir, CONVERSATION_FILE);
var content = File.ReadAllText(convFile);
@@ -401,15 +441,20 @@ public async ValueTask> GetConversations(ConversationFi
filter.AgentIds.Add(filter.AgentId);
}
- var totalDirs = Directory.GetDirectories(dir);
- foreach (var d in totalDirs)
+ foreach (var d in Directory.EnumerateDirectories(dir))
{
var convFile = Path.Combine(d, CONVERSATION_FILE);
- if (!File.Exists(convFile)) continue;
+ if (!File.Exists(convFile))
+ {
+ continue;
+ }
var json = File.ReadAllText(convFile);
var record = JsonSerializer.Deserialize(json, _options);
- if (record == null) continue;
+ if (record == null)
+ {
+ continue;
+ }
var matched = true;
if (filter?.Id != null)
@@ -475,7 +520,10 @@ public async ValueTask> GetConversations(ConversationFi
{
foreach (var pair in filter.States)
{
- if (pair == null || string.IsNullOrWhiteSpace(pair.Key)) continue;
+ if (pair == null || string.IsNullOrWhiteSpace(pair.Key))
+ {
+ continue;
+ }
var components = pair.Key.Split(".").ToList();
var primaryKey = components[0];
@@ -518,12 +566,18 @@ public async ValueTask> GetConversations(ConversationFi
matched = false;
}
- if (!matched) break;
+ if (!matched)
+ {
+ break;
+ }
}
}
}
- if (!matched) continue;
+ if (!matched)
+ {
+ continue;
+ }
if (filter.IsLoadLatestStates)
{
@@ -555,14 +609,20 @@ public List GetLastConversations()
var records = new List();
var dir = Path.Combine(_dbSettings.FileRepository, _conversationSettings.DataDir);
- foreach (var d in Directory.GetDirectories(dir))
+ foreach (var d in Directory.EnumerateDirectories(dir))
{
var path = Path.Combine(d, CONVERSATION_FILE);
- if (!File.Exists(path)) continue;
+ if (!File.Exists(path))
+ {
+ continue;
+ }
var json = File.ReadAllText(path);
var record = JsonSerializer.Deserialize(json, _options);
- if (record == null) continue;
+ if (record == null)
+ {
+ continue;
+ }
records.Add(record);
}
@@ -588,7 +648,7 @@ public List GetIdleConversations(int batchSize, int messageLimit, int bu
batchSize = batchLimit;
}
- foreach (var d in Directory.GetDirectories(dir))
+ foreach (var d in Directory.EnumerateDirectories(dir))
{
var convFile = Path.Combine(d, CONVERSATION_FILE);
if (!File.Exists(convFile))
@@ -687,12 +747,15 @@ public List TruncateConversation(string conversationId, string messageId
public List GetConversationStateSearchKeys(ConversationStateKeysFilter filter)
{
var dir = Path.Combine(_dbSettings.FileRepository, _conversationSettings.DataDir);
- if (!Directory.Exists(dir)) return [];
+ if (!Directory.Exists(dir))
+ {
+ return [];
+ }
var count = 0;
var keys = new List();
- foreach (var d in Directory.GetDirectories(dir))
+ foreach (var d in Directory.EnumerateDirectories(dir))
{
var convFile = Path.Combine(d, CONVERSATION_FILE);
var latestStateFile = Path.Combine(d, CONV_LATEST_STATE_FILE);
@@ -733,18 +796,25 @@ public List GetConversationStateSearchKeys(ConversationStateKeysFilter f
public List GetConversationsToMigrate(int batchSize = 100)
{
var baseDir = Path.Combine(_dbSettings.FileRepository, _conversationSettings.DataDir);
- if (!Directory.Exists(baseDir)) return [];
+ if (!Directory.Exists(baseDir))
+ {
+ return [];
+ }
var convIds = new List();
- var dirs = Directory.GetDirectories(baseDir);
-
- foreach (var dir in dirs)
+ foreach (var dir in Directory.EnumerateDirectories(baseDir))
{
var latestStateFile = Path.Combine(dir, CONV_LATEST_STATE_FILE);
- if (File.Exists(latestStateFile)) continue;
+ if (File.Exists(latestStateFile))
+ {
+ continue;
+ }
var convId = dir.Split(Path.DirectorySeparatorChar).Last();
- if (string.IsNullOrEmpty(convId)) continue;
+ if (string.IsNullOrEmpty(convId))
+ {
+ continue;
+ }
convIds.Add(convId);
if (convIds.Count >= batchSize)
@@ -759,7 +829,10 @@ public List GetConversationsToMigrate(int batchSize = 100)
public bool MigrateConvsersationLatestStates(string conversationId)
{
- if (string.IsNullOrEmpty(conversationId)) return false;
+ if (string.IsNullOrEmpty(conversationId))
+ {
+ return false;
+ }
var convDir = FindConversationDirectory(conversationId);
if (string.IsNullOrEmpty(convDir))
@@ -774,7 +847,6 @@ public bool MigrateConvsersationLatestStates(string conversationId)
var latestStateFile = Path.Combine(convDir, CONV_LATEST_STATE_FILE);
var stateStr = JsonSerializer.Serialize(latestStates, _options);
File.WriteAllText(latestStateFile, stateStr);
-
return true;
}
@@ -782,10 +854,16 @@ public bool MigrateConvsersationLatestStates(string conversationId)
#region Private methods
private string? FindConversationDirectory(string conversationId)
{
- if (string.IsNullOrEmpty(conversationId)) return null;
+ if (string.IsNullOrEmpty(conversationId))
+ {
+ return null;
+ }
var dir = Path.Combine(_dbSettings.FileRepository, _conversationSettings.DataDir, conversationId);
- if (!Directory.Exists(dir)) return null;
+ if (!Directory.Exists(dir))
+ {
+ return null;
+ }
return dir;
}
@@ -794,7 +872,10 @@ private List CollectDialogElements(string dialogDir)
{
var dialogs = new List();
- if (!File.Exists(dialogDir)) return dialogs;
+ if (!File.Exists(dialogDir))
+ {
+ return dialogs;
+ }
var texts = File.ReadAllText(dialogDir);
dialogs = JsonSerializer.Deserialize>(texts) ?? new List();
@@ -803,7 +884,10 @@ private List CollectDialogElements(string dialogDir)
private string ParseDialogElements(List dialogs)
{
- if (dialogs.IsNullOrEmpty()) return "[]";
+ if (dialogs.IsNullOrEmpty())
+ {
+ return "[]";
+ }
return JsonSerializer.Serialize(dialogs, _options) ?? "[]";
}
@@ -811,10 +895,16 @@ private string ParseDialogElements(List dialogs)
private List CollectConversationStates(string stateFile)
{
var states = new List();
- if (!File.Exists(stateFile)) return states;
+ if (!File.Exists(stateFile))
+ {
+ return states;
+ }
var stateStr = File.ReadAllText(stateFile);
- if (string.IsNullOrEmpty(stateStr)) return states;
+ if (string.IsNullOrEmpty(stateStr))
+ {
+ return states;
+ }
states = JsonSerializer.Deserialize>(stateStr, _options);
return states ?? new List();
@@ -823,10 +913,16 @@ private List CollectConversationStates(string stateFile)
private List CollectConversationBreakpoints(string breakpointFile)
{
var breakpoints = new List();
- if (!File.Exists(breakpointFile)) return breakpoints;
+ if (!File.Exists(breakpointFile))
+ {
+ return breakpoints;
+ }
var content = File.ReadAllText(breakpointFile);
- if (string.IsNullOrEmpty(content)) return breakpoints;
+ if (string.IsNullOrEmpty(content))
+ {
+ return breakpoints;
+ }
breakpoints = JsonSerializer.Deserialize>(content, _options);
return breakpoints ?? new List();
@@ -861,7 +957,10 @@ private bool HandleTruncatedStates(string stateDir, string latestStateDir, List<
var values = state.Values.Where(x => x.MessageId != refMsgId)
.Where(x => x.UpdateTime < refTime)
.ToList();
- if (values.Count == 0) continue;
+ if (values.Count == 0)
+ {
+ continue;
+ }
state.Values = values;
truncatedStates.Add(state);
@@ -891,11 +990,14 @@ private bool HandleTruncatedLogs(string convDir, DateTime refTime)
if (Directory.Exists(contentLogDir))
{
- foreach (var file in Directory.GetFiles(contentLogDir))
+ foreach (var file in Directory.EnumerateFiles(contentLogDir))
{
var text = File.ReadAllText(file);
var log = JsonSerializer.Deserialize(text);
- if (log == null) continue;
+ if (log == null)
+ {
+ continue;
+ }
if (log.CreatedTime >= refTime)
{
@@ -906,11 +1008,14 @@ private bool HandleTruncatedLogs(string convDir, DateTime refTime)
if (Directory.Exists(stateLogDir))
{
- foreach (var file in Directory.GetFiles(stateLogDir))
+ foreach (var file in Directory.EnumerateFiles(stateLogDir))
{
var text = File.ReadAllText(file);
var log = JsonSerializer.Deserialize(text);
- if (log == null) continue;
+ if (log == null)
+ {
+ continue;
+ }
if (log.CreatedTime >= refTime)
{
@@ -924,7 +1029,10 @@ private bool HandleTruncatedLogs(string convDir, DateTime refTime)
private bool SaveTruncatedDialogs(string dialogDir, List dialogs)
{
- if (string.IsNullOrEmpty(dialogDir) || dialogs == null) return false;
+ if (string.IsNullOrEmpty(dialogDir) || dialogs == null)
+ {
+ return false;
+ }
var texts = ParseDialogElements(dialogs);
File.WriteAllText(dialogDir, texts);
@@ -933,7 +1041,10 @@ private bool SaveTruncatedDialogs(string dialogDir, List dialogs)
private bool SaveTruncatedStates(string stateDir, List states)
{
- if (string.IsNullOrEmpty(stateDir) || states == null) return false;
+ if (string.IsNullOrEmpty(stateDir) || states == null)
+ {
+ return false;
+ }
var stateStr = JsonSerializer.Serialize(states, _options);
File.WriteAllText(stateDir, stateStr);
@@ -942,7 +1053,10 @@ private bool SaveTruncatedStates(string stateDir, List states)
private bool SaveTruncatedLatestStates(string latestStateDir, List states)
{
- if (string.IsNullOrEmpty(latestStateDir) || states == null) return false;
+ if (string.IsNullOrEmpty(latestStateDir) || states == null)
+ {
+ return false;
+ }
var latestStates = BuildLatestStates(states);
var stateStr = JsonSerializer.Serialize(latestStates, _options);
@@ -952,7 +1066,10 @@ private bool SaveTruncatedLatestStates(string latestStateDir, List breakpoints)
{
- if (string.IsNullOrEmpty(breakpointDir) || breakpoints == null) return false;
+ if (string.IsNullOrEmpty(breakpointDir) || breakpoints == null)
+ {
+ return false;
+ }
var breakpointStr = JsonSerializer.Serialize(breakpoints, _options);
File.WriteAllText(breakpointDir, breakpointStr);
@@ -961,7 +1078,10 @@ private bool SaveTruncatedBreakpoints(string breakpointDir, List CollectConversationLatestStates(string latestStateDir)
{
- if (string.IsNullOrEmpty(latestStateDir) || !File.Exists(latestStateDir)) return [];
+ if (string.IsNullOrEmpty(latestStateDir) || !File.Exists(latestStateDir))
+ {
+ return [];
+ }
var str = File.ReadAllText(latestStateDir);
var states = JsonSerializer.Deserialize>(str, _options);
@@ -979,7 +1099,10 @@ private Dictionary BuildLatestStates(List s
foreach (var pair in states)
{
var value = pair.Values?.LastOrDefault();
- if (value == null || !value.Active) continue;
+ if (value == null || !value.Active)
+ {
+ continue;
+ }
try
{
@@ -1009,7 +1132,10 @@ private Dictionary BuildLatestStates(List s
for (int i = 0; i < paths.Count(); i++)
{
- if (elem == null) return null;
+ if (elem == null)
+ {
+ return null;
+ }
var field = paths.ElementAt(i);
if (elem.Value.ValueKind == JsonValueKind.Array)
diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Crontab.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Crontab.cs
index 84f2794c3..ded762c85 100644
--- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Crontab.cs
+++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Crontab.cs
@@ -65,7 +65,6 @@ public bool DeleteCrontabItem(string conversationId)
public async ValueTask> GetCrontabItems(CrontabItemFilter filter)
{
-
if (filter == null)
{
filter = CrontabItemFilter.Empty();
@@ -79,15 +78,20 @@ public async ValueTask> GetCrontabItems(CrontabItemFilte
Directory.CreateDirectory(baseDir);
}
- var totalDirs = Directory.GetDirectories(baseDir);
- foreach (var d in totalDirs)
+ foreach (var d in Directory.EnumerateDirectories(baseDir))
{
var file = Path.Combine(d, CRON_FILE);
- if (!File.Exists(file)) continue;
+ if (!File.Exists(file))
+ {
+ continue;
+ }
var json = File.ReadAllText(file);
var record = JsonSerializer.Deserialize(json, _options);
- if (record == null) continue;
+ if (record == null)
+ {
+ continue;
+ }
var matched = true;
if (filter?.AgentIds != null)
@@ -103,7 +107,10 @@ public async ValueTask> GetCrontabItems(CrontabItemFilte
matched = matched && filter.UserIds.Contains(record.UserId);
}
- if (!matched) continue;
+ if (!matched)
+ {
+ continue;
+ }
records.Add(record);
}
diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.KnowledgeBase.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.KnowledgeBase.cs
index f245477f2..3c3ba64bc 100644
--- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.KnowledgeBase.cs
+++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.KnowledgeBase.cs
@@ -54,11 +54,17 @@ public bool AddKnowledgeCollectionConfigs(List configs,
public bool DeleteKnowledgeCollectionConfig(string collectionName)
{
- if (string.IsNullOrWhiteSpace(collectionName)) return false;
+ if (string.IsNullOrWhiteSpace(collectionName))
+ {
+ return false;
+ }
var vectorDir = BuildKnowledgeCollectionConfigDir();
var configFile = Path.Combine(vectorDir, COLLECTION_CONFIG_FILE);
- if (!File.Exists(configFile)) return false;
+ if (!File.Exists(configFile))
+ {
+ return false;
+ }
var str = File.ReadAllText(configFile);
var savedConfigs = JsonSerializer.Deserialize>(str, _options) ?? new();
@@ -139,7 +145,10 @@ public bool DeleteKnolwedgeBaseFileMeta(string collectionName, string vectorStor
}
var dir = BuildKnowledgeCollectionFileDir(collectionName, vectorStoreProvider);
- if (!Directory.Exists(dir)) return false;
+ if (!Directory.Exists(dir))
+ {
+ return false;
+ }
if (fileId == null)
{
@@ -172,14 +181,20 @@ public async ValueTask> GetKnowledgeBaseFileMet
}
var records = new List();
- foreach (var folder in Directory.GetDirectories(dir))
+ foreach (var folder in Directory.EnumerateDirectories(dir))
{
var metaFile = Path.Combine(folder, KNOWLEDGE_DOC_META_FILE);
- if (!File.Exists(metaFile)) continue;
+ if (!File.Exists(metaFile))
+ {
+ continue;
+ }
var content = File.ReadAllText(metaFile);
var metaData = JsonSerializer.Deserialize(content, _options);
- if (metaData == null) continue;
+ if (metaData == null)
+ {
+ continue;
+ }
var matched = true;
@@ -208,7 +223,10 @@ public async ValueTask> GetKnowledgeBaseFileMet
}
- if (!matched) continue;
+ if (!matched)
+ {
+ continue;
+ }
records.Add(metaData);
}
diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Log.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Log.cs
index c08514012..396e338f7 100644
--- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Log.cs
+++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Log.cs
@@ -1,5 +1,4 @@
using BotSharp.Abstraction.Loggers.Models;
-using Microsoft.IdentityModel.Logging;
using System.IO;
namespace BotSharp.Core.Repository
@@ -9,7 +8,10 @@ public partial class FileRepository
#region LLM Completion Log
public void SaveLlmCompletionLog(LlmCompletionLog log)
{
- if (log == null) return;
+ if (log == null)
+ {
+ return;
+ }
log.ConversationId = log.ConversationId.IfNullOrEmptyAs(Guid.NewGuid().ToString());
log.MessageId = log.MessageId.IfNullOrEmptyAs(Guid.NewGuid().ToString());
@@ -36,13 +38,19 @@ public void SaveLlmCompletionLog(LlmCompletionLog log)
#region Conversation Content Log
public void SaveConversationContentLog(ContentLogOutputModel log)
{
- if (log == null) return;
+ if (log == null)
+ {
+ return;
+ }
log.ConversationId = log.ConversationId.IfNullOrEmptyAs(Guid.NewGuid().ToString());
log.MessageId = log.MessageId.IfNullOrEmptyAs(Guid.NewGuid().ToString());
var convDir = FindConversationDirectory(log.ConversationId);
- if (string.IsNullOrEmpty(convDir)) return;
+ if (string.IsNullOrEmpty(convDir))
+ {
+ return;
+ }
var logDir = Path.Combine(convDir, "content_log");
if (!Directory.Exists(logDir))
@@ -57,20 +65,32 @@ public void SaveConversationContentLog(ContentLogOutputModel log)
public DateTimePagination GetConversationContentLogs(string conversationId, ConversationLogFilter filter)
{
- if (string.IsNullOrEmpty(conversationId)) return new();
+ if (string.IsNullOrEmpty(conversationId))
+ {
+ return new();
+ }
var convDir = FindConversationDirectory(conversationId);
- if (string.IsNullOrEmpty(convDir)) return new();
+ if (string.IsNullOrEmpty(convDir))
+ {
+ return new();
+ }
var logDir = Path.Combine(convDir, "content_log");
- if (!Directory.Exists(logDir)) return new();
+ if (!Directory.Exists(logDir))
+ {
+ return new();
+ }
var logs = new List();
- foreach (var file in Directory.GetFiles(logDir))
+ foreach (var file in Directory.EnumerateFiles(logDir))
{
var text = File.ReadAllText(file);
var log = JsonSerializer.Deserialize(text);
- if (log == null || log.CreatedTime >= filter.StartTime) continue;
+ if (log == null || log.CreatedTime >= filter.StartTime)
+ {
+ continue;
+ }
logs.Add(log);
}
@@ -89,13 +109,19 @@ public DateTimePagination GetConversationContentLogs(stri
#region Conversation State Log
public void SaveConversationStateLog(ConversationStateLogModel log)
{
- if (log == null) return;
+ if (log == null)
+ {
+ return;
+ }
log.ConversationId = log.ConversationId.IfNullOrEmptyAs(Guid.NewGuid().ToString());
log.MessageId = log.MessageId.IfNullOrEmptyAs(Guid.NewGuid().ToString());
var convDir = FindConversationDirectory(log.ConversationId);
- if (string.IsNullOrEmpty(convDir)) return;
+ if (string.IsNullOrEmpty(convDir))
+ {
+ return;
+ }
var logDir = Path.Combine(convDir, "state_log");
if (!Directory.Exists(logDir))
@@ -110,20 +136,32 @@ public void SaveConversationStateLog(ConversationStateLogModel log)
public DateTimePagination GetConversationStateLogs(string conversationId, ConversationLogFilter filter)
{
- if (string.IsNullOrEmpty(conversationId)) return new();
+ if (string.IsNullOrEmpty(conversationId))
+ {
+ return new();
+ }
var convDir = FindConversationDirectory(conversationId);
- if (string.IsNullOrEmpty(convDir)) return new();
+ if (string.IsNullOrEmpty(convDir))
+ {
+ return new();
+ }
var logDir = Path.Combine(convDir, "state_log");
- if (!Directory.Exists(logDir)) return new();
+ if (!Directory.Exists(logDir))
+ {
+ return new();
+ }
var logs = new List();
- foreach (var file in Directory.GetFiles(logDir))
+ foreach (var file in Directory.EnumerateFiles(logDir))
{
var text = File.ReadAllText(file);
var log = JsonSerializer.Deserialize(text);
- if (log == null || log.CreatedTime >= filter.StartTime) continue;
+ if (log == null || log.CreatedTime >= filter.StartTime)
+ {
+ continue;
+ }
logs.Add(log);
}
@@ -142,7 +180,10 @@ public DateTimePagination GetConversationStateLogs(st
#region Instruction Log
public bool SaveInstructionLogs(IEnumerable logs)
{
- if (logs.IsNullOrEmpty()) return false;
+ if (logs.IsNullOrEmpty())
+ {
+ return false;
+ }
var baseDir = Path.Combine(_dbSettings.FileRepository, INSTRUCTION_LOG_FOLDER);
if (!Directory.Exists(baseDir))
@@ -174,12 +215,14 @@ public async ValueTask> GetInstructionLogs(Instr
}
var logs = new List();
- var files = Directory.GetFiles(baseDir);
- foreach (var file in files)
+ foreach (var file in Directory.EnumerateFiles(baseDir))
{
var json = File.ReadAllText(file);
var log = JsonSerializer.Deserialize(json, _options);
- if (log == null) continue;
+ if (log == null)
+ {
+ continue;
+ }
var matched = true;
if (!filter.AgentIds.IsNullOrEmpty())
@@ -223,7 +266,10 @@ public async ValueTask> GetInstructionLogs(Instr
{
foreach (var pair in filter.States)
{
- if (pair == null || string.IsNullOrWhiteSpace(pair.Key)) continue;
+ if (pair == null || string.IsNullOrWhiteSpace(pair.Key))
+ {
+ continue;
+ }
var components = pair.Key.Split(".").ToList();
var primaryKey = components[0];
@@ -266,12 +312,18 @@ public async ValueTask> GetInstructionLogs(Instr
matched = false;
}
- if (!matched) break;
+ if (!matched)
+ {
+ break;
+ }
}
}
}
- if (!matched) continue;
+ if (!matched)
+ {
+ continue;
+ }
log.Id = Path.GetFileNameWithoutExtension(file);
logs.Add(log);
@@ -306,12 +358,14 @@ public List GetInstructionLogSearchKeys(InstructLogKeysFilter filter)
}
var count = 0;
- var files = Directory.GetFiles(baseDir);
- foreach (var file in files)
+ foreach (var file in Directory.EnumerateFiles(baseDir))
{
var json = File.ReadAllText(file);
var log = JsonSerializer.Deserialize(json, _options);
- if (log == null) continue;
+ if (log == null)
+ {
+ continue;
+ }
if (log == null
|| log.InnerStates.IsNullOrEmpty()
@@ -340,11 +394,7 @@ public List GetInstructionLogSearchKeys(InstructLogKeysFilter filter)
#region Private methods
private int GetNextLogIndex(string logDir, string id)
{
- var files = Directory.GetFiles(logDir);
- if (files.IsNullOrEmpty())
- return 0;
-
- var logIndexes = files.Where(file =>
+ var logIndexes = Directory.EnumerateFiles(logDir).Where(file =>
{
var fileName = ParseFileNameByPath(file);
return fileName[0].IsEqualTo(id);
diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Role.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Role.cs
index c797ce5aa..825df02f0 100644
--- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Role.cs
+++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Role.cs
@@ -6,11 +6,17 @@ public partial class FileRepository
{
public bool RefreshRoles(IEnumerable roles)
{
- if (roles.IsNullOrEmpty()) return false;
+ if (roles.IsNullOrEmpty())
+ {
+ return false;
+ }
var validRoles = roles.Where(x => !string.IsNullOrWhiteSpace(x.Id)
&& !string.IsNullOrWhiteSpace(x.Name)).ToList();
- if (validRoles.IsNullOrEmpty()) return false;
+ if (validRoles.IsNullOrEmpty())
+ {
+ return false;
+ }
var baseDir = Path.Combine(_dbSettings.FileRepository, ROLES_FOLDER);
if (Directory.Exists(baseDir))
@@ -58,10 +64,16 @@ public IEnumerable GetRoles(RoleFilter filter)
public Role? GetRoleDetails(string roleId, bool includeAgent = false)
{
- if (string.IsNullOrWhiteSpace(roleId)) return null;
+ if (string.IsNullOrWhiteSpace(roleId))
+ {
+ return null;
+ }
var role = Roles.FirstOrDefault(x => x.Id == roleId);
- if (role == null) return null;
+ if (role == null)
+ {
+ return null;
+ }
var agentActions = new List();
var roleAgents = RoleAgents?.Where(x => x.RoleId == roleId)?.ToList() ?? [];
diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Translation.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Translation.cs
index e52e09c24..e4f016a02 100644
--- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Translation.cs
+++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Translation.cs
@@ -112,7 +112,10 @@ public bool SaveTranslationMemories(IEnumerable inputs)
else
{
var foundItem = foundMemory.Translations?.FirstOrDefault(x => x.Language.Equals(input.Language));
- if (foundItem != null) continue;
+ if (foundItem != null)
+ {
+ continue;
+ }
if (foundMemory.Translations == null)
{
diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.User.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.User.cs
index 09212e202..16520b232 100644
--- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.User.cs
+++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.User.cs
@@ -254,7 +254,10 @@ public List SearchLoginUsers(User filter, string source = UserSource.Inter
public bool UpdateUser(User user, bool updateUserAgents = false)
{
- if (string.IsNullOrEmpty(user?.Id)) return false;
+ if (string.IsNullOrEmpty(user?.Id))
+ {
+ return false;
+ }
var dir = Path.Combine(_dbSettings.FileRepository, USERS_FOLDER, user.Id);
if (!Directory.Exists(dir))
@@ -265,7 +268,10 @@ public bool UpdateUser(User user, bool updateUserAgents = false)
var userFile = Path.Combine(dir, USER_FILE);
var userJson = File.ReadAllText(userFile);
var curUser = JsonSerializer.Deserialize(userJson, _options);
- if (curUser == null) return false;
+ if (curUser == null)
+ {
+ return false;
+ }
curUser.Type = user.Type;
curUser.Role = user.Role;
@@ -297,13 +303,19 @@ public bool UpdateUser(User user, bool updateUserAgents = false)
public void AddDashboardConversation(string userId, string conversationId)
{
var user = GetUserById(userId);
- if (user == null) return;
+ if (user == null)
+ {
+ return;
+ }
// one user only has one dashboard currently
var dash = Dashboards.FirstOrDefault();
dash ??= new();
var existingConv = dash.ConversationList.FirstOrDefault(x => string.Equals(x.ConversationId, conversationId, StringComparison.OrdinalIgnoreCase));
- if (existingConv != null) return;
+ if (existingConv != null)
+ {
+ return;
+ }
var dashconv = new DashboardConversation
{
@@ -321,15 +333,24 @@ public void AddDashboardConversation(string userId, string conversationId)
public void RemoveDashboardConversation(string userId, string conversationId)
{
var user = GetUserById(userId);
- if (user == null) return;
+ if (user == null)
+ {
+ return;
+ }
// one user only has one dashboard currently
var dash = Dashboards.FirstOrDefault();
- if (dash == null) return;
+ if (dash == null)
+ {
+ return;
+ }
var dashconv = dash.ConversationList.FirstOrDefault(
c => string.Equals(c.ConversationId, conversationId, StringComparison.OrdinalIgnoreCase));
- if (dashconv == null) return;
+ if (dashconv == null)
+ {
+ return;
+ }
dash.ConversationList.Remove(dashconv);
@@ -341,15 +362,24 @@ public void RemoveDashboardConversation(string userId, string conversationId)
public void UpdateDashboardConversation(string userId, DashboardConversation dashConv)
{
var user = GetUserById(userId);
- if (user == null) return;
+ if (user == null)
+ {
+ return;
+ }
// one user only has one dashboard currently
var dash = Dashboards.FirstOrDefault();
- if (dash == null) return;
+ if (dash == null)
+ {
+ return;
+ }
var curIdx = dash.ConversationList.ToList().FindIndex(
x => string.Equals(x.ConversationId, dashConv.ConversationId, StringComparison.OrdinalIgnoreCase));
- if (curIdx < 0) return;
+ if (curIdx < 0)
+ {
+ return;
+ }
dash.ConversationList[curIdx] = dashConv;
diff --git a/src/Infrastructure/BotSharp.Core/Using.cs b/src/Infrastructure/BotSharp.Core/Using.cs
index 07b0f1642..de3fa1e78 100644
--- a/src/Infrastructure/BotSharp.Core/Using.cs
+++ b/src/Infrastructure/BotSharp.Core/Using.cs
@@ -5,6 +5,7 @@
global using BotSharp.Abstraction.Conversations;
global using BotSharp.Abstraction.Conversations.Models;
global using BotSharp.Abstraction.Conversations.Settings;
+global using BotSharp.Abstraction.Coding.Models;
global using BotSharp.Abstraction.Crontab.Models;
global using BotSharp.Abstraction.Files;
global using BotSharp.Abstraction.Files.Enums;
diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/Agent/AgentController.Coding.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/Agent/AgentController.Coding.cs
new file mode 100644
index 000000000..10a53f2e3
--- /dev/null
+++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/Agent/AgentController.Coding.cs
@@ -0,0 +1,63 @@
+using BotSharp.Abstraction.Coding.Models;
+using BotSharp.Abstraction.Infrastructures.Attributes;
+
+namespace BotSharp.OpenAPI.Controllers;
+
+public partial class AgentController
+{
+ ///
+ /// Get agent code scripts
+ ///
+ ///
+ ///
+ ///
+ [HttpGet("/agent/{agentId}/code-scripts")]
+ public async Task> GetAgentCodeScripts([FromRoute] string agentId, [FromQuery] AgentCodeScriptFilter request)
+ {
+ var scripts = await _agentService.GetAgentCodeScripts(agentId, request);
+ return scripts.Select(x => AgentCodeScriptViewModel.From(x)).ToList();
+ }
+
+ ///
+ /// Update agent code scripts
+ ///
+ ///
+ ///
+ ///
+ [BotSharpAuth]
+ [HttpPost("/agent/{agentId}/code-scripts")]
+ public async Task UpdateAgentCodeScripts([FromRoute] string agentId, [FromBody] AgentCodeScriptUpdateModel request)
+ {
+ var scripts = request?.CodeScripts?.Select(x => AgentCodeScriptViewModel.To(x))?.ToList() ?? [];
+ var updated = await _agentService.UpdateAgentCodeScripts(agentId, scripts, request?.Options);
+ return updated;
+ }
+
+ ///
+ /// Delete agent code scripts
+ ///
+ ///
+ ///
+ ///
+ [BotSharpAuth]
+ [HttpDelete("/agent/{agentId}/code-scripts")]
+ public async Task DeleteAgentCodeScripts([FromRoute] string agentId, [FromBody] AgentCodeScriptDeleteModel request)
+ {
+ var scripts = request?.CodeScripts?.Select(x => AgentCodeScriptViewModel.To(x))?.ToList();
+ var updated = await _agentService.DeleteAgentCodeScripts(agentId, scripts);
+ return updated;
+ }
+
+ [HttpPost("/agent/{agentId}/code-script/generate")]
+ public async Task GenerateAgentCodeScript([FromRoute] string agentId, [FromBody] AgentCodeScriptGenerationRequest request)
+ {
+ request ??= new();
+ var states = request.Options?.Data?.ToList();
+ var state = _services.GetRequiredService();
+ states?.ForEach(x => state.SetState(x.Key, x.Value, source: StateSource.External));
+ state.SetState("programming_language", request.Options?.Language, source: StateSource.External);
+
+ var result = await _agentService.GenerateCodeScript(agentId, request.Text, request?.Options);
+ return result;
+ }
+}
diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/RulesController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/Agent/AgentController.Rule.cs
similarity index 73%
rename from src/Infrastructure/BotSharp.OpenAPI/Controllers/RulesController.cs
rename to src/Infrastructure/BotSharp.OpenAPI/Controllers/Agent/AgentController.Rule.cs
index 0f58d9e56..4daefc717 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/RulesController.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/Agent/AgentController.Rule.cs
@@ -3,18 +3,8 @@
namespace BotSharp.OpenAPI.Controllers;
-[Authorize]
-[ApiController]
-public class RulesController
+public partial class AgentController
{
- private readonly IServiceProvider _services;
-
- public RulesController(
- IServiceProvider services)
- {
- _services = services;
- }
-
[HttpGet("/rule/triggers")]
public IEnumerable GetRuleTriggers()
{
diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentTaskController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/Agent/AgentController.Task.cs
similarity index 87%
rename from src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentTaskController.cs
rename to src/Infrastructure/BotSharp.OpenAPI/Controllers/Agent/AgentController.Task.cs
index 2322dae3c..6e6ecc3c0 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentTaskController.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/Agent/AgentController.Task.cs
@@ -1,20 +1,7 @@
-using BotSharp.Abstraction.Tasks;
-
namespace BotSharp.OpenAPI.Controllers;
-[Authorize]
-[ApiController]
-public class AgentTaskController : ControllerBase
+public partial class AgentController
{
- private readonly IAgentTaskService _agentTaskService;
- private readonly IServiceProvider _services;
-
- public AgentTaskController(IAgentTaskService agentTaskService, IServiceProvider services)
- {
- _agentTaskService = agentTaskService;
- _services = services;
- }
-
///
/// Get an agent task
///
@@ -25,7 +12,10 @@ public AgentTaskController(IAgentTaskService agentTaskService, IServiceProvider
public async Task GetAgentTask([FromRoute] string agentId, [FromRoute] string taskId)
{
var task = await _agentTaskService.GetTask(agentId, taskId);
- if (task == null) return null;
+ if (task == null)
+ {
+ return null;
+ }
return AgentTaskViewModel.From(task);
}
diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/Agent/AgentController.cs
similarity index 92%
rename from src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs
rename to src/Infrastructure/BotSharp.OpenAPI/Controllers/Agent/AgentController.cs
index 6aff56aee..1fcdb1285 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/Agent/AgentController.cs
@@ -1,22 +1,26 @@
using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Infrastructures.Attributes;
+using BotSharp.Abstraction.Tasks;
namespace BotSharp.OpenAPI.Controllers;
[Authorize]
[ApiController]
-public class AgentController : ControllerBase
+public partial class AgentController : ControllerBase
{
private readonly IAgentService _agentService;
+ private readonly IAgentTaskService _agentTaskService;
private readonly IUserIdentity _user;
private readonly IServiceProvider _services;
public AgentController(
IAgentService agentService,
+ IAgentTaskService agentTaskService,
IUserIdentity user,
IServiceProvider services)
{
_agentService = agentService;
+ _agentTaskService = agentTaskService;
_user = user;
_services = services;
}
@@ -140,9 +144,9 @@ public async Task