diff --git a/BotSharp.sln b/BotSharp.sln
index b7545cdc..8c1030f9 100644
--- a/BotSharp.sln
+++ b/BotSharp.sln
@@ -105,6 +105,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "FileStorages", "FileStorage
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotSharp.Plugin.TencentCos", "src\Plugins\BotSharp.Plugin.TencentCos\BotSharp.Plugin.TencentCos.csproj", "{BF029B0A-768B-43A1-8D91-E70B95505716}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Interpreters", "Interpreters", "{C4C59872-3C8A-450D-83D5-2BE402D610D5}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.Plugin.PythonInterpreter", "src\Plugins\BotSharp.Plugin.PythonInterpreter\BotSharp.Plugin.PythonInterpreter.csproj", "{05E6E405-5021-406E-8A5E-0A7CEC881F6D}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -425,6 +429,14 @@ Global
{BF029B0A-768B-43A1-8D91-E70B95505716}.Release|Any CPU.Build.0 = Release|Any CPU
{BF029B0A-768B-43A1-8D91-E70B95505716}.Release|x64.ActiveCfg = Release|Any CPU
{BF029B0A-768B-43A1-8D91-E70B95505716}.Release|x64.Build.0 = Release|Any CPU
+ {05E6E405-5021-406E-8A5E-0A7CEC881F6D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {05E6E405-5021-406E-8A5E-0A7CEC881F6D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {05E6E405-5021-406E-8A5E-0A7CEC881F6D}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {05E6E405-5021-406E-8A5E-0A7CEC881F6D}.Debug|x64.Build.0 = Debug|Any CPU
+ {05E6E405-5021-406E-8A5E-0A7CEC881F6D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {05E6E405-5021-406E-8A5E-0A7CEC881F6D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {05E6E405-5021-406E-8A5E-0A7CEC881F6D}.Release|x64.ActiveCfg = Release|Any CPU
+ {05E6E405-5021-406E-8A5E-0A7CEC881F6D}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -475,6 +487,8 @@ Global
{54E83C6F-54EE-4ADC-8D72-93C009CC4FB4} = {51AFE054-AE99-497D-A593-69BAEFB5106F}
{38B37C0D-1930-4D47-BCBF-E358EC1096B1} = {2635EC9B-2E5F-4313-AC21-0B847F31F36C}
{BF029B0A-768B-43A1-8D91-E70B95505716} = {38B37C0D-1930-4D47-BCBF-E358EC1096B1}
+ {C4C59872-3C8A-450D-83D5-2BE402D610D5} = {2635EC9B-2E5F-4313-AC21-0B847F31F36C}
+ {05E6E405-5021-406E-8A5E-0A7CEC881F6D} = {C4C59872-3C8A-450D-83D5-2BE402D610D5}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A9969D89-C98B-40A5-A12B-FC87E55B3A19}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs
index 8405d9b5..1fd7a38c 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs
@@ -20,6 +20,13 @@ public interface IAgentService
///
Task LoadAgent(string id);
+ ///
+ /// Inherit from an agent
+ ///
+ ///
+ ///
+ Task InheritAgent(Agent agent);
+
string RenderedInstruction(Agent agent);
string RenderedTemplate(Agent agent, string templateName);
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs
index 01ec2acb..43f0f5ba 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs
@@ -1,6 +1,5 @@
using BotSharp.Abstraction.Functions.Models;
using BotSharp.Abstraction.Plugins.Models;
-using BotSharp.Abstraction.Routing.Models;
using BotSharp.Abstraction.Tasks.Models;
namespace BotSharp.Abstraction.Agents.Models;
@@ -21,8 +20,7 @@ public class Agent
/// Default LLM settings
///
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- public AgentLlmConfig LlmConfig { get; set; }
- = new AgentLlmConfig();
+ public AgentLlmConfig LlmConfig { get; set; } = new();
///
/// Instruction
@@ -30,33 +28,35 @@ public class Agent
[JsonIgnore]
public string? Instruction { get; set; }
+ ///
+ /// Channel instructions
+ ///
+ [JsonIgnore]
+ public List ChannelInstructions { get; set; } = new();
+
///
/// Templates
///
[JsonIgnore]
- public List Templates { get; set; }
- = new List();
+ public List Templates { get; set; } = new();
///
/// Agent tasks
///
[JsonIgnore]
- public List Tasks { get; set; }
- = new List();
+ public List Tasks { get; set; } = new();
///
/// Samples
///
[JsonIgnore]
- public List Samples { get; set; }
- = new List();
+ public List Samples { get; set; } = new();
///
/// Functions
///
[JsonIgnore]
- public List Functions { get; set; }
- = new List();
+ public List Functions { get; set; } = new();
///
/// Responses
@@ -93,23 +93,20 @@ public class Agent
///
/// Agent utilities
///
- public List Utilities { get; set; }
- = new List();
+ public List Utilities { get; set; } = new();
///
/// Inherit from agent
///
public string? InheritAgentId { get; set; }
- public List RoutingRules { get; set; }
- = new List();
+ public List RoutingRules { get; set; } = new();
///
/// For rendering deferral
///
[JsonIgnore]
- public Dictionary TemplateDict { get; set; }
- = new Dictionary();
+ public Dictionary TemplateDict { get; set; } = new();
public override string ToString()
=> $"{Name} {Id}";
@@ -124,6 +121,7 @@ public class Agent
Description = agent.Description,
Type = agent.Type,
Instruction = agent.Instruction,
+ ChannelInstructions = agent.ChannelInstructions,
Functions = agent.Functions,
Responses = agent.Responses,
Samples = agent.Samples,
@@ -145,6 +143,12 @@ public class Agent
return this;
}
+ public Agent SetChannelInstructions(List instructions)
+ {
+ ChannelInstructions = instructions ?? new List();
+ return this;
+ }
+
public Agent SetTemplates(List templates)
{
Templates = templates ?? new List();
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/ChannelInstruction.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/ChannelInstruction.cs
new file mode 100644
index 00000000..d4ff6c1f
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/ChannelInstruction.cs
@@ -0,0 +1,7 @@
+namespace BotSharp.Abstraction.Agents.Models;
+
+public class ChannelInstruction
+{
+ public string Channel { get; set; }
+ public string Instruction { get; set; }
+}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionDef.cs b/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionDef.cs
index 4366d323..d5dabb3c 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionDef.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionDef.cs
@@ -8,7 +8,12 @@ public class FunctionDef
[JsonPropertyName("description")]
public string Description { get; set; } = null!;
+ [JsonPropertyName("channels")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public List? Channels { get; set; }
+
[JsonPropertyName("visibility_expression")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? VisibilityExpression { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
diff --git a/src/Infrastructure/BotSharp.Abstraction/Interpreters/Models/InterpretationRequest.cs b/src/Infrastructure/BotSharp.Abstraction/Interpreters/Models/InterpretationRequest.cs
new file mode 100644
index 00000000..5a8f7552
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/Interpreters/Models/InterpretationRequest.cs
@@ -0,0 +1,10 @@
+namespace BotSharp.Abstraction.Interpreters.Models;
+
+public class InterpretationRequest
+{
+ [JsonPropertyName("script")]
+ public string Script { get; set; } = null!;
+
+ [JsonPropertyName("language")]
+ public string Language { get; set; } = null!;
+}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Knowledges/IKnowledgeService.cs b/src/Infrastructure/BotSharp.Abstraction/Knowledges/IKnowledgeService.cs
index 657ac42a..02afb420 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Knowledges/IKnowledgeService.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Knowledges/IKnowledgeService.cs
@@ -2,8 +2,9 @@ namespace BotSharp.Abstraction.Knowledges;
public interface IKnowledgeService
{
- Task> SearchKnowledge(string collectionName, KnowledgeRetrievalOptions options);
+ Task> GetKnowledgeCollections();
+ Task> SearchKnowledge(string collectionName, KnowledgeSearchOptions options);
Task FeedKnowledge(string collectionName, KnowledgeCreationModel model);
- Task> GetKnowledgeCollectionData(string collectionName, KnowledgeFilter filter);
+ Task> GetKnowledgeCollectionData(string collectionName, KnowledgeFilter filter);
Task DeleteKnowledgeCollectionData(string collectionName, string id);
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Knowledges/Models/KnowledgeCollectionData.cs b/src/Infrastructure/BotSharp.Abstraction/Knowledges/Models/KnowledgeCollectionData.cs
index d013529f..6a8faff4 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Knowledges/Models/KnowledgeCollectionData.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Knowledges/Models/KnowledgeCollectionData.cs
@@ -3,7 +3,7 @@ namespace BotSharp.Abstraction.Knowledges.Models;
public class KnowledgeCollectionData
{
public string Id { get; set; }
- public string Question { get; set; }
- public string Answer { get; set; }
+ public Dictionary Data { get; set; } = new();
+ public double? Score { get; set; }
public float[]? Vector { get; set; }
-}
+}
\ No newline at end of file
diff --git a/src/Infrastructure/BotSharp.Abstraction/Knowledges/Models/KnowledgeRetrievalOptions.cs b/src/Infrastructure/BotSharp.Abstraction/Knowledges/Models/KnowledgeSearchOptions.cs
similarity index 91%
rename from src/Infrastructure/BotSharp.Abstraction/Knowledges/Models/KnowledgeRetrievalOptions.cs
rename to src/Infrastructure/BotSharp.Abstraction/Knowledges/Models/KnowledgeSearchOptions.cs
index 8a608ddc..4ac1b77b 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Knowledges/Models/KnowledgeRetrievalOptions.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Knowledges/Models/KnowledgeSearchOptions.cs
@@ -2,7 +2,7 @@ using BotSharp.Abstraction.Knowledges.Enums;
namespace BotSharp.Abstraction.Knowledges.Models;
-public class KnowledgeRetrievalOptions
+public class KnowledgeSearchOptions
{
public string Text { get; set; } = string.Empty;
public IEnumerable? Fields { get; set; } = new List { KnowledgePayloadName.Text, KnowledgePayloadName.Answer };
diff --git a/src/Infrastructure/BotSharp.Abstraction/Knowledges/Models/KnowledgeSearchResult.cs b/src/Infrastructure/BotSharp.Abstraction/Knowledges/Models/KnowledgeSearchResult.cs
index b0deaa0f..661578c2 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Knowledges/Models/KnowledgeSearchResult.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Knowledges/Models/KnowledgeSearchResult.cs
@@ -1,12 +1,20 @@
namespace BotSharp.Abstraction.Knowledges.Models;
-public class KnowledgeSearchResult
+public class KnowledgeSearchResult : KnowledgeCollectionData
{
- public IDictionary Data { get; set; } = new Dictionary();
- public double Score { get; set; }
- public float[]? Vector { get; set; }
-}
+ public KnowledgeSearchResult()
+ {
+
+ }
-public class KnowledgeRetrievalResult : KnowledgeSearchResult
-{
+ public static KnowledgeSearchResult CopyFrom(KnowledgeCollectionData data)
+ {
+ return new KnowledgeSearchResult
+ {
+ Id = data.Id,
+ Data = data.Data,
+ Score = data.Score,
+ Vector = data.Vector
+ };
+ }
}
\ No newline at end of file
diff --git a/src/Infrastructure/BotSharp.Abstraction/Knowledges/Settings/KnowledgeBaseSettings.cs b/src/Infrastructure/BotSharp.Abstraction/Knowledges/Settings/KnowledgeBaseSettings.cs
index ac3f0500..f2c62fd0 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Knowledges/Settings/KnowledgeBaseSettings.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Knowledges/Settings/KnowledgeBaseSettings.cs
@@ -1,8 +1,11 @@
+using BotSharp.Abstraction.Knowledges.Enums;
+
namespace BotSharp.Abstraction.Knowledges.Settings;
public class KnowledgeBaseSettings
{
public string VectorDb { get; set; }
+ public string DefaultCollection { get; set; } = KnowledgeCollectionName.BotSharp;
public KnowledgeModelSetting TextEmbedding { get; set; }
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/VectorStorage/IVectorDb.cs b/src/Infrastructure/BotSharp.Abstraction/VectorStorage/IVectorDb.cs
index a079aaef..ff4ec26a 100644
--- a/src/Infrastructure/BotSharp.Abstraction/VectorStorage/IVectorDb.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/VectorStorage/IVectorDb.cs
@@ -3,11 +3,11 @@ namespace BotSharp.Abstraction.VectorStorage;
public interface IVectorDb
{
string Name { get; }
-
+
Task> GetCollections();
Task> GetCollectionData(string collectionName, KnowledgeFilter filter);
Task CreateCollection(string collectionName, int dim);
Task Upsert(string collectionName, string id, float[] vector, string text, Dictionary? payload = null);
- Task> Search(string collectionName, float[] vector, IEnumerable fields, int limit = 5, float confidence = 0.5f, bool withVector = false);
+ Task> Search(string collectionName, float[] vector, IEnumerable? fields, int limit = 5, float confidence = 0.5f, bool withVector = false);
Task DeleteCollectionData(string collectionName, string id);
}
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs
index 59de3096..9e2e1d5f 100644
--- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs
+++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs
@@ -41,44 +41,52 @@ public partial class AgentService
});
Utilities.ClearCache();
-
return await Task.FromResult(agentRecord);
}
- private Agent FetchAgentFileByName(string agentName, string filePath)
+ private (string, List) GetInstructionsFromFile(string fileDir)
{
- foreach (var dir in Directory.GetDirectories(filePath))
+ var defaultInstruction = string.Empty;
+ var channelInstructions = new List();
+
+ var instructionDir = Path.Combine(fileDir, "instructions");
+ if (!Directory.Exists(instructionDir))
{
- var agentJson = File.ReadAllText(Path.Combine(dir, "agent.json"));
- var agent = JsonSerializer.Deserialize(agentJson, _options);
- if (agent != null && agent.Name.IsEqualTo(agentName))
- {
- var functions = FetchFunctionsFromFile(dir);
- var instruction = FetchInstructionFromFile(dir);
- var responses = FetchResponsesFromFile(dir);
- var templates = FetchTemplatesFromFile(dir);
- var samples = FetchSamplesFromFile(dir);
- return agent.SetInstruction(instruction)
- .SetTemplates(templates)
- .SetFunctions(functions)
- .SetResponses(responses)
- .SetSamples(samples);
- }
+ return (defaultInstruction, channelInstructions);
}
- return null;
+ foreach (var file in Directory.GetFiles(instructionDir))
+ {
+ var extension = Path.GetExtension(file).Substring(1);
+ if (!extension.IsEqualTo(_agentSettings.TemplateFormat))
+ {
+ continue;
+ }
+
+ var segments = Path.GetFileName(file).Split(".", StringSplitOptions.RemoveEmptyEntries);
+ if (segments.IsNullOrEmpty() || !segments[0].IsEqualTo("instruction"))
+ {
+ continue;
+ }
+
+ if (segments.Length == 2)
+ {
+ defaultInstruction = File.ReadAllText(file);
+ }
+ else if (segments.Length == 3)
+ {
+ var item = new ChannelInstruction
+ {
+ Channel = segments[1],
+ Instruction = File.ReadAllText(file)
+ };
+ channelInstructions.Add(item);
+ }
+ }
+ return (defaultInstruction, channelInstructions);
}
- private string FetchInstructionFromFile(string fileDir)
- {
- var file = Path.Combine(fileDir, $"instruction.{_agentSettings.TemplateFormat}");
- if (!File.Exists(file)) return null;
-
- var instruction = File.ReadAllText(file);
- return instruction;
- }
-
- private List FetchTemplatesFromFile(string fileDir)
+ private List GetTemplatesFromFile(string fileDir)
{
var templates = new List();
var templateDir = Path.Combine(fileDir, "templates");
@@ -86,10 +94,10 @@ public partial class AgentService
foreach (var file in Directory.GetFiles(templateDir))
{
- var name = Path.GetFileNameWithoutExtension(file);
var extension = Path.GetExtension(file).Substring(1);
if (extension.IsEqualTo(_agentSettings.TemplateFormat))
{
+ var name = Path.GetFileNameWithoutExtension(file);
var content = File.ReadAllText(file);
templates.Add(new AgentTemplate(name, content));
}
@@ -98,7 +106,7 @@ public partial class AgentService
return templates;
}
- private List FetchFunctionsFromFile(string fileDir)
+ private List GetFunctionsFromFile(string fileDir)
{
var functions = new List();
var functionDir = Path.Combine(fileDir, "functions");
@@ -125,7 +133,7 @@ public partial class AgentService
return functions;
}
- private List FetchResponsesFromFile(string fileDir)
+ private List GetResponsesFromFile(string fileDir)
{
var responses = new List();
var responseDir = Path.Combine(fileDir, "responses");
@@ -143,7 +151,7 @@ public partial class AgentService
return responses;
}
- private List FetchSamplesFromFile(string fileDir)
+ private List GetSamplesFromFile(string fileDir)
{
var file = Path.Combine(fileDir, "samples.txt");
if (!File.Exists(file)) return new List();
@@ -152,7 +160,7 @@ public partial class AgentService
return samples?.ToList() ?? new List();
}
- private List FetchTasksFromFile(string fileDir)
+ private List GetTasksFromFile(string fileDir)
{
var tasks = new List();
var taskDir = Path.Combine(fileDir, "tasks");
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs
index 15ce6eca..04b5c22d 100644
--- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs
+++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs
@@ -53,7 +53,29 @@ public partial class AgentService
}
profile.Plugin = GetPlugin(profile.Id);
-
return profile;
}
+
+ public async Task InheritAgent(Agent agent)
+ {
+ if (string.IsNullOrWhiteSpace(agent?.InheritAgentId)) return;
+
+ var inheritedAgent = await GetAgent(agent.InheritAgentId);
+ agent.Templates.AddRange(inheritedAgent.Templates
+ // exclude private template
+ .Where(x => !x.Name.StartsWith("."))
+ // exclude duplicate name
+ .Where(x => !agent.Templates.Exists(t => t.Name == x.Name)));
+
+ agent.Functions.AddRange(inheritedAgent.Functions
+ // exclude private template
+ .Where(x => !x.Name.StartsWith("."))
+ // exclude duplicate name
+ .Where(x => !agent.Functions.Exists(t => t.Name == x.Name)));
+
+ if (string.IsNullOrWhiteSpace(agent.Instruction))
+ {
+ agent.Instruction = inheritedAgent.Instruction;
+ }
+ }
}
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs
index 757d9937..f0a864a2 100644
--- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs
+++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs
@@ -34,31 +34,12 @@ public partial class AgentService
return null;
}
- if (agent.InheritAgentId != null)
- {
- var inheritedAgent = await GetAgent(agent.InheritAgentId);
- agent.Templates.AddRange(inheritedAgent.Templates
- // exclude private template
- .Where(x => !x.Name.StartsWith("."))
- // exclude duplicate name
- .Where(x => !agent.Templates.Exists(t => t.Name == x.Name)));
-
- agent.Functions.AddRange(inheritedAgent.Functions
- // exclude private template
- .Where(x => !x.Name.StartsWith("."))
- // exclude duplicate name
- .Where(x => !agent.Functions.Exists(t => t.Name == x.Name)));
-
- if (agent.Instruction == null)
- {
- agent.Instruction = inheritedAgent.Instruction;
- }
- }
+ await InheritAgent(agent);
+ OverrideInstructionByChannel(agent);
AddOrUpdateParameters(agent);
- agent.TemplateDict = new Dictionary();
-
// Populate state into dictionary
+ agent.TemplateDict = new Dictionary();
PopulateState(agent.TemplateDict);
// After agent is loaded
@@ -94,6 +75,23 @@ public partial class AgentService
return agent;
}
+ private void OverrideInstructionByChannel(Agent agent)
+ {
+ var instructions = agent.ChannelInstructions;
+ if (instructions.IsNullOrEmpty()) return;
+
+ var state = _services.GetRequiredService();
+ var channel = state.GetState("channel");
+
+ if (string.IsNullOrWhiteSpace(channel))
+ {
+ return;
+ }
+
+ var found = instructions.FirstOrDefault(x => x.Channel.IsEqualTo(channel));
+ agent.Instruction = !string.IsNullOrWhiteSpace(found?.Instruction) ? found.Instruction : agent.Instruction;
+ }
+
private void PopulateState(Dictionary dict)
{
var conv = _services.GetRequiredService();
@@ -114,18 +112,27 @@ public partial class AgentService
private void AddOrUpdateRoutesParameters(string agentId, List routingRules)
{
- if(!AgentParameterTypes.TryGetValue(agentId, out var parameterTypes)) parameterTypes = new();
+ if(!AgentParameterTypes.TryGetValue(agentId, out var parameterTypes))
+ {
+ parameterTypes = new();
+ }
+
foreach (var rule in routingRules.Where(x => x.Required))
{
if (string.IsNullOrEmpty(rule.FieldType)) continue;
parameterTypes.TryAdd(rule.Field, rule.FieldType);
}
+
AgentParameterTypes.TryAdd(agentId, parameterTypes);
}
private void AddOrUpdateFunctionsParameters(string agentId, List functions)
{
- if (!AgentParameterTypes.TryGetValue(agentId, out var parameterTypes)) parameterTypes = new();
+ if (!AgentParameterTypes.TryGetValue(agentId, out var parameterTypes))
+ {
+ parameterTypes = new();
+ }
+
var parameters = functions.Select(p => p.Parameters);
foreach (var param in parameters)
{
@@ -139,6 +146,7 @@ public partial class AgentService
}
}
}
+
AgentParameterTypes.TryAdd(agentId, parameterTypes);
}
}
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.RefreshAgents.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.RefreshAgents.cs
index 0b61977e..10598d4e 100644
--- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.RefreshAgents.cs
+++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.RefreshAgents.cs
@@ -42,19 +42,20 @@ public partial class AgentService
continue;
}
- var functions = FetchFunctionsFromFile(dir);
- var instruction = FetchInstructionFromFile(dir);
- var responses = FetchResponsesFromFile(dir);
- var templates = FetchTemplatesFromFile(dir);
- var samples = FetchSamplesFromFile(dir);
- agent.SetInstruction(instruction)
+ var (defaultInstruction, channelInstructions) = GetInstructionsFromFile(dir);
+ var functions = GetFunctionsFromFile(dir);
+ var responses = GetResponsesFromFile(dir);
+ var templates = GetTemplatesFromFile(dir);
+ var samples = GetSamplesFromFile(dir);
+ agent.SetInstruction(defaultInstruction)
+ .SetChannelInstructions(channelInstructions)
.SetTemplates(templates)
.SetFunctions(functions)
.SetResponses(responses)
.SetSamples(samples);
var userAgent = BuildUserAgent(agent.Id, user.Id);
- var tasks = FetchTasksFromFile(dir);
+ var tasks = GetTasksFromFile(dir);
var isAgentDeleted = _db.DeleteAgent(agent.Id);
if (isAgentDeleted)
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.Rendering.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.Rendering.cs
index a0b2f130..e9617d17 100644
--- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.Rendering.cs
+++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.Rendering.cs
@@ -20,17 +20,32 @@ public partial class AgentService
public bool RenderFunction(Agent agent, FunctionDef def)
{
- if (!string.IsNullOrEmpty(def.VisibilityExpression))
+ var isRender = true;
+
+ var channels = def.Channels;
+ if (channels != null)
+ {
+ var state = _services.GetRequiredService();
+ var channel = state.GetState("channel");
+ if (!string.IsNullOrWhiteSpace(channel))
+ {
+ isRender = isRender && channels.Contains(channel);
+ }
+ }
+
+ if (!isRender) return false;
+
+ if (!string.IsNullOrWhiteSpace(def.VisibilityExpression))
{
var render = _services.GetRequiredService();
var result = render.Render(def.VisibilityExpression, new Dictionary
{
{ "states", agent.TemplateDict }
});
- return result == "visible";
+ isRender = isRender && result == "visible";
}
- return true;
+ return isRender;
}
public FunctionParametersDef? RenderFunctionProperty(Agent agent, FunctionDef def)
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs
index 6fd0f85e..fe532e28 100644
--- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs
+++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs
@@ -28,6 +28,7 @@ public partial class AgentService
record.Profiles = agent.Profiles ?? new List();
record.RoutingRules = agent.RoutingRules ?? new List();
record.Instruction = agent.Instruction ?? string.Empty;
+ record.ChannelInstructions = agent.ChannelInstructions ?? new List();
record.Functions = agent.Functions ?? new List();
record.Templates = agent.Templates ?? new List();
record.Responses = agent.Responses ?? new List();
@@ -41,7 +42,6 @@ public partial class AgentService
_db.UpdateAgent(record, updateField);
Utilities.ClearCache();
-
await Task.CompletedTask;
}
@@ -71,7 +71,7 @@ public partial class AgentService
agentSettings.DataDir);
var clonedAgent = Agent.Clone(agent);
- var foundAgent = FetchAgentFileById(agent.Id, filePath);
+ var foundAgent = GetAgentFileById(agent.Id, filePath);
if (foundAgent == null)
{
updateResult = $"Cannot find agent {agent.Name} in file directory: {filePath}";
@@ -90,6 +90,7 @@ public partial class AgentService
.SetProfiles(foundAgent.Profiles)
.SetRoutingRules(foundAgent.RoutingRules)
.SetInstruction(foundAgent.Instruction)
+ .SetChannelInstructions(foundAgent.ChannelInstructions)
.SetTemplates(foundAgent.Templates)
.SetFunctions(foundAgent.Functions)
.SetResponses(foundAgent.Responses)
@@ -165,7 +166,7 @@ public partial class AgentService
return patchResult;
}
- private Agent? FetchAgentFileById(string agentId, string filePath)
+ private Agent? GetAgentFileById(string agentId, string filePath)
{
if (!Directory.Exists(filePath)) return null;
@@ -175,12 +176,13 @@ public partial class AgentService
var agent = JsonSerializer.Deserialize(agentJson, _options);
if (agent != null && agent.Id == agentId)
{
- var functions = FetchFunctionsFromFile(dir);
- var instruction = FetchInstructionFromFile(dir);
- var responses = FetchResponsesFromFile(dir);
- var templates = FetchTemplatesFromFile(dir);
- var samples = FetchSamplesFromFile(dir);
- return agent.SetInstruction(instruction)
+ var (defaultInstruction, channelInstructions) = GetInstructionsFromFile(dir);
+ var functions = GetFunctionsFromFile(dir);
+ var responses = GetResponsesFromFile(dir);
+ var templates = GetTemplatesFromFile(dir);
+ var samples = GetSamplesFromFile(dir);
+ return agent.SetInstruction(defaultInstruction)
+ .SetChannelInstructions(channelInstructions)
.SetTemplates(templates)
.SetFunctions(functions)
.SetResponses(responses)
diff --git a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj
index ad46fb56..73bf035c 100644
--- a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj
+++ b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj
@@ -1,4 +1,4 @@
-
+
$(TargetFramework)
@@ -56,17 +56,17 @@
-
+
-
+
-
+
-
+
-
+
@@ -80,7 +80,7 @@
-
+
@@ -90,7 +90,7 @@
PreserveNewest
-
+
PreserveNewest
@@ -99,19 +99,19 @@
PreserveNewest
-
+
PreserveNewest
PreserveNewest
-
+
PreserveNewest
PreserveNewest
-
+
PreserveNewest
@@ -147,7 +147,7 @@
PreserveNewest
-
+
PreserveNewest
@@ -162,7 +162,7 @@
PreserveNewest
-
+
PreserveNewest
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 9788631e..e90c7812 100644
--- a/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.Audio.cs
+++ b/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.Audio.cs
@@ -6,19 +6,21 @@ namespace BotSharp.Core.Files.Services
{
public async Task SaveSpeechFileAsync(string conversationId, string fileName, BinaryData data)
{
- var dir = Path.Combine(_baseDir, CONVERSATION_FOLDER, TEXT_TO_SPEECH_FOLDER, conversationId);
+ var dir = Path.Combine(_baseDir, CONVERSATION_FOLDER, conversationId, TEXT_TO_SPEECH_FOLDER);
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
- using var file = File.Create(Path.Combine(dir, fileName));
+ var filePath = Path.Combine(dir, fileName);
+ if (File.Exists(filePath)) return;
+ using var file = File.Create(filePath);
using var input = data.ToStream();
await input.CopyToAsync(file);
}
public async Task RetrieveSpeechFileAsync(string conversationId, string fileName)
{
- var path = Path.Combine(_baseDir, CONVERSATION_FOLDER, TEXT_TO_SPEECH_FOLDER, conversationId, fileName);
+ var path = Path.Combine(_baseDir, CONVERSATION_FOLDER, conversationId, TEXT_TO_SPEECH_FOLDER, fileName);
using var file = new FileStream(path, FileMode.Open, FileAccess.Read);
return await BinaryData.FromStreamAsync(file);
}
diff --git a/src/Infrastructure/BotSharp.Core/Infrastructures/SettingService.cs b/src/Infrastructure/BotSharp.Core/Infrastructures/SettingService.cs
index fe3d9007..cbde5f44 100644
--- a/src/Infrastructure/BotSharp.Core/Infrastructures/SettingService.cs
+++ b/src/Infrastructure/BotSharp.Core/Infrastructures/SettingService.cs
@@ -31,6 +31,7 @@ public class SettingService : ISettingService
var plugins = pluginService.GetPlugins(_services);
var plugin = plugins.First(x => x.Module.Settings.Name == settingName);
var instance = plugin.Module.GetNewSettingsInstance();
+
_config.Bind(settingName, instance);
if (mask)
{
diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs
index c0c59142..bb137279 100644
--- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs
+++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs
@@ -1,6 +1,6 @@
+using BotSharp.Abstraction.Functions.Models;
using BotSharp.Abstraction.Routing.Models;
using System.IO;
-using System.Threading;
namespace BotSharp.Core.Repository
{
@@ -37,7 +37,7 @@ namespace BotSharp.Core.Repository
UpdateAgentRoutingRules(agent.Id, agent.RoutingRules);
break;
case AgentField.Instruction:
- UpdateAgentInstruction(agent.Id, agent.Instruction);
+ UpdateAgentInstructions(agent.Id, agent.Instruction, agent.ChannelInstructions);
break;
case AgentField.Function:
UpdateAgentFunctions(agent.Id, agent.Functions);
@@ -175,17 +175,30 @@ namespace BotSharp.Core.Repository
File.WriteAllText(agentFile, json);
}
- private void UpdateAgentInstruction(string agentId, string instruction)
+ private void UpdateAgentInstructions(string agentId, string instruction, List channelInstructions)
{
if (string.IsNullOrWhiteSpace(instruction)) return;
var (agent, agentFile) = GetAgentFromFile(agentId);
if (agent == null) return;
- var instructionFile = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir,
- agentId, $"{AGENT_INSTRUCTION_FILE}.{_agentSettings.TemplateFormat}");
+ var instructionDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId, AGENT_INSTRUCTIONS_FOLDER);
+ DeleteBeforeCreateDirectory(instructionDir);
- File.WriteAllText(instructionFile, instruction);
+ // Save default instructions
+ var instructionFile = Path.Combine(instructionDir, $"{AGENT_INSTRUCTION_FILE}.{_agentSettings.TemplateFormat}");
+ File.WriteAllText(instructionFile, instruction ?? string.Empty);
+ Thread.Sleep(100);
+
+ // Save channel instructions
+ foreach (var ci in channelInstructions)
+ {
+ if (string.IsNullOrWhiteSpace(ci.Channel)) continue;
+
+ var file = Path.Combine(instructionDir, $"{AGENT_INSTRUCTION_FILE}.{ci.Channel}.{_agentSettings.TemplateFormat}");
+ File.WriteAllText(file, ci.Instruction ?? string.Empty);
+ Thread.Sleep(100);
+ }
}
private void UpdateAgentFunctions(string agentId, List inputFunctions)
@@ -195,14 +208,8 @@ namespace BotSharp.Core.Repository
var (agent, agentFile) = GetAgentFromFile(agentId);
if (agent == null) return;
- var functionDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir,
- agentId, AGENT_FUNCTIONS_FOLDER);
-
- if (Directory.Exists(functionDir))
- {
- Directory.Delete(functionDir, true);
- }
- Directory.CreateDirectory(functionDir);
+ var functionDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId, AGENT_FUNCTIONS_FOLDER);
+ DeleteBeforeCreateDirectory(functionDir);
foreach (var func in inputFunctions)
{
@@ -211,7 +218,7 @@ namespace BotSharp.Core.Repository
var text = JsonSerializer.Serialize(func, _options);
var file = Path.Combine(functionDir, $"{func.Name}.json");
File.WriteAllText(file, text);
- Thread.Sleep(200);
+ Thread.Sleep(100);
}
}
@@ -223,16 +230,7 @@ namespace BotSharp.Core.Repository
if (agent == null) return;
var templateDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId, AGENT_TEMPLATES_FOLDER);
-
- if (!Directory.Exists(templateDir))
- {
- Directory.CreateDirectory(templateDir);
- }
-
- foreach (var file in Directory.GetFiles(templateDir))
- {
- File.Delete(file);
- }
+ DeleteBeforeCreateDirectory(templateDir);
foreach (var template in templates)
{
@@ -249,15 +247,7 @@ namespace BotSharp.Core.Repository
if (agent == null) return;
var responseDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId, AGENT_RESPONSES_FOLDER);
- if (!Directory.Exists(responseDir))
- {
- Directory.CreateDirectory(responseDir);
- }
-
- foreach (var file in Directory.GetFiles(responseDir))
- {
- File.Delete(file);
- }
+ DeleteBeforeCreateDirectory(responseDir);
for (int i = 0; i < responses.Count; i++)
{
@@ -308,7 +298,7 @@ namespace BotSharp.Core.Repository
var json = JsonSerializer.Serialize(agent, _options);
File.WriteAllText(agentFile, json);
- UpdateAgentInstruction(inputAgent.Id, inputAgent.Instruction);
+ UpdateAgentInstructions(inputAgent.Id, inputAgent.Instruction, inputAgent.ChannelInstructions);
UpdateAgentResponses(inputAgent.Id, inputAgent.Responses);
UpdateAgentTemplates(inputAgent.Id, inputAgent.Templates);
UpdateAgentFunctions(inputAgent.Id, inputAgent.Functions);
@@ -348,12 +338,13 @@ namespace BotSharp.Core.Repository
var record = JsonSerializer.Deserialize(json, _options);
if (record == null) return null;
- var instruction = FetchInstruction(dir);
+ var (defaultInstruction, channelInstructions) = FetchInstructions(dir);
var functions = FetchFunctions(dir);
var samples = FetchSamples(dir);
var templates = FetchTemplates(dir);
var responses = FetchResponses(dir);
- return record.SetInstruction(instruction)
+ return record.SetInstruction(defaultInstruction)
+ .SetChannelInstructions(channelInstructions)
.SetFunctions(functions)
.SetTemplates(templates)
.SetSamples(samples)
@@ -451,13 +442,9 @@ namespace BotSharp.Core.Repository
return true;
}
- public void BulkInsertAgents(List agents)
- {
- }
+ public void BulkInsertAgents(List agents) { }
- public void BulkInsertUserAgents(List userAgents)
- {
- }
+ public void BulkInsertUserAgents(List userAgents) { }
public bool DeleteAgents()
{
diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.cs
index 78bd5cc0..7e5b4d9d 100644
--- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.cs
+++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.cs
@@ -34,6 +34,7 @@ public partial class FileRepository : IBotSharpRepository
private const string AGENT_TASK_PREFIX = "#metadata";
private const string AGENT_TASK_SUFFIX = "/metadata";
private const string TRANSLATION_MEMORY_FILE = "memory.json";
+ private const string AGENT_INSTRUCTIONS_FOLDER = "instructions";
private const string AGENT_FUNCTIONS_FOLDER = "functions";
private const string AGENT_TEMPLATES_FOLDER = "templates";
private const string AGENT_RESPONSES_FOLDER = "responses";
@@ -123,7 +124,9 @@ public partial class FileRepository : IBotSharpRepository
var agent = JsonSerializer.Deserialize(json, _options);
if (agent != null)
{
- agent = agent.SetInstruction(FetchInstruction(d))
+ var (defaultInstruction, channelInstructions) = FetchInstructions(d);
+ agent = agent.SetInstruction(defaultInstruction)
+ .SetChannelInstructions(channelInstructions)
.SetFunctions(FetchFunctions(d))
.SetTemplates(FetchTemplates(d))
.SetResponses(FetchResponses(d))
@@ -165,6 +168,17 @@ public partial class FileRepository : IBotSharpRepository
#region Private methods
+ private void DeleteBeforeCreateDirectory(string dir)
+ {
+ if (string.IsNullOrWhiteSpace(dir)) return;
+
+ if (Directory.Exists(dir))
+ {
+ Directory.Delete(dir, true);
+ }
+ Directory.CreateDirectory(dir);
+ }
+
private string GetAgentDataDir(string agentId)
{
var dir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId);
@@ -186,13 +200,46 @@ public partial class FileRepository : IBotSharpRepository
return (agent, agentFile);
}
- private string? FetchInstruction(string fileDir)
+ private (string, List) FetchInstructions(string fileDir)
{
- var file = Path.Combine(fileDir, $"{AGENT_INSTRUCTION_FILE}.{_agentSettings.TemplateFormat}");
- if (!File.Exists(file)) return null;
+ var defaultInstruction = string.Empty;
+ var channelInstructions = new List();
- var instruction = File.ReadAllText(file);
- return instruction;
+ var instructionDir = Path.Combine(fileDir, AGENT_INSTRUCTIONS_FOLDER);
+ if (!Directory.Exists(instructionDir))
+ {
+ return (defaultInstruction, channelInstructions);
+ }
+
+ foreach (var file in Directory.GetFiles(instructionDir))
+ {
+ var extension = Path.GetExtension(file).Substring(1);
+ if (!extension.IsEqualTo(_agentSettings.TemplateFormat))
+ {
+ continue;
+ }
+
+ var segments = Path.GetFileName(file).Split(".", StringSplitOptions.RemoveEmptyEntries);
+ if (segments.IsNullOrEmpty() || !segments[0].IsEqualTo(AGENT_INSTRUCTION_FILE))
+ {
+ continue;
+ }
+
+ if (segments.Length == 2)
+ {
+ defaultInstruction = File.ReadAllText(file);
+ }
+ else if (segments.Length == 3)
+ {
+ var item = new ChannelInstruction
+ {
+ Channel = segments[1],
+ Instruction = File.ReadAllText(file)
+ };
+ channelInstructions.Add(item);
+ }
+ }
+ return (defaultInstruction, channelInstructions);
}
private List FetchFunctions(string fileDir)
@@ -298,13 +345,14 @@ public partial class FileRepository : IBotSharpRepository
var agent = JsonSerializer.Deserialize(agentJson, _options);
if (agent == null) return null;
- var instruction = FetchInstruction(agentDir);
+ var (defaultInstruction, channelInstructions) = FetchInstructions(agentDir);
var functions = FetchFunctions(agentDir);
var samples = FetchSamples(agentDir);
var templates = FetchTemplates(agentDir);
var responses = FetchResponses(agentDir);
- return agent.SetInstruction(instruction)
+ return agent.SetInstruction(defaultInstruction)
+ .SetChannelInstructions(channelInstructions)
.SetFunctions(functions)
.SetTemplates(templates)
.SetSamples(samples)
diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01dcc3e5-0af7-49e6-ad7a-a760bd12dc4b/instruction.liquid b/src/Infrastructure/BotSharp.Core/data/agents/01dcc3e5-0af7-49e6-ad7a-a760bd12dc4b/instructions/instruction.liquid
similarity index 100%
rename from src/Infrastructure/BotSharp.Core/data/agents/01dcc3e5-0af7-49e6-ad7a-a760bd12dc4b/instruction.liquid
rename to src/Infrastructure/BotSharp.Core/data/agents/01dcc3e5-0af7-49e6-ad7a-a760bd12dc4b/instructions/instruction.liquid
diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01e2fc5c-2c89-4ec7-8470-7688608b496c/instruction.liquid b/src/Infrastructure/BotSharp.Core/data/agents/01e2fc5c-2c89-4ec7-8470-7688608b496c/instructions/instruction.liquid
similarity index 100%
rename from src/Infrastructure/BotSharp.Core/data/agents/01e2fc5c-2c89-4ec7-8470-7688608b496c/instruction.liquid
rename to src/Infrastructure/BotSharp.Core/data/agents/01e2fc5c-2c89-4ec7-8470-7688608b496c/instructions/instruction.liquid
diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-0af7-49e6-ad7a-a760bd12dc4d/instruction.liquid b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-0af7-49e6-ad7a-a760bd12dc4d/instructions/instruction.liquid
similarity index 100%
rename from src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-0af7-49e6-ad7a-a760bd12dc4d/instruction.liquid
rename to src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-0af7-49e6-ad7a-a760bd12dc4d/instructions/instruction.liquid
diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/instruction.liquid b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/instructions/instruction.liquid
similarity index 100%
rename from src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/instruction.liquid
rename to src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/instructions/instruction.liquid
diff --git a/src/Infrastructure/BotSharp.Core/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/instruction.liquid b/src/Infrastructure/BotSharp.Core/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/instructions/instruction.liquid
similarity index 100%
rename from src/Infrastructure/BotSharp.Core/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/instruction.liquid
rename to src/Infrastructure/BotSharp.Core/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/instructions/instruction.liquid
diff --git a/src/Infrastructure/BotSharp.Core/data/agents/dfd9b46d-d00c-40af-8a75-3fbdc2b89869/instruction.liquid b/src/Infrastructure/BotSharp.Core/data/agents/dfd9b46d-d00c-40af-8a75-3fbdc2b89869/instructions/instruction.liquid
similarity index 100%
rename from src/Infrastructure/BotSharp.Core/data/agents/dfd9b46d-d00c-40af-8a75-3fbdc2b89869/instruction.liquid
rename to src/Infrastructure/BotSharp.Core/data/agents/dfd9b46d-d00c-40af-8a75-3fbdc2b89869/instructions/instruction.liquid
diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs
index f2bbc2eb..f033e31c 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs
@@ -1,4 +1,3 @@
-using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Users.Enums;
namespace BotSharp.OpenAPI.Controllers;
@@ -28,17 +27,24 @@ public class AgentController : ControllerBase
[HttpGet("/agent/{id}")]
public async Task GetAgent([FromRoute] string id)
{
- var agents = await GetAgents(new AgentFilter
+ var pagedAgents = await _agentService.GetAgents(new AgentFilter
{
AgentIds = new List { id }
- }, useHook: true);
+ });
- var targetAgent = agents.Items.FirstOrDefault();
- if (targetAgent == null) return null;
+ var foundAgent = pagedAgents.Items.FirstOrDefault();
+ if (foundAgent == null) return null;
+
+ await _agentService.InheritAgent(foundAgent);
+ var targetAgent = AgentViewModel.FromAgent(foundAgent);
+ var agentSetting = _services.GetRequiredService();
+ targetAgent.IsHost = targetAgent.Id == agentSetting.HostAgentId;
var redirectAgentIds = targetAgent.RoutingRules
.Where(x => !string.IsNullOrEmpty(x.RedirectTo))
- .Select(x => x.RedirectTo).ToList();
+ .Select(x => x.RedirectTo)
+ .ToList();
+
var redirectAgents = await _agentService.GetAgents(new AgentFilter
{
AgentIds = redirectAgentIds
@@ -65,39 +71,16 @@ public class AgentController : ControllerBase
}
[HttpGet("/agents")]
- public async Task> GetAgents([FromQuery] AgentFilter filter, [FromQuery] bool useHook = false)
+ public async Task> GetAgents([FromQuery] AgentFilter filter)
{
var agentSetting = _services.GetRequiredService();
var pagedAgents = await _agentService.GetAgents(filter);
-
- var items = new List();
- var agents = new List();
- if (useHook)
- {
- // prerender agent
- foreach (var agent in pagedAgents.Items)
- {
- var renderedAgent = await _agentService.LoadAgent(agent.Id);
- items.Add(renderedAgent);
- }
-
- // Set IsHost
- agents = items.Select(x => AgentViewModel.FromAgent(x)).ToList();
- foreach (var agent in agents)
- {
- agent.IsHost = agentSetting.HostAgentId == agent.Id;
- }
- }
- else
- {
- items = pagedAgents.Items.ToList();
- agents = items.Select(x => AgentViewModel.FromAgent(x)).ToList();
- }
+ var agents = pagedAgents?.Items?.Select(x => AgentViewModel.FromAgent(x))?.ToList() ?? new List();
return new PagedItems
{
Items = agents,
- Count = pagedAgents.Count
+ Count = pagedAgents?.Count ?? 0
};
}
diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/KnowledgeBaseController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/KnowledgeBaseController.cs
index e20632f5..b01c4950 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/KnowledgeBaseController.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/KnowledgeBaseController.cs
@@ -16,30 +16,36 @@ public class KnowledgeBaseController : ControllerBase
_services = services;
}
- [HttpPost("/knowledge/{collection}/search")]
- public async Task> SearchKnowledge([FromRoute] string collection, [FromBody] SearchKnowledgeModel model)
+ [HttpGet("knowledge/collections")]
+ public async Task> GetKnowledgeCollections()
{
- var options = new KnowledgeRetrievalOptions
+ return await _knowledgeService.GetKnowledgeCollections();
+ }
+
+ [HttpPost("/knowledge/{collection}/search")]
+ public async Task> SearchKnowledge([FromRoute] string collection, [FromBody] SearchKnowledgeRequest request)
+ {
+ var options = new KnowledgeSearchOptions
{
- Text = model.Text,
- Fields = model.Fields,
- Limit = model.Limit ?? 5,
- Confidence = model.Confidence ?? 0.5f,
- WithVector = model.WithVector
+ Text = request.Text,
+ Fields = request.Fields,
+ Limit = request.Limit ?? 5,
+ Confidence = request.Confidence ?? 0.5f,
+ WithVector = request.WithVector
};
var results = await _knowledgeService.SearchKnowledge(collection, options);
- return results.Select(x => KnowledgeRetrivalViewModel.From(x)).ToList();
+ return results.Select(x => KnowledgeSearchResultViewModel.From(x)).ToList();
}
[HttpPost("/knowledge/{collection}/data")]
- public async Task> GetKnowledgeCollectionData([FromRoute] string collection, [FromBody] KnowledgeFilter filter)
+ public async Task> GetKnowledgeCollectionData([FromRoute] string collection, [FromBody] KnowledgeFilter filter)
{
var data = await _knowledgeService.GetKnowledgeCollectionData(collection, filter);
- var items = data.Items?.Select(x => KnowledgeCollectionDataViewModel.From(x))?
- .ToList() ?? new List();
+ var items = data.Items?.Select(x => KnowledgeSearchResultViewModel.From(x))?
+ .ToList() ?? new List();
- return new StringIdPagedItems
+ return new StringIdPagedItems
{
Count = data.Count,
NextId = data.NextId,
diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentCreationModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentCreationModel.cs
index c0fa8320..78f75833 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentCreationModel.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentCreationModel.cs
@@ -1,7 +1,6 @@
using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Functions.Models;
using BotSharp.Abstraction.Routing.Models;
-using BotSharp.Core.Infrastructures;
namespace BotSharp.OpenAPI.ViewModels.Agents;
@@ -16,21 +15,26 @@ public class AgentCreationModel
///
public string Instruction { get; set; } = string.Empty;
+ ///
+ ///
+ ///
+ public List ChannelInstructions { get; set; } = new();
+
///
/// LLM extensible Instructions in addition to the default Instructions
///
- public List Templates { get; set; } = new List();
+ public List Templates { get; set; } = new();
///
/// LLM callable function definition
///
- public List Functions { get; set; } = new List();
+ public List Functions { get; set; } = new();
///
/// Response template
///
- public List Responses { get; set; } = new List();
- public List Samples { get; set; } = new List();
+ public List Responses { get; set; } = new();
+ public List Samples { get; set; } = new();
public bool IsPublic { get; set; }
@@ -43,9 +47,9 @@ public class AgentCreationModel
///
/// Combine different Agents together to form a Profile.
///
- public List Profiles { get; set; } = new List();
- public List Utilities { get; set; } = new List();
- public List RoutingRules { get; set; } = new List();
+ public List Profiles { get; set; } = new();
+ public List Utilities { get; set; } = new();
+ public List RoutingRules { get; set; } = new();
public AgentLlmConfig? LlmConfig { get; set; }
public Agent ToAgent()
@@ -55,6 +59,7 @@ public class AgentCreationModel
Name = Name,
Description = Description,
Instruction = Instruction,
+ ChannelInstructions = ChannelInstructions,
Templates = Templates,
Functions = Functions,
Responses = Responses,
@@ -64,9 +69,7 @@ public class AgentCreationModel
Type = Type,
Disabled = Disabled,
Profiles = Profiles,
- RoutingRules = RoutingRules?
- .Select(x => RoutingRuleUpdateModel.ToDomainElement(x))?
- .ToList() ?? new List(),
+ RoutingRules = RoutingRules?.Select(x => RoutingRuleUpdateModel.ToDomainElement(x))?.ToList() ?? new List(),
LlmConfig = LlmConfig
};
}
diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentUpdateModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentUpdateModel.cs
index 96cc7278..d64530c6 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentUpdateModel.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentUpdateModel.cs
@@ -15,6 +15,12 @@ public class AgentUpdateModel
///
public string Instruction { get; set; } = string.Empty;
+ ///
+ /// Channel instructions
+ ///
+ [JsonPropertyName("channel_instructions")]
+ public List? ChannelInstructions { get; set; }
+
///
/// Templates
///
@@ -39,11 +45,11 @@ public class AgentUpdateModel
/// Routes
///
public List? Responses { get; set; }
+
[JsonPropertyName("is_public")]
-
public bool IsPublic { get; set; }
- [JsonPropertyName("allow_routing")]
+ [JsonPropertyName("allow_routing")]
public bool AllowRouting { get; set; }
public bool Disabled { get; set; }
@@ -52,8 +58,8 @@ public class AgentUpdateModel
/// Profile by channel
///
public List? Profiles { get; set; }
- [JsonPropertyName("routing_rules")]
+ [JsonPropertyName("routing_rules")]
public List? RoutingRules { get; set; }
[JsonPropertyName("llm_config")]
@@ -69,10 +75,9 @@ public class AgentUpdateModel
Disabled = Disabled,
Type = Type,
Profiles = Profiles ?? new List(),
- RoutingRules = RoutingRules?
- .Select(x => RoutingRuleUpdateModel.ToDomainElement(x))?
- .ToList() ?? new List(),
+ RoutingRules = RoutingRules?.Select(x => RoutingRuleUpdateModel.ToDomainElement(x))?.ToList() ?? new List(),
Instruction = Instruction ?? string.Empty,
+ ChannelInstructions = ChannelInstructions ?? new List(),
Templates = Templates ?? new List(),
Functions = Functions ?? new List(),
Responses = Responses ?? new List(),
diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs
index a88b3c72..5c23c4d4 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs
@@ -13,6 +13,9 @@ public class AgentViewModel
public string Description { get; set; }
public string Type { get; set; } = AgentType.Task;
public string Instruction { get; set; }
+
+ [JsonPropertyName("channel_instructions")]
+ public List ChannelInstructions { get; set; }
public List Templates { get; set; }
public List Functions { get; set; }
public List Responses { get; set; }
@@ -60,6 +63,7 @@ public class AgentViewModel
Description = agent.Description,
Type = agent.Type,
Instruction = agent.Instruction,
+ ChannelInstructions = agent.ChannelInstructions,
Templates = agent.Templates,
Functions = agent.Functions,
Responses = agent.Responses,
diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Knowledges/KnowledgeCollectionDataViewModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Knowledges/KnowledgeCollectionDataViewModel.cs
deleted file mode 100644
index f77b8777..00000000
--- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Knowledges/KnowledgeCollectionDataViewModel.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using BotSharp.Abstraction.Knowledges.Models;
-using System.Text.Json.Serialization;
-
-namespace BotSharp.OpenAPI.ViewModels.Knowledges;
-
-public class KnowledgeCollectionDataViewModel
-{
- [JsonPropertyName("id")]
- public string Id { get; set; }
-
- [JsonPropertyName("question")]
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- public string Question { get; set; }
-
- [JsonPropertyName("answer")]
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- public string Answer { get; set; }
-
- [JsonPropertyName("vector")]
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- public float[]? Vector { get; set; }
-
- public static KnowledgeCollectionDataViewModel From(KnowledgeCollectionData data)
- {
- return new KnowledgeCollectionDataViewModel
- {
- Id = data.Id,
- Question = data.Question,
- Answer = data.Answer,
- Vector = data.Vector
- };
- }
-}
diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Knowledges/KnowledgeRetrivalViewModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Knowledges/KnowledgeRetrivalViewModel.cs
deleted file mode 100644
index 2e2b9e08..00000000
--- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Knowledges/KnowledgeRetrivalViewModel.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using BotSharp.Abstraction.Knowledges.Models;
-using System.Text.Json.Serialization;
-
-namespace BotSharp.OpenAPI.ViewModels.Knowledges;
-
-public class KnowledgeRetrivalViewModel
-{
- [JsonPropertyName("data")]
- public IDictionary Data { get; set; }
-
- [JsonPropertyName("score")]
- public double Score { get; set; }
-
- [JsonPropertyName("vector")]
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- public float[]? Vector { get; set; }
-
- public static KnowledgeRetrivalViewModel From(KnowledgeRetrievalResult model)
- {
- return new KnowledgeRetrivalViewModel
- {
- Data = model.Data,
- Score = model.Score,
- Vector = model.Vector
- };
- }
-}
diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Knowledges/KnowledgeSearchResultViewModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Knowledges/KnowledgeSearchResultViewModel.cs
new file mode 100644
index 00000000..f322bc7d
--- /dev/null
+++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Knowledges/KnowledgeSearchResultViewModel.cs
@@ -0,0 +1,33 @@
+using BotSharp.Abstraction.Knowledges.Models;
+using System.Text.Json.Serialization;
+
+namespace BotSharp.OpenAPI.ViewModels.Knowledges;
+
+public class KnowledgeSearchResultViewModel
+{
+ [JsonPropertyName("id")]
+ public string Id { get; set; }
+
+ [JsonPropertyName("data")]
+ public IDictionary Data { get; set; }
+
+ [JsonPropertyName("score")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public double? Score { get; set; }
+
+ [JsonPropertyName("vector")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public float[]? Vector { get; set; }
+
+
+ public static KnowledgeSearchResultViewModel From(KnowledgeSearchResult result)
+ {
+ return new KnowledgeSearchResultViewModel
+ {
+ Id = result.Id,
+ Data = result.Data,
+ Score = result.Score,
+ Vector = result.Vector
+ };
+ }
+}
diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Knowledges/SearchKnowledgeModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Knowledges/SearchKnowledgeRequest.cs
similarity index 93%
rename from src/Infrastructure/BotSharp.OpenAPI/ViewModels/Knowledges/SearchKnowledgeModel.cs
rename to src/Infrastructure/BotSharp.OpenAPI/ViewModels/Knowledges/SearchKnowledgeRequest.cs
index 9a91e004..cacb133a 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Knowledges/SearchKnowledgeModel.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Knowledges/SearchKnowledgeRequest.cs
@@ -3,7 +3,7 @@ using System.Text.Json.Serialization;
namespace BotSharp.OpenAPI.ViewModels.Knowledges;
-public class SearchKnowledgeModel
+public class SearchKnowledgeRequest
{
[JsonPropertyName("text")]
public string Text { get; set; } = string.Empty;
diff --git a/src/Plugins/BotSharp.Plugin.HttpHandler/BotSharp.Plugin.HttpHandler.csproj b/src/Plugins/BotSharp.Plugin.HttpHandler/BotSharp.Plugin.HttpHandler.csproj
index 2911dc2b..8664c654 100644
--- a/src/Plugins/BotSharp.Plugin.HttpHandler/BotSharp.Plugin.HttpHandler.csproj
+++ b/src/Plugins/BotSharp.Plugin.HttpHandler/BotSharp.Plugin.HttpHandler.csproj
@@ -15,14 +15,14 @@
-
+
PreserveNewest
-
+
PreserveNewest
diff --git a/src/Plugins/BotSharp.Plugin.HttpHandler/data/agents/87c458fc-ec5f-40ae-8ed6-05dda8a07523/instruction.liquid b/src/Plugins/BotSharp.Plugin.HttpHandler/data/agents/87c458fc-ec5f-40ae-8ed6-05dda8a07523/instructions/instruction.liquid
similarity index 100%
rename from src/Plugins/BotSharp.Plugin.HttpHandler/data/agents/87c458fc-ec5f-40ae-8ed6-05dda8a07523/instruction.liquid
rename to src/Plugins/BotSharp.Plugin.HttpHandler/data/agents/87c458fc-ec5f-40ae-8ed6-05dda8a07523/instructions/instruction.liquid
diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/BotSharp.Plugin.KnowledgeBase.csproj b/src/Plugins/BotSharp.Plugin.KnowledgeBase/BotSharp.Plugin.KnowledgeBase.csproj
index ecf15fe2..42663445 100644
--- a/src/Plugins/BotSharp.Plugin.KnowledgeBase/BotSharp.Plugin.KnowledgeBase.csproj
+++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/BotSharp.Plugin.KnowledgeBase.csproj
@@ -20,7 +20,7 @@
-
+
@@ -34,7 +34,7 @@
PreserveNewest
-
+
PreserveNewest
diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/KnowledgeRetrievalFn.cs b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/KnowledgeRetrievalFn.cs
index ca81a4ba..52e45e7e 100644
--- a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/KnowledgeRetrievalFn.cs
+++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/KnowledgeRetrievalFn.cs
@@ -21,8 +21,9 @@ public class KnowledgeRetrievalFn : IFunctionCallback
embedding.SetModelName(_settings.TextEmbedding.Model);
var vector = await embedding.GetVectorAsync(args.Question);
- var vectorDb = _services.GetRequiredService();
- var knowledges = await vectorDb.Search(KnowledgeCollectionName.BotSharp, vector, new List { KnowledgePayloadName.Answer });
+ var vectorDb = _services.GetServices().FirstOrDefault(x => x.Name == _settings.VectorDb);
+ var collectionName = !string.IsNullOrWhiteSpace(_settings.DefaultCollection) ? _settings.DefaultCollection : KnowledgeCollectionName.BotSharp;
+ var knowledges = await vectorDb.Search(collectionName, vector, new List { KnowledgePayloadName.Answer });
if (!knowledges.IsNullOrEmpty())
{
diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/MemorizeKnowledgeFn.cs b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/MemorizeKnowledgeFn.cs
index 218b33d4..237f7385 100644
--- a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/MemorizeKnowledgeFn.cs
+++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/MemorizeKnowledgeFn.cs
@@ -25,11 +25,12 @@ public class MemorizeKnowledgeFn : IFunctionCallback
args.Question
});
- var vectorDb = _services.GetRequiredService();
- await vectorDb.CreateCollection(KnowledgeCollectionName.BotSharp, vector[0].Length);
+ var vectorDb = _services.GetServices().FirstOrDefault(x => x.Name == _settings.VectorDb);
+ var collectionName = !string.IsNullOrWhiteSpace(_settings.DefaultCollection) ? _settings.DefaultCollection : KnowledgeCollectionName.BotSharp;
+ await vectorDb.CreateCollection(collectionName, vector[0].Length);
var id = Guid.NewGuid().ToString();
- var result = await vectorDb.Upsert(KnowledgeCollectionName.BotSharp, id, vector[0],
+ var result = await vectorDb.Upsert(collectionName, id, vector[0],
args.Question,
new Dictionary
{
diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/MemVecDb/MemoryVectorDb.cs b/src/Plugins/BotSharp.Plugin.KnowledgeBase/MemVecDb/MemoryVectorDb.cs
index ba5e6383..f8f31ca2 100644
--- a/src/Plugins/BotSharp.Plugin.KnowledgeBase/MemVecDb/MemoryVectorDb.cs
+++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/MemVecDb/MemoryVectorDb.cs
@@ -27,12 +27,12 @@ public class MemoryVectorDb : IVectorDb
throw new NotImplementedException();
}
- public async Task> Search(string collectionName, float[] vector,
- IEnumerable fields, int limit = 5, float confidence = 0.5f, bool withVector = false)
+ public async Task> Search(string collectionName, float[] vector,
+ IEnumerable? fields, int limit = 5, float confidence = 0.5f, bool withVector = false)
{
if (!_vectors.ContainsKey(collectionName))
{
- return new List();
+ return new List();
}
var similarities = VectorUtility.CalCosineSimilarity(vector, _vectors[collectionName]);
@@ -41,7 +41,7 @@ public class MemoryVectorDb : IVectorDb
var results = np.argsort(similarities).ToArray()
.Reverse()
.Take(limit)
- .Select(i => new KnowledgeSearchResult
+ .Select(i => new KnowledgeCollectionData
{
Data = new Dictionary { { "text", _vectors[collectionName][i].Text } },
Score = similarities[i],
@@ -64,8 +64,8 @@ public class MemoryVectorDb : IVectorDb
return true;
}
- public Task DeleteCollectionData(string collectionName, string id)
+ public async Task DeleteCollectionData(string collectionName, string id)
{
- throw new NotImplementedException();
+ return await Task.FromResult(false);
}
}
diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Get.cs b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Get.cs
index 96a5c139..243eca02 100644
--- a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Get.cs
+++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Get.cs
@@ -2,36 +2,58 @@ namespace BotSharp.Plugin.KnowledgeBase.Services;
public partial class KnowledgeService
{
- public async Task> GetKnowledgeCollectionData(string collectionName, KnowledgeFilter filter)
+ public async Task> GetKnowledgeCollections()
{
try
{
var db = GetVectorDb();
- return await db.GetCollectionData(collectionName, filter);
+ return await db.GetCollections();
+ }
+ catch (Exception ex)
+ {
+ _logger.LogWarning($"Error when getting knowledge collections. {ex.Message}\r\n{ex.InnerException}");
+ return Enumerable.Empty();
+ }
+ }
+
+ public async Task> GetKnowledgeCollectionData(string collectionName, KnowledgeFilter filter)
+ {
+ try
+ {
+ var db = GetVectorDb();
+ var pagedResult = await db.GetCollectionData(collectionName, filter);
+ return new StringIdPagedItems
+ {
+ Count = pagedResult.Count,
+ Items = pagedResult.Items.Select(x => KnowledgeSearchResult.CopyFrom(x)),
+ NextId = pagedResult.NextId,
+ };
}
catch (Exception ex)
{
_logger.LogWarning($"Error when getting knowledge collection data ({collectionName}). {ex.Message}\r\n{ex.InnerException}");
- return new StringIdPagedItems();
+ return new StringIdPagedItems();
}
}
- public async Task> SearchKnowledge(string collectionName, KnowledgeRetrievalOptions options)
+ public async Task> SearchKnowledge(string collectionName, KnowledgeSearchOptions options)
{
- var textEmbedding = GetTextEmbedding();
- var vector = await textEmbedding.GetVectorAsync(options.Text);
-
- // Vector search
- var db = GetVectorDb();
- var fields = !options.Fields.IsNullOrEmpty() ? options.Fields : new List { KnowledgePayloadName.Text, KnowledgePayloadName.Answer };
- var found = await db.Search(collectionName, vector, fields, limit: options.Limit ?? 5, confidence: options.Confidence ?? 0.5f, withVector: options.WithVector);
-
- var results = found.Select(x => new KnowledgeRetrievalResult
+ try
{
- Data = x.Data,
- Score = x.Score,
- Vector = x.Vector
- }).ToList();
- return results;
+ var textEmbedding = GetTextEmbedding();
+ var vector = await textEmbedding.GetVectorAsync(options.Text);
+
+ // Vector search
+ var db = GetVectorDb();
+ var found = await db.Search(collectionName, vector, options.Fields, limit: options.Limit ?? 5, confidence: options.Confidence ?? 0.5f, withVector: options.WithVector);
+
+ var results = found.Select(x => KnowledgeSearchResult.CopyFrom(x)).ToList();
+ return results;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogWarning($"Error when searching knowledge ({collectionName}). {ex.Message}\r\n{ex.InnerException}");
+ return new List();
+ }
}
}
diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/data/agents/01acc3e5-0af7-49e6-ad7a-a760bd12dc40/instruction.liquid b/src/Plugins/BotSharp.Plugin.KnowledgeBase/data/agents/01acc3e5-0af7-49e6-ad7a-a760bd12dc40/instructions/instruction.liquid
similarity index 100%
rename from src/Plugins/BotSharp.Plugin.KnowledgeBase/data/agents/01acc3e5-0af7-49e6-ad7a-a760bd12dc40/instruction.liquid
rename to src/Plugins/BotSharp.Plugin.KnowledgeBase/data/agents/01acc3e5-0af7-49e6-ad7a-a760bd12dc40/instructions/instruction.liquid
diff --git a/src/Plugins/BotSharp.Plugin.MetaAI/Providers/FaissDb.cs b/src/Plugins/BotSharp.Plugin.MetaAI/Providers/FaissDb.cs
index 785acd4d..225c0705 100644
--- a/src/Plugins/BotSharp.Plugin.MetaAI/Providers/FaissDb.cs
+++ b/src/Plugins/BotSharp.Plugin.MetaAI/Providers/FaissDb.cs
@@ -26,8 +26,8 @@ public class FaissDb : IVectorDb
throw new NotImplementedException();
}
- public Task> Search(string collectionName, float[] vector,
- IEnumerable fields, int limit = 10, float confidence = 0.5f, bool withVector = false)
+ public Task> Search(string collectionName, float[] vector,
+ IEnumerable? fields, int limit = 10, float confidence = 0.5f, bool withVector = false)
{
throw new NotImplementedException();
}
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentDocument.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentDocument.cs
index 4f1c5194..baa0729f 100644
--- a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentDocument.cs
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentDocument.cs
@@ -8,6 +8,7 @@ public class AgentDocument : MongoBase
public string? InheritAgentId { get; set; }
public string? IconUrl { get; set; }
public string Instruction { get; set; }
+ public List ChannelInstructions { get; set; }
public List Templates { get; set; }
public List Functions { get; set; }
public List Responses { get; set; }
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Models/ChannelInstructionMongoElement.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/ChannelInstructionMongoElement.cs
new file mode 100644
index 00000000..884c638c
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/ChannelInstructionMongoElement.cs
@@ -0,0 +1,27 @@
+using BotSharp.Abstraction.Agents.Models;
+
+namespace BotSharp.Plugin.MongoStorage.Models;
+
+public class ChannelInstructionMongoElement
+{
+ public string Channel { get; set; }
+ public string Instruction { get; set; }
+
+ public static ChannelInstructionMongoElement ToMongoElement(ChannelInstruction instruction)
+ {
+ return new ChannelInstructionMongoElement
+ {
+ Channel = instruction.Channel,
+ Instruction = instruction.Instruction
+ };
+ }
+
+ public static ChannelInstruction ToDomainElement(ChannelInstructionMongoElement instruction)
+ {
+ return new ChannelInstruction
+ {
+ Channel = instruction.Channel,
+ Instruction = instruction.Instruction
+ };
+ }
+}
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Models/FunctionDefMongoElement.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/FunctionDefMongoElement.cs
index dac77d69..6f72c517 100644
--- a/src/Plugins/BotSharp.Plugin.MongoStorage/Models/FunctionDefMongoElement.cs
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/FunctionDefMongoElement.cs
@@ -8,6 +8,7 @@ public class FunctionDefMongoElement
{
public string Name { get; set; }
public string Description { get; set; }
+ public List? Channels { get; set; }
public string? VisibilityExpression { get; set; }
public string? Impact { get; set; }
public FunctionParametersDefMongoElement Parameters { get; set; } = new FunctionParametersDefMongoElement();
@@ -23,6 +24,7 @@ public class FunctionDefMongoElement
{
Name = function.Name,
Description = function.Description,
+ Channels = function.Channels,
VisibilityExpression = function.VisibilityExpression,
Impact = function.Impact,
Parameters = new FunctionParametersDefMongoElement
@@ -34,19 +36,20 @@ public class FunctionDefMongoElement
};
}
- public static FunctionDef ToDomainElement(FunctionDefMongoElement mongoFunction)
+ public static FunctionDef ToDomainElement(FunctionDefMongoElement function)
{
return new FunctionDef
{
- Name = mongoFunction.Name,
- Description = mongoFunction.Description,
- VisibilityExpression = mongoFunction.VisibilityExpression,
- Impact = mongoFunction.Impact,
+ Name = function.Name,
+ Description = function.Description,
+ Channels = function.Channels,
+ VisibilityExpression = function.VisibilityExpression,
+ Impact = function.Impact,
Parameters = new FunctionParametersDef
{
- Type = mongoFunction.Parameters.Type,
- Properties = JsonSerializer.Deserialize(mongoFunction.Parameters.Properties.IfNullOrEmptyAs("{}")),
- Required = mongoFunction.Parameters.Required,
+ Type = function.Parameters.Type,
+ Properties = JsonSerializer.Deserialize(function.Parameters.Properties.IfNullOrEmptyAs("{}")),
+ Required = function.Parameters.Required,
}
};
}
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs
index 60dcd6c3..49c8616e 100644
--- a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs
@@ -38,7 +38,7 @@ public partial class MongoRepository
UpdateAgentRoutingRules(agent.Id, agent.RoutingRules);
break;
case AgentField.Instruction:
- UpdateAgentInstruction(agent.Id, agent.Instruction);
+ UpdateAgentInstructions(agent.Id, agent.Instruction, agent.ChannelInstructions);
break;
case AgentField.Function:
UpdateAgentFunctions(agent.Id, agent.Functions);
@@ -156,13 +156,17 @@ public partial class MongoRepository
_dc.Agents.UpdateOne(filter, update);
}
- private void UpdateAgentInstruction(string agentId, string instruction)
+ private void UpdateAgentInstructions(string agentId, string instruction, List? channelInstructions)
{
- if (string.IsNullOrWhiteSpace(instruction)) return;
+ if (string.IsNullOrWhiteSpace(agentId)) return;
+
+ var instructionElements = channelInstructions?.Select(x => ChannelInstructionMongoElement.ToMongoElement(x))?
+ .ToList() ?? new List();
var filter = Builders.Filter.Eq(x => x.Id, agentId);
var update = Builders.Update
.Set(x => x.Instruction, instruction)
+ .Set(x => x.ChannelInstructions, instructionElements)
.Set(x => x.UpdatedTime, DateTime.UtcNow);
_dc.Agents.UpdateOne(filter, update);
@@ -253,6 +257,7 @@ public partial class MongoRepository
.Set(x => x.Profiles, agent.Profiles)
.Set(x => x.RoutingRules, agent.RoutingRules.Select(r => RoutingRuleMongoElement.ToMongoElement(r)).ToList())
.Set(x => x.Instruction, agent.Instruction)
+ .Set(x => x.ChannelInstructions, agent.ChannelInstructions.Select(i => ChannelInstructionMongoElement.ToMongoElement(i)).ToList())
.Set(x => x.Templates, agent.Templates.Select(t => AgentTemplateMongoElement.ToMongoElement(t)).ToList())
.Set(x => x.Functions, agent.Functions.Select(f => FunctionDefMongoElement.ToMongoElement(f)).ToList())
.Set(x => x.Responses, agent.Responses.Select(r => AgentResponseMongoElement.ToMongoElement(r)).ToList())
@@ -373,6 +378,9 @@ public partial class MongoRepository
IconUrl = x.IconUrl,
Description = x.Description,
Instruction = x.Instruction,
+ ChannelInstructions = x.ChannelInstructions?
+ .Select(i => ChannelInstructionMongoElement.ToMongoElement(i))?
+ .ToList() ?? new List(),
Templates = x.Templates?
.Select(t => AgentTemplateMongoElement.ToMongoElement(t))?
.ToList() ?? new List(),
@@ -463,6 +471,9 @@ public partial class MongoRepository
IconUrl = agentDoc.IconUrl,
Description = agentDoc.Description,
Instruction = agentDoc.Instruction,
+ ChannelInstructions = !agentDoc.ChannelInstructions.IsNullOrEmpty() ? agentDoc.ChannelInstructions
+ .Select(i => ChannelInstructionMongoElement.ToDomainElement(i))
+ .ToList() : new List(),
Templates = !agentDoc.Templates.IsNullOrEmpty() ? agentDoc.Templates
.Select(t => AgentTemplateMongoElement.ToDomainElement(t))
.ToList() : new List(),
@@ -472,6 +483,10 @@ public partial class MongoRepository
Responses = !agentDoc.Responses.IsNullOrEmpty() ? agentDoc.Responses
.Select(r => AgentResponseMongoElement.ToDomainElement(r))
.ToList() : new List(),
+ RoutingRules = !agentDoc.RoutingRules.IsNullOrEmpty() ? agentDoc.RoutingRules
+ .Select(r => RoutingRuleMongoElement.ToDomainElement(agentDoc.Id, agentDoc.Name, r))
+ .ToList() : new List(),
+ LlmConfig = AgentLlmConfigMongoElement.ToDomainElement(agentDoc.LlmConfig),
Samples = agentDoc.Samples ?? new List(),
Utilities = agentDoc.Utilities ?? new List(),
IsPublic = agentDoc.IsPublic,
@@ -479,10 +494,6 @@ public partial class MongoRepository
Type = agentDoc.Type,
InheritAgentId = agentDoc.InheritAgentId,
Profiles = agentDoc.Profiles,
- RoutingRules = !agentDoc.RoutingRules.IsNullOrEmpty() ? agentDoc.RoutingRules
- .Select(r => RoutingRuleMongoElement.ToDomainElement(agentDoc.Id, agentDoc.Name, r))
- .ToList() : new List(),
- LlmConfig = AgentLlmConfigMongoElement.ToDomainElement(agentDoc.LlmConfig)
};
}
}
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Transaction.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Transaction.cs
index 4a4542ed..e2ffbb0e 100644
--- a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Transaction.cs
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Transaction.cs
@@ -37,9 +37,12 @@ public partial class MongoRepository
{
Id = !string.IsNullOrEmpty(x.Id) ? x.Id : Guid.NewGuid().ToString(),
Name = x.Name,
+ IconUrl = x.IconUrl,
Description = x.Description,
Instruction = x.Instruction,
- IconUrl = x.IconUrl,
+ ChannelInstructions = x.ChannelInstructions?
+ .Select(i => ChannelInstructionMongoElement.ToMongoElement(i))?
+ .ToList() ?? new List(),
Templates = x.Templates?
.Select(t => AgentTemplateMongoElement.ToMongoElement(t))?
.ToList() ?? new List(),
@@ -71,6 +74,7 @@ public partial class MongoRepository
.Set(x => x.Name, agent.Name)
.Set(x => x.Description, agent.Description)
.Set(x => x.Instruction, agent.Instruction)
+ .Set(x => x.ChannelInstructions, agent.ChannelInstructions)
.Set(x => x.Templates, agent.Templates)
.Set(x => x.Functions, agent.Functions)
.Set(x => x.Responses, agent.Responses)
diff --git a/src/Plugins/BotSharp.Plugin.PythonInterpreter/BotSharp.Plugin.PythonInterpreter.csproj b/src/Plugins/BotSharp.Plugin.PythonInterpreter/BotSharp.Plugin.PythonInterpreter.csproj
new file mode 100644
index 00000000..b3293a0f
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.PythonInterpreter/BotSharp.Plugin.PythonInterpreter.csproj
@@ -0,0 +1,35 @@
+
+
+
+ $(TargetFramework)
+ enable
+ $(LangVersion)
+ $(BotSharpVersion)
+ $(GeneratePackageOnBuild)
+ $(GenerateDocumentationFile)
+ $(SolutionDir)packages
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Plugins/BotSharp.Plugin.PythonInterpreter/Enums/UtilityName.cs b/src/Plugins/BotSharp.Plugin.PythonInterpreter/Enums/UtilityName.cs
new file mode 100644
index 00000000..95a5b8a2
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.PythonInterpreter/Enums/UtilityName.cs
@@ -0,0 +1,6 @@
+namespace BotSharp.Plugin.PythonInterpreter.Enums;
+
+public class UtilityName
+{
+ public const string PythonInterpreter = "python-interpreter";
+}
diff --git a/src/Plugins/BotSharp.Plugin.PythonInterpreter/Functions/InterpretationFn.cs b/src/Plugins/BotSharp.Plugin.PythonInterpreter/Functions/InterpretationFn.cs
new file mode 100644
index 00000000..b12cb739
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.PythonInterpreter/Functions/InterpretationFn.cs
@@ -0,0 +1,46 @@
+using BotSharp.Abstraction.Conversations.Models;
+using BotSharp.Abstraction.Functions;
+using BotSharp.Abstraction.Interpreters.Models;
+using Microsoft.Extensions.Logging;
+using Python.Runtime;
+using System.Text.Json;
+using System.Threading.Tasks;
+
+namespace BotSharp.Plugin.PythonInterpreter.Functions;
+
+public class InterpretationFn : IFunctionCallback
+{
+ public string Name => "python_interpreter";
+ public string Indication => "Interpreting python code";
+
+ private readonly IServiceProvider _services;
+ private readonly ILogger _logger;
+
+ public async Task Execute(RoleDialogModel message)
+ {
+ var args = JsonSerializer.Deserialize(message.FunctionArgs);
+
+ using (Py.GIL())
+ {
+ // Import necessary Python modules
+ dynamic sys = Py.Import("sys");
+ dynamic io = Py.Import("io");
+
+ // Redirect standard output to capture it
+ dynamic stringIO = io.StringIO();
+ sys.stdout = stringIO;
+
+ // Execute a simple Python script
+ using var locals = new PyDict();
+ PythonEngine.Exec(args.Script, null, locals);
+
+ // Console.WriteLine($"Result from Python: {result}");
+ message.Content = stringIO.getvalue();
+
+ // Restore the original stdout
+ sys.stdout = sys.__stdout__;
+ }
+
+ return true;
+ }
+}
diff --git a/src/Plugins/BotSharp.Plugin.PythonInterpreter/Hooks/InterpreterAgentHook.cs b/src/Plugins/BotSharp.Plugin.PythonInterpreter/Hooks/InterpreterAgentHook.cs
new file mode 100644
index 00000000..64e0ec27
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.PythonInterpreter/Hooks/InterpreterAgentHook.cs
@@ -0,0 +1,51 @@
+namespace BotSharp.Plugin.PythonInterpreter.Hooks;
+
+public class InterpreterAgentHook : AgentHookBase
+{
+ private static string FUNCTION_NAME = "python_interpreter";
+
+ public override string SelfId => string.Empty;
+
+ public InterpreterAgentHook(IServiceProvider services, AgentSettings settings)
+ : base(services, settings)
+ {
+ }
+ public override void OnAgentLoaded(Agent agent)
+ {
+ var conv = _services.GetRequiredService();
+ var isConvMode = conv.IsConversationMode();
+ var isEnabled = !agent.Utilities.IsNullOrEmpty() && agent.Utilities.Contains(UtilityName.PythonInterpreter);
+
+ if (isConvMode && isEnabled)
+ {
+ var (prompt, fn) = GetPromptAndFunction();
+ if (fn != null)
+ {
+ if (!string.IsNullOrWhiteSpace(prompt))
+ {
+ agent.Instruction += $"\r\n\r\n{prompt}\r\n\r\n";
+ }
+
+ if (agent.Functions == null)
+ {
+ agent.Functions = new List { fn };
+ }
+ else
+ {
+ agent.Functions.Add(fn);
+ }
+ }
+ }
+
+ base.OnAgentLoaded(agent);
+ }
+
+ private (string, FunctionDef?) GetPromptAndFunction()
+ {
+ var db = _services.GetRequiredService();
+ var agent = db.GetAgent(BuiltInAgentId.UtilityAssistant);
+ var prompt = agent?.Templates?.FirstOrDefault(x => x.Name.IsEqualTo($"{FUNCTION_NAME}.fn"))?.Content ?? string.Empty;
+ var loadAttachmentFn = agent?.Functions?.FirstOrDefault(x => x.Name.IsEqualTo(FUNCTION_NAME));
+ return (prompt, loadAttachmentFn);
+ }
+}
diff --git a/src/Plugins/BotSharp.Plugin.PythonInterpreter/Hooks/InterpreterUtilityHook.cs b/src/Plugins/BotSharp.Plugin.PythonInterpreter/Hooks/InterpreterUtilityHook.cs
new file mode 100644
index 00000000..be37bfa1
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.PythonInterpreter/Hooks/InterpreterUtilityHook.cs
@@ -0,0 +1,9 @@
+namespace BotSharp.Plugin.PythonInterpreter.Hooks;
+
+public class InterpreterUtilityHook : IAgentUtilityHook
+{
+ public void AddUtilities(List utilities)
+ {
+ utilities.Add(UtilityName.PythonInterpreter);
+ }
+}
diff --git a/src/Plugins/BotSharp.Plugin.PythonInterpreter/InterpreterPlugin.cs b/src/Plugins/BotSharp.Plugin.PythonInterpreter/InterpreterPlugin.cs
new file mode 100644
index 00000000..075038e1
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.PythonInterpreter/InterpreterPlugin.cs
@@ -0,0 +1,17 @@
+using BotSharp.Plugin.PythonInterpreter.Hooks;
+
+namespace BotSharp.Plugin.PythonInterpreter;
+
+public class InterpreterPlugin : IBotSharpPlugin
+{
+ public string Id => "23174e08-e866-4173-824a-cf1d97afa8d0";
+ public string Name => "Python Interpreter";
+ public string Description => "Python Interpreter enables AI to write and execute Python code within a secure, sandboxed environment.";
+ public string? IconUrl => "https://static.vecteezy.com/system/resources/previews/012/697/295/non_2x/3d-python-programming-language-logo-free-png.png";
+
+ public void RegisterDI(IServiceCollection services, IConfiguration config)
+ {
+ services.AddScoped();
+ services.AddScoped();
+ }
+}
diff --git a/src/Plugins/BotSharp.Plugin.PythonInterpreter/Using.cs b/src/Plugins/BotSharp.Plugin.PythonInterpreter/Using.cs
new file mode 100644
index 00000000..8cc31aa1
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.PythonInterpreter/Using.cs
@@ -0,0 +1,18 @@
+global using System;
+global using System.Linq;
+global using System.Collections.Generic;
+
+global using Microsoft.Extensions.Configuration;
+global using Microsoft.Extensions.DependencyInjection;
+
+global using BotSharp.Abstraction.Agents;
+global using BotSharp.Abstraction.Plugins;
+global using BotSharp.Abstraction.Utilities;
+global using BotSharp.Abstraction.Agents.Enums;
+global using BotSharp.Abstraction.Agents.Models;
+global using BotSharp.Abstraction.Agents.Settings;
+global using BotSharp.Abstraction.Conversations;
+global using BotSharp.Abstraction.Functions.Models;
+global using BotSharp.Abstraction.Repositories;
+
+global using BotSharp.Plugin.PythonInterpreter.Enums;
diff --git a/src/Plugins/BotSharp.Plugin.PythonInterpreter/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/python_interpreter.json b/src/Plugins/BotSharp.Plugin.PythonInterpreter/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/python_interpreter.json
new file mode 100644
index 00000000..ac2b2a91
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.PythonInterpreter/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/python_interpreter.json
@@ -0,0 +1,19 @@
+{
+ "name": "python_interpreter",
+ "description": "write and execute python code, print the result in Console",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "script": {
+ "type": "string",
+ "description": "python code"
+ },
+ "language": {
+ "type": "string",
+ "enum": [ "python" ],
+ "description": "python code"
+ }
+ },
+ "required": [ "language", "script" ]
+ }
+}
\ No newline at end of file
diff --git a/src/Plugins/BotSharp.Plugin.PythonInterpreter/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/python_interpreter.fn.liquid b/src/Plugins/BotSharp.Plugin.PythonInterpreter/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/python_interpreter.fn.liquid
new file mode 100644
index 00000000..8dd2425f
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.PythonInterpreter/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/python_interpreter.fn.liquid
@@ -0,0 +1 @@
+Write and execute Python script in python_interpreter function, and use python function print(a) to output the result in stand output.
\ No newline at end of file
diff --git a/src/Plugins/BotSharp.Plugin.Qdrant/QdrantDb.cs b/src/Plugins/BotSharp.Plugin.Qdrant/QdrantDb.cs
index f03b4ab6..0e56f680 100644
--- a/src/Plugins/BotSharp.Plugin.Qdrant/QdrantDb.cs
+++ b/src/Plugins/BotSharp.Plugin.Qdrant/QdrantDb.cs
@@ -57,8 +57,7 @@ public class QdrantDb : IVectorDb
var points = response?.Result?.Select(x => new KnowledgeCollectionData
{
Id = x.Id?.Uuid ?? string.Empty,
- Question = x.Payload.ContainsKey(KnowledgePayloadName.Text) ? x.Payload[KnowledgePayloadName.Text].StringValue : string.Empty,
- Answer = x.Payload.ContainsKey(KnowledgePayloadName.Answer) ? x.Payload[KnowledgePayloadName.Answer].StringValue : string.Empty,
+ Data = x.Payload.ToDictionary(x => x.Key, x => x.Value.StringValue),
Vector = filter.WithVector ? x.Vectors?.Vector?.Data?.ToArray() : null
})?.ToList() ?? new List();
@@ -125,30 +124,46 @@ public class QdrantDb : IVectorDb
return result.Status == UpdateStatus.Completed;
}
- public async Task> Search(string collectionName, float[] vector,
- IEnumerable fields, int limit = 5, float confidence = 0.5f, bool withVector = false)
+ public async Task> Search(string collectionName, float[] vector,
+ IEnumerable? fields, int limit = 5, float confidence = 0.5f, bool withVector = false)
{
+ var results = new List();
+
var client = GetClient();
+ var exist = await DoesCollectionExist(client, collectionName);
+ if (!exist)
+ {
+ return results;
+ }
+
var points = await client.SearchAsync(collectionName, vector, limit: (ulong)limit, scoreThreshold: confidence);
- var results = new List();
+ var pickFields = fields != null;
foreach (var point in points)
{
var data = new Dictionary();
- foreach (var field in fields)
+ if (pickFields)
{
- if (point.Payload.ContainsKey(field))
+ foreach (var field in fields)
{
- data[field] = point.Payload[field].StringValue;
- }
- else
- {
- data[field] = "";
+ if (point.Payload.ContainsKey(field))
+ {
+ data[field] = point.Payload[field].StringValue;
+ }
+ else
+ {
+ data[field] = "";
+ }
}
}
-
- results.Add(new KnowledgeSearchResult
+ else
{
+ data = point.Payload.ToDictionary(k => k.Key, v => v.Value.StringValue);
+ }
+
+ results.Add(new KnowledgeCollectionData
+ {
+ Id = point.Id.Uuid,
Data = data,
Score = point.Score,
Vector = withVector ? point.Vectors?.Vector?.Data?.ToArray() : null
diff --git a/src/Plugins/BotSharp.Plugin.SemanticKernel/SemanticKernelMemoryStoreProvider.cs b/src/Plugins/BotSharp.Plugin.SemanticKernel/SemanticKernelMemoryStoreProvider.cs
index a5db6de8..487b8ffd 100644
--- a/src/Plugins/BotSharp.Plugin.SemanticKernel/SemanticKernelMemoryStoreProvider.cs
+++ b/src/Plugins/BotSharp.Plugin.SemanticKernel/SemanticKernelMemoryStoreProvider.cs
@@ -2,7 +2,6 @@ using BotSharp.Abstraction.Knowledges.Models;
using BotSharp.Abstraction.Utilities;
using BotSharp.Abstraction.VectorStorage;
using Microsoft.SemanticKernel.Memory;
-using System;
using System.Collections.Generic;
using System.Threading.Tasks;
@@ -44,15 +43,15 @@ namespace BotSharp.Plugin.SemanticKernel
return result;
}
- public async Task> Search(string collectionName, float[] vector,
- IEnumerable fields, int limit = 5, float confidence = 0.5f, bool withVector = false)
+ public async Task> Search(string collectionName, float[] vector,
+ IEnumerable? fields, int limit = 5, float confidence = 0.5f, bool withVector = false)
{
var results = _memoryStore.GetNearestMatchesAsync(collectionName, vector, limit);
- var resultTexts = new List();
+ var resultTexts = new List();
await foreach (var (record, score) in results)
{
- resultTexts.Add(new KnowledgeSearchResult
+ resultTexts.Add(new KnowledgeCollectionData
{
Data = new Dictionary { { "text", record.Metadata.Text } },
Score = score,
diff --git a/src/Plugins/BotSharp.Plugin.SqlDriver/BotSharp.Plugin.SqlDriver.csproj b/src/Plugins/BotSharp.Plugin.SqlDriver/BotSharp.Plugin.SqlDriver.csproj
index 8d861d68..6d2b4b05 100644
--- a/src/Plugins/BotSharp.Plugin.SqlDriver/BotSharp.Plugin.SqlDriver.csproj
+++ b/src/Plugins/BotSharp.Plugin.SqlDriver/BotSharp.Plugin.SqlDriver.csproj
@@ -18,7 +18,7 @@
-
+
@@ -26,7 +26,7 @@
PreserveNewest
-
+
PreserveNewest
diff --git a/src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/beda4c12-e1ec-4b4b-b328-3df4a6687c4f/instruction.liquid b/src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/beda4c12-e1ec-4b4b-b328-3df4a6687c4f/instructions/instruction.liquid
similarity index 100%
rename from src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/beda4c12-e1ec-4b4b-b328-3df4a6687c4f/instruction.liquid
rename to src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/beda4c12-e1ec-4b4b-b328-3df4a6687c4f/instructions/instruction.liquid
diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioVoiceController.cs b/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioVoiceController.cs
index 6e163ce8..859e34ff 100644
--- a/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioVoiceController.cs
+++ b/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioVoiceController.cs
@@ -1,5 +1,4 @@
using BotSharp.Abstraction.Files;
-using BotSharp.Abstraction.Routing;
using BotSharp.Core.Infrastructures;
using BotSharp.Plugin.Twilio.Models;
using BotSharp.Plugin.Twilio.Services;
@@ -10,7 +9,7 @@ using System.IdentityModel.Tokens.Jwt;
namespace BotSharp.Plugin.Twilio.Controllers;
[AllowAnonymous]
-[Route("[controller]")]
+[Route("twilio/voice")]
public class TwilioVoiceController : TwilioController
{
private readonly TwilioSetting _settings;
@@ -38,73 +37,25 @@ public class TwilioVoiceController : TwilioController
};
}
- [HttpPost("/twilio/voice/welcome")]
- public async Task StartConversation(VoiceRequest request)
- {
- string sessionId = $"TwilioVoice_{request.CallSid}";
- var twilio = _services.GetRequiredService();
- var response = twilio.ReturnInstructions("Hello, how may I help you?");
- return TwiML(response);
- }
-
- [HttpPost("/twilio/voice/{agentId}")]
- public async Task ReceivedVoiceMessage([FromRoute] string agentId, VoiceRequest input)
- {
- string sessionId = $"TwilioVoice_{input.CallSid}";
-
- var inputMsg = new RoleDialogModel(AgentRole.User, input.SpeechResult);
- var conv = _services.GetRequiredService();
- var routing = _services.GetRequiredService();
- routing.Context.SetMessageId(sessionId, inputMsg.MessageId);
-
- conv.SetConversationId(sessionId, new List
- {
- new MessageState("channel", ConversationChannel.Phone),
- new MessageState("calling_phone", input.DialCallSid)
- });
-
- var twilio = _services.GetRequiredService();
- VoiceResponse response = default;
-
- var result = await conv.SendMessage(agentId,
- inputMsg,
- replyMessage: null,
- async msg =>
- {
- response = twilio.ReturnInstructions(msg.Content);
- if (msg.FunctionName == "conversation_end")
- {
- response = twilio.HangUp(msg.Content);
- }
- }, async functionExecuting =>
- {
- }, async functionExecuted =>
- {
- });
-
- return TwiML(response);
- }
-
-
- [HttpPost("start")]
- public TwiMLResult InitiateConversation(VoiceRequest request)
+ [HttpPost("welcome")]
+ public TwiMLResult InitiateConversation(VoiceRequest request, [FromQuery] string states)
{
if (request?.CallSid == null) throw new ArgumentNullException(nameof(VoiceRequest.CallSid));
- string sessionId = $"TwilioVoice_{request.CallSid}";
+ string conversationId = $"TwilioVoice_{request.CallSid}";
var twilio = _services.GetRequiredService();
- var url = $"twiliovoice/{sessionId}/send/0";
- var response = twilio.ReturnInstructions("twilio/welcome.mp3", url, false);
+ var url = $"twilio/voice/{conversationId}/receive/0?states={states}";
+ var response = twilio.ReturnInstructions("twilio/welcome.mp3", url, true);
return TwiML(response);
}
- [HttpPost("{sessionId}/send/{seqNum}")]
- public async Task SendCallerMessage([FromRoute] string sessionId, [FromRoute] int seqNum, VoiceRequest request)
+ [HttpPost("{conversationId}/receive/{seqNum}")]
+ public async Task ReceiveCallerMessage([FromRoute] string conversationId, [FromRoute] int seqNum, [FromQuery] string states, VoiceRequest request)
{
var twilio = _services.GetRequiredService();
var messageQueue = _services.GetRequiredService();
var sessionManager = _services.GetRequiredService();
- var url = $"twiliovoice/{sessionId}/reply/{seqNum}";
- var messages = await sessionManager.RetrieveStagedCallerMessagesAsync(sessionId, seqNum);
+ var url = $"twilio/voice/{conversationId}/reply/{seqNum}?states={states}";
+ var messages = await sessionManager.RetrieveStagedCallerMessagesAsync(conversationId, seqNum);
if (!string.IsNullOrWhiteSpace(request.SpeechResult))
{
messages.Add(request.SpeechResult);
@@ -113,48 +64,78 @@ public class TwilioVoiceController : TwilioController
VoiceResponse response;
if (!string.IsNullOrWhiteSpace(messageContent))
{
+
var callerMessage = new CallerMessage()
{
- SessionId = sessionId,
+ ConversationId = conversationId,
SeqNumber = seqNum,
Content = messageContent,
From = request.From
};
+ if (!string.IsNullOrEmpty(states))
+ {
+ var kvp = states.Split(':');
+ if (kvp.Length == 2)
+ {
+ callerMessage.States.Add(kvp[0], kvp[1]);
+ }
+ }
await messageQueue.EnqueueAsync(callerMessage);
- response = twilio.ReturnInstructions("twilio/holdon.mp3", url, true);
+ response = twilio.ReturnInstructions(null, url, true, 1);
}
else
{
- response = twilio.HangUp("twilio/holdon.mp3");
+ var speechPath = seqNum > 0 ? $"twilio/voice/speeches/{conversationId}/{seqNum - 1}.mp3" : "twilio/welcome.mp3";
+ response = twilio.ReturnInstructions(speechPath, $"twilio/voice/{conversationId}/receive/{seqNum}?states={states}", true);
}
return TwiML(response);
}
- [HttpPost("{sessionId}/reply/{seqNum}")]
- public async Task ReplyCallerMessage([FromRoute] string sessionId, [FromRoute] int seqNum, VoiceRequest request)
+ [HttpPost("{conversationId}/reply/{seqNum}")]
+ public async Task ReplyCallerMessage([FromRoute] string conversationId, [FromRoute] int seqNum, [FromQuery] string states, VoiceRequest request)
{
var nextSeqNum = seqNum + 1;
var sessionManager = _services.GetRequiredService();
var twilio = _services.GetRequiredService();
if (request.SpeechResult != null)
{
- await sessionManager.StageCallerMessageAsync(sessionId, nextSeqNum, request.SpeechResult);
+ await sessionManager.StageCallerMessageAsync(conversationId, nextSeqNum, request.SpeechResult);
}
- var reply = await sessionManager.GetAssistantReplyAsync(sessionId, seqNum);
+ var reply = await sessionManager.GetAssistantReplyAsync(conversationId, seqNum);
VoiceResponse response;
- if (string.IsNullOrEmpty(reply))
+ if (reply == null)
{
- response = twilio.ReturnInstructions(null, $"twiliovoice/{sessionId}/reply/{seqNum}", true);
+ var indication = await sessionManager.GetReplyIndicationAsync(conversationId, seqNum);
+ if (indication != null)
+ {
+ var textToSpeechService = CompletionProvider.GetTextToSpeech(_services, "openai", "tts-1");
+ var fileService = _services.GetRequiredService();
+ var data = await textToSpeechService.GenerateSpeechFromTextAsync(indication);
+ var fileName = $"indication_{seqNum}.mp3";
+ await fileService.SaveSpeechFileAsync(conversationId, fileName, data);
+ response = twilio.ReturnInstructions($"twilio/voice/speeches/{conversationId}/{fileName}", $"twilio/voice/{conversationId}/reply/{seqNum}?states={states}", true, 2);
+ }
+ else
+ {
+ response = twilio.ReturnInstructions(null, $"twilio/voice/{conversationId}/reply/{seqNum}?states={states}", true, 1);
+ }
}
else
{
-
var textToSpeechService = CompletionProvider.GetTextToSpeech(_services, "openai", "tts-1");
var fileService = _services.GetRequiredService();
- var data = await textToSpeechService.GenerateSpeechFromTextAsync(reply);
- var fileName = $"{seqNum}.mp3";
- await fileService.SaveSpeechFileAsync(sessionId, fileName, data);
- response = twilio.ReturnInstructions($"twiliovoice/speeches/{sessionId}/{fileName}", $"twiliovoice/{sessionId}/send/{nextSeqNum}", true);
+ var data = await textToSpeechService.GenerateSpeechFromTextAsync(reply.Content);
+ var fileName = $"reply_{seqNum}.mp3";
+ await fileService.SaveSpeechFileAsync(conversationId, fileName, data);
+ if (reply.ConversationEnd)
+ {
+ response = twilio.HangUp($"twilio/voice/speeches/{conversationId}/{fileName}");
+ }
+ else
+ {
+ response = twilio.ReturnInstructions($"twilio/voice/speeches/{conversationId}/{fileName}", $"twilio/voice/{conversationId}/receive/{nextSeqNum}?states={states}", true);
+ }
+
}
return TwiML(response);
}
diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Models/AssistantMessage.cs b/src/Plugins/BotSharp.Plugin.Twilio/Models/AssistantMessage.cs
new file mode 100644
index 00000000..f9a83613
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.Twilio/Models/AssistantMessage.cs
@@ -0,0 +1,8 @@
+namespace BotSharp.Plugin.Twilio.Models
+{
+ public class AssistantMessage
+ {
+ public bool ConversationEnd { get; set; }
+ public string Content { get; set; }
+ }
+}
diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Models/CallerMessage.cs b/src/Plugins/BotSharp.Plugin.Twilio/Models/CallerMessage.cs
index e0f4463a..a6339c7b 100644
--- a/src/Plugins/BotSharp.Plugin.Twilio/Models/CallerMessage.cs
+++ b/src/Plugins/BotSharp.Plugin.Twilio/Models/CallerMessage.cs
@@ -2,14 +2,15 @@ namespace BotSharp.Plugin.Twilio.Models
{
public class CallerMessage
{
- public string SessionId { get; set; }
+ public string ConversationId { get; set; }
public int SeqNumber { get; set; }
public string Content { get; set; }
public string From { get; set; }
+ public Dictionary States { get; set; } = new();
public override string ToString()
{
- return $"{SessionId}-{SeqNumber}";
+ return $"{ConversationId}-{SeqNumber}";
}
}
}
diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Services/ITwilioSessionManager.cs b/src/Plugins/BotSharp.Plugin.Twilio/Services/ITwilioSessionManager.cs
index 3ad027f7..b1acd298 100644
--- a/src/Plugins/BotSharp.Plugin.Twilio/Services/ITwilioSessionManager.cs
+++ b/src/Plugins/BotSharp.Plugin.Twilio/Services/ITwilioSessionManager.cs
@@ -1,12 +1,15 @@
+using BotSharp.Plugin.Twilio.Models;
using Task = System.Threading.Tasks.Task;
namespace BotSharp.Plugin.Twilio.Services
{
public interface ITwilioSessionManager
{
- Task SetAssistantReplyAsync(string sessionId, int seqNum, string message);
- Task GetAssistantReplyAsync(string sessionId, int seqNum);
- Task StageCallerMessageAsync(string sessionId, int seqNum, string message);
- Task> RetrieveStagedCallerMessagesAsync(string sessionId, int seqNum);
+ Task SetAssistantReplyAsync(string conversationId, int seqNum, AssistantMessage message);
+ Task GetAssistantReplyAsync(string conversationId, int seqNum);
+ Task StageCallerMessageAsync(string conversationId, int seqNum, string message);
+ Task> RetrieveStagedCallerMessagesAsync(string conversationId, int seqNum);
+ Task SetReplyIndicationAsync(string conversationId, int seqNum, string indication);
+ Task GetReplyIndicationAsync(string conversationId, int seqNum);
}
}
diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioMessageQueueService.cs b/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioMessageQueueService.cs
index dab06c4b..a84ce5d9 100644
--- a/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioMessageQueueService.cs
+++ b/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioMessageQueueService.cs
@@ -55,35 +55,53 @@ namespace BotSharp.Plugin.Twilio.Services
{
using var scope = _serviceProvider.CreateScope();
var sp = scope.ServiceProvider;
- string reply = null;
+ AssistantMessage reply = null;
var inputMsg = new RoleDialogModel(AgentRole.User, message.Content);
var conv = sp.GetRequiredService();
var routing = sp.GetRequiredService();
var config = sp.GetRequiredService();
- routing.Context.SetMessageId(message.SessionId, inputMsg.MessageId);
- conv.SetConversationId(message.SessionId, new List
+ routing.Context.SetMessageId(message.ConversationId, inputMsg.MessageId);
+ var states = new List
{
new MessageState("channel", ConversationChannel.Phone),
new MessageState("calling_phone", message.From)
- });
+ };
+ foreach (var kvp in message.States)
+ {
+ states.Add(new MessageState(kvp.Key, kvp.Value));
+ }
+ conv.SetConversationId(message.ConversationId, states);
+ var sessionManager = sp.GetRequiredService();
var result = await conv.SendMessage(config.AgentId,
inputMsg,
replyMessage: null,
async msg =>
{
- reply = msg.Content;
+ reply = new AssistantMessage()
+ {
+ ConversationEnd = msg.Instruction.ConversationEnd,
+ Content = msg.Content
+ };
+ },
+ async msg =>
+ {
+ if (!string.IsNullOrEmpty(msg.Indication))
+ {
+ await sessionManager.SetReplyIndicationAsync(message.ConversationId, message.SeqNumber, msg.Indication);
+ }
},
- async functionExecuting =>
- { },
async functionExecuted =>
{ }
);
- if (string.IsNullOrWhiteSpace(reply))
+ if (reply == null || string.IsNullOrWhiteSpace(reply.Content))
{
- reply = "Sorry, something was wrong.";
- }
- var sessionManager = sp.GetRequiredService();
- await sessionManager.SetAssistantReplyAsync(message.SessionId, message.SeqNumber, reply);
+ reply = new AssistantMessage()
+ {
+ ConversationEnd = true,
+ Content = "Sorry, something was wrong."
+ };
+ }
+ await sessionManager.SetAssistantReplyAsync(message.ConversationId, message.SeqNumber, reply);
}
}
}
diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioService.cs b/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioService.cs
index 09405817..a4e9d4ab 100644
--- a/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioService.cs
+++ b/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioService.cs
@@ -63,7 +63,7 @@ public class TwilioService
return response;
}
- public VoiceResponse ReturnInstructions(string speechPath, string callbackPath, bool actionOnEmptyResult)
+ public VoiceResponse ReturnInstructions(string speechPath, string callbackPath, bool actionOnEmptyResult, int timeout = 3)
{
var response = new VoiceResponse();
var gather = new Gather()
@@ -73,7 +73,9 @@ public class TwilioService
Gather.InputEnum.Speech
},
Action = new Uri($"{_settings.CallbackHost}/{callbackPath}"),
- SpeechTimeout = "3",
+ SpeechModel = Gather.SpeechModelEnum.PhoneCall,
+ SpeechTimeout = timeout > 0 ? timeout.ToString() : "3",
+ Timeout = timeout > 0 ? timeout : 3,
ActionOnEmptyResult = actionOnEmptyResult
};
if (!string.IsNullOrEmpty(speechPath))
diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioSessionManager.cs b/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioSessionManager.cs
index daefbdcc..eae0b238 100644
--- a/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioSessionManager.cs
+++ b/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioSessionManager.cs
@@ -1,3 +1,4 @@
+using BotSharp.Plugin.Twilio.Models;
using StackExchange.Redis;
using Task = System.Threading.Tasks.Task;
@@ -12,35 +13,51 @@ namespace BotSharp.Plugin.Twilio.Services
_redis = redis;
}
- public async Task GetAssistantReplyAsync(string sessionId, int seqNum)
+ public async Task GetAssistantReplyAsync(string conversationId, int seqNum)
{
var db = _redis.GetDatabase();
- var key = $"{sessionId}:Assisist:{seqNum}";
- return await db.StringGetAsync(key);
+ var key = $"{conversationId}:Assisist:{seqNum}";
+ var jsonStr = await db.StringGetAsync(key);
+ return jsonStr.IsNull ? null : JsonSerializer.Deserialize(jsonStr);
}
- public async Task> RetrieveStagedCallerMessagesAsync(string sessionId, int seqNum)
+ public async Task> RetrieveStagedCallerMessagesAsync(string conversationId, int seqNum)
{
var db = _redis.GetDatabase();
- var key = $"{sessionId}:Caller:{seqNum}";
+ var key = $"{conversationId}:Caller:{seqNum}";
return (await db.ListRangeAsync(key))
.Select(x => (string)x)
.ToList();
}
- public async Task SetAssistantReplyAsync(string sessionId, int seqNum, string message)
+ public async Task SetAssistantReplyAsync(string conversationId, int seqNum, AssistantMessage message)
{
+ var jsonStr = JsonSerializer.Serialize(message);
var db = _redis.GetDatabase();
- var key = $"{sessionId}:Assisist:{seqNum}";
- await db.StringSetAsync(key, message, TimeSpan.FromMinutes(5));
+ var key = $"{conversationId}:Assisist:{seqNum}";
+ await db.StringSetAsync(key, jsonStr, TimeSpan.FromMinutes(5));
}
- public async Task StageCallerMessageAsync(string sessionId, int seqNum, string message)
+ public async Task StageCallerMessageAsync(string conversationId, int seqNum, string message)
{
var db = _redis.GetDatabase();
- var key = $"{sessionId}:Caller:{seqNum}";
+ var key = $"{conversationId}:Caller:{seqNum}";
await db.ListRightPushAsync(key, message);
await db.KeyExpireAsync(key, DateTime.UtcNow.AddMinutes(10));
}
+
+ public async Task SetReplyIndicationAsync(string conversationId, int seqNum, string indication)
+ {
+ var db = _redis.GetDatabase();
+ var key = $"{conversationId}:Indication:{seqNum}";
+ await db.StringSetAsync(key, indication, TimeSpan.FromMinutes(5));
+ }
+
+ public async Task GetReplyIndicationAsync(string conversationId, int seqNum)
+ {
+ var db = _redis.GetDatabase();
+ var key = $"{conversationId}:Indication:{seqNum}";
+ return await db.StringGetAsync(key);
+ }
}
}
diff --git a/src/Plugins/BotSharp.Plugin.Twilio/TwilioPlugin.cs b/src/Plugins/BotSharp.Plugin.Twilio/TwilioPlugin.cs
index 38d278a6..1247d0d4 100644
--- a/src/Plugins/BotSharp.Plugin.Twilio/TwilioPlugin.cs
+++ b/src/Plugins/BotSharp.Plugin.Twilio/TwilioPlugin.cs
@@ -17,7 +17,6 @@ public class TwilioPlugin : IBotSharpPlugin
var settingService = provider.GetRequiredService();
return settingService.Bind("Twilio");
});
-
services.AddScoped();
var conn = ConnectionMultiplexer.Connect(config["Twilio:RedisConnectionString"]);
var sessionManager = new TwilioSessionManager(conn);
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/BotSharp.Plugin.WebDriver.csproj b/src/Plugins/BotSharp.Plugin.WebDriver/BotSharp.Plugin.WebDriver.csproj
index ce32616a..d6074b19 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/BotSharp.Plugin.WebDriver.csproj
+++ b/src/Plugins/BotSharp.Plugin.WebDriver/BotSharp.Plugin.WebDriver.csproj
@@ -40,7 +40,7 @@
-
+
@@ -50,7 +50,7 @@
PreserveNewest
-
+
PreserveNewest
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/instruction.liquid b/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/instructions/instruction.liquid
similarity index 100%
rename from src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/instruction.liquid
rename to src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/instructions/instruction.liquid
diff --git a/src/WebStarter/Program.cs b/src/WebStarter/Program.cs
index ed0f8baf..a13d9d0f 100644
--- a/src/WebStarter/Program.cs
+++ b/src/WebStarter/Program.cs
@@ -4,6 +4,7 @@ using BotSharp.Logger;
using BotSharp.Plugin.ChatHub;
using Serilog;
using BotSharp.Abstraction.Messaging.JsonConverters;
+using Python.Runtime;
var builder = WebApplication.CreateBuilder(args);
@@ -41,4 +42,11 @@ app.UseBotSharp()
.UseBotSharpOpenAPI(app.Environment)
.UseBotSharpUI();
+Runtime.PythonDLL = @"C:\Users\xxx\AppData\Local\Programs\Python\Python311\python311.dll";
+PythonEngine.Initialize();
+PythonEngine.BeginAllowThreads();
+
app.Run();
+
+// Shut down the Python engine
+PythonEngine.Shutdown();
\ No newline at end of file
diff --git a/src/WebStarter/WebStarter.csproj b/src/WebStarter/WebStarter.csproj
index 5a5b1ced..c7443dc1 100644
--- a/src/WebStarter/WebStarter.csproj
+++ b/src/WebStarter/WebStarter.csproj
@@ -30,6 +30,7 @@
+
diff --git a/src/WebStarter/appsettings.json b/src/WebStarter/appsettings.json
index 155dae1b..3b170fa0 100644
--- a/src/WebStarter/appsettings.json
+++ b/src/WebStarter/appsettings.json
@@ -259,6 +259,7 @@
"KnowledgeBase": {
"VectorDb": "Qdrant",
+ "DefaultCollection": "BotSharp",
"TextEmbedding": {
"Provider": "openai",
"Model": "text-embedding-3-small"
@@ -319,7 +320,8 @@
"BotSharp.Plugin.HttpHandler",
"BotSharp.Plugin.FileHandler",
"BotSharp.Plugin.EmailHandler",
- "BotSharp.Plugin.TencentCos"
+ "BotSharp.Plugin.TencentCos",
+ "BotSharp.Plugin.PythonInterpreter"
]
}
}
diff --git a/tests/BotSharp.Plugin.PizzaBot/BotSharp.Plugin.PizzaBot.csproj b/tests/BotSharp.Plugin.PizzaBot/BotSharp.Plugin.PizzaBot.csproj
index e448b9e0..716f1f4d 100644
--- a/tests/BotSharp.Plugin.PizzaBot/BotSharp.Plugin.PizzaBot.csproj
+++ b/tests/BotSharp.Plugin.PizzaBot/BotSharp.Plugin.PizzaBot.csproj
@@ -24,16 +24,16 @@
-
+
-
+
-
+
@@ -50,13 +50,13 @@
PreserveNewest
-
+
PreserveNewest
PreserveNewest
-
+
PreserveNewest
@@ -65,7 +65,7 @@
PreserveNewest
-
+
PreserveNewest
diff --git a/tests/BotSharp.Plugin.PizzaBot/data/agents/b284db86-e9c2-4c25-a59e-4649797dd130/instruction.liquid b/tests/BotSharp.Plugin.PizzaBot/data/agents/b284db86-e9c2-4c25-a59e-4649797dd130/instructions/instruction.liquid
similarity index 100%
rename from tests/BotSharp.Plugin.PizzaBot/data/agents/b284db86-e9c2-4c25-a59e-4649797dd130/instruction.liquid
rename to tests/BotSharp.Plugin.PizzaBot/data/agents/b284db86-e9c2-4c25-a59e-4649797dd130/instructions/instruction.liquid
diff --git a/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/instruction.liquid b/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/instructions/instruction.liquid
similarity index 100%
rename from tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/instruction.liquid
rename to tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/instructions/instruction.liquid
diff --git a/tests/BotSharp.Plugin.PizzaBot/data/agents/fe8c60aa-b114-4ef3-93cb-a8efeac80f75/instruction.liquid b/tests/BotSharp.Plugin.PizzaBot/data/agents/fe8c60aa-b114-4ef3-93cb-a8efeac80f75/instructions/instruction.liquid
similarity index 100%
rename from tests/BotSharp.Plugin.PizzaBot/data/agents/fe8c60aa-b114-4ef3-93cb-a8efeac80f75/instruction.liquid
rename to tests/BotSharp.Plugin.PizzaBot/data/agents/fe8c60aa-b114-4ef3-93cb-a8efeac80f75/instructions/instruction.liquid