diff --git a/BotSharp.sln b/BotSharp.sln
index 52b3f9d0..5baf8d10 100644
--- a/BotSharp.sln
+++ b/BotSharp.sln
@@ -121,6 +121,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotSharp.Core.SideCar", "sr
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.Plugin.VertexAI", "src\Plugins\BotSharp.Plugin.LangChain\BotSharp.Plugin.VertexAI.csproj", "{7DA2DCD0-551B-432E-AA5C-22DDD3ED459B}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.Core.Crontab", "src\Infrastructure\BotSharp.Core.Crontab\BotSharp.Core.Crontab.csproj", "{F812BAAE-5A7D-4DF7-8E71-70696B51C61F}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -489,6 +491,14 @@ Global
{7DA2DCD0-551B-432E-AA5C-22DDD3ED459B}.Release|Any CPU.Build.0 = Release|Any CPU
{7DA2DCD0-551B-432E-AA5C-22DDD3ED459B}.Release|x64.ActiveCfg = Release|Any CPU
{7DA2DCD0-551B-432E-AA5C-22DDD3ED459B}.Release|x64.Build.0 = Release|Any CPU
+ {F812BAAE-5A7D-4DF7-8E71-70696B51C61F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F812BAAE-5A7D-4DF7-8E71-70696B51C61F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F812BAAE-5A7D-4DF7-8E71-70696B51C61F}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {F812BAAE-5A7D-4DF7-8E71-70696B51C61F}.Debug|x64.Build.0 = Debug|Any CPU
+ {F812BAAE-5A7D-4DF7-8E71-70696B51C61F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F812BAAE-5A7D-4DF7-8E71-70696B51C61F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F812BAAE-5A7D-4DF7-8E71-70696B51C61F}.Release|x64.ActiveCfg = Release|Any CPU
+ {F812BAAE-5A7D-4DF7-8E71-70696B51C61F}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -547,6 +557,7 @@ Global
{F57F4862-F8D4-44A1-AC12-5C131B5C9785} = {51AFE054-AE99-497D-A593-69BAEFB5106F}
{6D3A54F9-4792-41DB-BE7D-4F7B1D918EAE} = {E29DC6C4-5E57-48C5-BCB0-6B8F84782749}
{7DA2DCD0-551B-432E-AA5C-22DDD3ED459B} = {D5293208-2BEF-42FC-A64C-5954F61720BA}
+ {F812BAAE-5A7D-4DF7-8E71-70696B51C61F} = {E29DC6C4-5E57-48C5-BCB0-6B8F84782749}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A9969D89-C98B-40A5-A12B-FC87E55B3A19}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentType.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentType.cs
index 53d64a07..455e87ff 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentType.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentType.cs
@@ -10,7 +10,7 @@ public class AgentType
///
/// Planning agent
///
- public const string Planning = "plan";
+ public const string Planning = "planning";
public const string Evaluating = "evaluation";
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/BuiltInAgentId.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/BuiltInAgentId.cs
index f2f64b6b..ecdda1c7 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/BuiltInAgentId.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/BuiltInAgentId.cs
@@ -32,11 +32,6 @@ public class BuiltInAgentId
///
public const string Learner = "01acc3e5-0af7-49e6-ad7a-a760bd12dc40";
- ///
- /// Plan feasible implementation steps for complex problems
- ///
- public const string Planner = "282a7128-69a1-44b0-878c-a9159b88f3b9";
-
///
/// SQL statement generation
///
diff --git a/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj b/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj
index 5be126b8..9b31ae6f 100644
--- a/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj
+++ b/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj
@@ -1,4 +1,4 @@
-
+
$(TargetFramework)
diff --git a/src/Infrastructure/BotSharp.Abstraction/Crontab/Models/CrontabItem.cs b/src/Infrastructure/BotSharp.Abstraction/Crontab/Models/CrontabItem.cs
new file mode 100644
index 00000000..a8acdc79
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/Crontab/Models/CrontabItem.cs
@@ -0,0 +1,24 @@
+namespace BotSharp.Abstraction.Crontab.Models;
+
+public class CrontabItem : ScheduleTaskArgs
+{
+ [JsonPropertyName("user_id")]
+ public string UserId { get; set; } = null!;
+
+ [JsonPropertyName("agent_id")]
+ public string AgentId { get; set; } = null!;
+
+ [JsonPropertyName("conversation_id")]
+ public string ConversationId { get; set; } = null!;
+
+ [JsonPropertyName("execution_result")]
+ public string ExecutionResult { get; set; } = null!;
+
+ [JsonPropertyName("created_time")]
+ public DateTime CreatedTime { get; set; } = DateTime.UtcNow;
+
+ public override string ToString()
+ {
+ return $"{Title}: {Description} [AgentId: {AgentId}, UserId: {UserId}]";
+ }
+}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Crontab/Models/CrontabItemFilter.cs b/src/Infrastructure/BotSharp.Abstraction/Crontab/Models/CrontabItemFilter.cs
new file mode 100644
index 00000000..7a949dc2
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/Crontab/Models/CrontabItemFilter.cs
@@ -0,0 +1,23 @@
+namespace BotSharp.Abstraction.Crontab.Models;
+
+public class CrontabItemFilter : Pagination
+{
+ [JsonPropertyName("user_ids")]
+ public IEnumerable? UserIds { get; set; }
+
+ [JsonPropertyName("agent_ids")]
+ public IEnumerable? AgentIds { get; set; }
+
+ [JsonPropertyName("conversation_ids")]
+ public IEnumerable? ConversationIds { get; set; }
+
+ public CrontabItemFilter()
+ {
+
+ }
+
+ public static CrontabItemFilter Empty()
+ {
+ return new CrontabItemFilter();
+ }
+}
diff --git a/src/Infrastructure/BotSharp.Core.Crontab/Models/ScheduleTaskArgs.cs b/src/Infrastructure/BotSharp.Abstraction/Crontab/Models/ScheduleTaskArgs.cs
similarity index 63%
rename from src/Infrastructure/BotSharp.Core.Crontab/Models/ScheduleTaskArgs.cs
rename to src/Infrastructure/BotSharp.Abstraction/Crontab/Models/ScheduleTaskArgs.cs
index af1bb23f..df11160a 100644
--- a/src/Infrastructure/BotSharp.Core.Crontab/Models/ScheduleTaskArgs.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Crontab/Models/ScheduleTaskArgs.cs
@@ -1,18 +1,25 @@
-using System.Text.Json.Serialization;
-
-namespace BotSharp.Core.Crontab.Models;
+namespace BotSharp.Abstraction.Crontab.Models;
public class ScheduleTaskArgs
{
[JsonPropertyName("cron_expression")]
public string Cron { get; set; } = null!;
- [JsonPropertyName("topic")]
- public string Topic { get; set; } = null!;
+ [JsonPropertyName("title")]
+ public string Title { get; set; } = null!;
[JsonPropertyName("description")]
public string Description { get; set; } = null!;
+ [JsonPropertyName("to_do_list")]
+ public ScheduleTaskItemArgs[] Tasks { get; set; } = [];
+}
+
+public class ScheduleTaskItemArgs
+{
+ [JsonPropertyName("topic")]
+ public string Topic { get; set; } = null!;
+
[JsonPropertyName("script")]
public string Script { get; set; } = null!;
diff --git a/src/Infrastructure/BotSharp.Abstraction/Planning/ITaskPlanner.cs b/src/Infrastructure/BotSharp.Abstraction/Planning/ITaskPlanner.cs
index 67f30fb1..2bd8da83 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Planning/ITaskPlanner.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Planning/ITaskPlanner.cs
@@ -8,6 +8,7 @@ namespace BotSharp.Abstraction.Planning;
///
public interface ITaskPlanner
{
+ string Name => "Unamed Task Planner";
Task GetNextInstruction(Agent router, string messageId, List dialogs);
Task AgentExecuting(Agent router, FunctionCallFromLlm inst, RoleDialogModel message, List dialogs);
Task AgentExecuted(Agent router, FunctionCallFromLlm inst, RoleDialogModel message, List dialogs);
diff --git a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs
index 037e0037..61982cc4 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs
@@ -145,4 +145,10 @@ public interface IBotSharpRepository : IHaveServiceProvider
bool DeleteKnolwedgeBaseFileMeta(string collectionName, string vectorStoreProvider, Guid? fileId = null);
PagedItems GetKnowledgeBaseFileMeta(string collectionName, string vectorStoreProvider, KnowledgeFileFilter filter);
#endregion
+
+ #region Crontab
+ bool UpsertCrontabItem(CrontabItem cron) => throw new NotImplementedException();
+ bool DeleteCrontabItem(string conversationId) => throw new NotImplementedException();
+ PagedItems GetCrontabItems(CrontabItemFilter filter) => throw new NotImplementedException();
+ #endregion
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutableAgent.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutableAgent.cs
index 14fd6826..861f3f2f 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutableAgent.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutableAgent.cs
@@ -13,6 +13,9 @@ public class RoutableAgent
[JsonPropertyName("description")]
public string Description { get; set; } = string.Empty;
+ [JsonPropertyName("type")]
+ public string Type { get; set; } = AgentType.Task;
+
[JsonPropertyName("profiles")]
public List Profiles { get; set; }
= new List();
diff --git a/src/Infrastructure/BotSharp.Abstraction/SideCar/IConversationSideCar.cs b/src/Infrastructure/BotSharp.Abstraction/SideCar/IConversationSideCar.cs
index 9a1316fb..84b65573 100644
--- a/src/Infrastructure/BotSharp.Abstraction/SideCar/IConversationSideCar.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/SideCar/IConversationSideCar.cs
@@ -9,5 +9,6 @@ public interface IConversationSideCar
List GetConversationDialogs(string conversationId);
void UpdateConversationBreakpoint(string conversationId, ConversationBreakpoint breakpoint);
ConversationBreakpoint? GetConversationBreakpoint(string conversationId);
- Task SendMessage(string agentId, string text, PostbackMessageModel? postback = null, List? states = null);
+ Task SendMessage(string agentId, string text,
+ PostbackMessageModel? postback = null, List? states = null, List? dialogs = null);
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Using.cs b/src/Infrastructure/BotSharp.Abstraction/Using.cs
index 9f35c1c8..592803c2 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Using.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Using.cs
@@ -17,4 +17,5 @@ global using BotSharp.Abstraction.Translation.Attributes;
global using BotSharp.Abstraction.Messaging.Enums;
global using BotSharp.Abstraction.Files.Models;
global using BotSharp.Abstraction.Files.Enums;
-global using BotSharp.Abstraction.Knowledges.Models;
\ No newline at end of file
+global using BotSharp.Abstraction.Knowledges.Models;
+global using BotSharp.Abstraction.Crontab.Models;
\ No newline at end of file
diff --git a/src/Infrastructure/BotSharp.Core.Crontab/Abstraction/ICrontabHook.cs b/src/Infrastructure/BotSharp.Core.Crontab/Abstraction/ICrontabHook.cs
index 49ffe54c..1738ef5e 100644
--- a/src/Infrastructure/BotSharp.Core.Crontab/Abstraction/ICrontabHook.cs
+++ b/src/Infrastructure/BotSharp.Core.Crontab/Abstraction/ICrontabHook.cs
@@ -1,5 +1,3 @@
-using BotSharp.Core.Crontab.Models;
-
namespace BotSharp.Core.Crontab.Abstraction;
public interface ICrontabHook
diff --git a/src/Infrastructure/BotSharp.Core.Crontab/Abstraction/ICrontabService.cs b/src/Infrastructure/BotSharp.Core.Crontab/Abstraction/ICrontabService.cs
index 6a18018d..39c13779 100644
--- a/src/Infrastructure/BotSharp.Core.Crontab/Abstraction/ICrontabService.cs
+++ b/src/Infrastructure/BotSharp.Core.Crontab/Abstraction/ICrontabService.cs
@@ -1,5 +1,3 @@
-using BotSharp.Core.Crontab.Models;
-
namespace BotSharp.Core.Crontab.Abstraction;
public interface ICrontabService
diff --git a/src/Infrastructure/BotSharp.Core.Crontab/BotSharp.Core.Crontab.csproj b/src/Infrastructure/BotSharp.Core.Crontab/BotSharp.Core.Crontab.csproj
index 0740b6fa..cc072fe6 100644
--- a/src/Infrastructure/BotSharp.Core.Crontab/BotSharp.Core.Crontab.csproj
+++ b/src/Infrastructure/BotSharp.Core.Crontab/BotSharp.Core.Crontab.csproj
@@ -21,7 +21,6 @@
-
@@ -29,4 +28,8 @@
+
+
+
+
diff --git a/src/Infrastructure/BotSharp.Core.Crontab/Functions/ScheduleTaskFn.cs b/src/Infrastructure/BotSharp.Core.Crontab/Functions/ScheduleTaskFn.cs
index 70d3b410..87a1bad6 100644
--- a/src/Infrastructure/BotSharp.Core.Crontab/Functions/ScheduleTaskFn.cs
+++ b/src/Infrastructure/BotSharp.Core.Crontab/Functions/ScheduleTaskFn.cs
@@ -1,3 +1,4 @@
+using BotSharp.Abstraction.Repositories;
using BotSharp.Abstraction.Routing;
using BotSharp.Abstraction.Users;
using BotSharp.Core.Crontab.Hooks;
@@ -22,16 +23,18 @@ public class ScheduleTaskFn : IFunctionCallback
var user = _services.GetRequiredService();
var crontabItem = new CrontabItem
{
- Topic = args.Topic,
+ Title = args.Title,
Description = args.Description,
Cron = args.Cron,
- Script = args.Script,
- Language = args.Language,
UserId = user.Id,
AgentId = routing.EntryAgentId,
- ConversationId = routing.ConversationId
+ ConversationId = routing.ConversationId,
+ Tasks = args.Tasks,
};
+ var db = _services.GetRequiredService();
+ // var ret = db.UpsertCrontabItem(crontabItem);
+
return true;
}
}
diff --git a/src/Infrastructure/BotSharp.Core.Crontab/Models/CrontabItem.cs b/src/Infrastructure/BotSharp.Core.Crontab/Models/CrontabItem.cs
deleted file mode 100644
index c3fab2e8..00000000
--- a/src/Infrastructure/BotSharp.Core.Crontab/Models/CrontabItem.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-namespace BotSharp.Core.Crontab.Models;
-
-public class CrontabItem : ScheduleTaskArgs
-{
- public string UserId { get; set; } = null!;
- public string AgentId { get; set; } = null!;
- public string ConversationId { get; set; } = null!;
- public string ExecutionResult { get; set; } = null!;
-
- public override string ToString()
- {
- return $"{Topic}: {Description} [AgentId: {AgentId}, UserId: {UserId}]";
- }
-}
diff --git a/src/Infrastructure/BotSharp.Core.Crontab/Services/CrontabService.cs b/src/Infrastructure/BotSharp.Core.Crontab/Services/CrontabService.cs
index d09f9260..e5e68cc0 100644
--- a/src/Infrastructure/BotSharp.Core.Crontab/Services/CrontabService.cs
+++ b/src/Infrastructure/BotSharp.Core.Crontab/Services/CrontabService.cs
@@ -14,29 +14,7 @@
limitations under the License.
******************************************************************************/
-using BotSharp.Abstraction.Agents.Enums;
-using BotSharp.Abstraction.Conversations;
-using BotSharp.Abstraction.Routing;
-using BotSharp.Core.Crontab.Models;
-using BotSharp.Core.Infrastructures;
-
-
-/*****************************************************************************
- Copyright 2024 Written by Haiping Chen. All Rights Reserved.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-******************************************************************************/
-
+using BotSharp.Abstraction.Repositories;
using Microsoft.Extensions.Logging;
namespace BotSharp.Core.Crontab.Services;
@@ -58,24 +36,9 @@ public class CrontabService : ICrontabService
public async Task> GetCrontable()
{
- var convService = _services.GetRequiredService();
- var conv = await convService.GetConversation("73a9ee27-d597-4739-958f-3bd79760ac8e");
- if (conv == null || !conv.States.ContainsKey("cron_expression"))
- {
- return [];
- }
-
- return
- [
- new CrontabItem
- {
- Topic = conv.States["topic"],
- Cron = conv.States["cron_expression"],
- Description = conv.States["description"],
- Script = conv.States["script"],
- Language = conv.States["language"]
- }
- ];
+ var repo = _services.GetRequiredService();
+ var crontable = repo.GetCrontabItems(CrontabItemFilter.Empty());
+ return crontable.Items.ToList();
}
public async Task ScheduledTimeArrived(CrontabItem item)
diff --git a/src/Infrastructure/BotSharp.Core.Crontab/Services/CrontabWatcher.cs b/src/Infrastructure/BotSharp.Core.Crontab/Services/CrontabWatcher.cs
index f29bd069..a7db1220 100644
--- a/src/Infrastructure/BotSharp.Core.Crontab/Services/CrontabWatcher.cs
+++ b/src/Infrastructure/BotSharp.Core.Crontab/Services/CrontabWatcher.cs
@@ -46,24 +46,32 @@ public class CrontabWatcher : BackgroundService
var crons = await cron.GetCrontable();
foreach (var item in crons)
{
- var schedule = CrontabSchedule.Parse(item.Cron, new CrontabSchedule.ParseOptions
+ try
{
- IncludingSeconds = true // Ensure you account for seconds
- });
+ var schedule = CrontabSchedule.Parse(item.Cron, new CrontabSchedule.ParseOptions
+ {
+ IncludingSeconds = true // Ensure you account for seconds
+ });
- // Get the current time
- var currentTime = DateTime.UtcNow;
+ // Get the current time
+ var currentTime = DateTime.UtcNow;
- // Get the next occurrence from the schedule
- var nextOccurrence = schedule.GetNextOccurrence(currentTime.AddSeconds(-1));
+ // Get the next occurrence from the schedule
+ var nextOccurrence = schedule.GetNextOccurrence(currentTime.AddSeconds(-1));
- // Check if the current time matches the schedule
- bool matches = currentTime >= nextOccurrence && currentTime < nextOccurrence.AddSeconds(1);
+ // Check if the current time matches the schedule
+ bool matches = currentTime >= nextOccurrence && currentTime < nextOccurrence.AddSeconds(1);
- if (matches)
+ if (matches)
+ {
+ _logger.LogDebug($"The current time matches the cron expression {item}");
+ cron.ScheduledTimeArrived(item);
+ }
+ }
+ catch (Exception ex)
{
- _logger.LogDebug($"The current time matches the cron expression {item}");
- cron.ScheduledTimeArrived(item);
+ _logger.LogWarning($"Error when running cron task ({item.ConversationId}, {item.Title}, {item.Cron}): {ex.Message}\r\n{ex.InnerException}");
+ continue;
}
}
}
diff --git a/src/Infrastructure/BotSharp.Core.Crontab/Using.cs b/src/Infrastructure/BotSharp.Core.Crontab/Using.cs
index 42563238..0420faf7 100644
--- a/src/Infrastructure/BotSharp.Core.Crontab/Using.cs
+++ b/src/Infrastructure/BotSharp.Core.Crontab/Using.cs
@@ -4,10 +4,10 @@ global using Microsoft.Extensions.Configuration;
global using Microsoft.Extensions.DependencyInjection;
global using BotSharp.Abstraction.Agents.Enums;
+global using BotSharp.Abstraction.Crontab.Models;
global using BotSharp.Abstraction.Agents;
global using BotSharp.Abstraction.Plugins;
global using BotSharp.Abstraction.Conversations.Models;
global using BotSharp.Abstraction.Functions;
global using BotSharp.Core.Crontab.Services;
-global using BotSharp.Core.Crontab.Abstraction;
-global using BotSharp.Core.Crontab.Models;
+global using BotSharp.Core.Crontab.Abstraction;
\ No newline at end of file
diff --git a/src/Infrastructure/BotSharp.Core.Crontab/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/util-crontab-schedule_task.json b/src/Infrastructure/BotSharp.Core.Crontab/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/util-crontab-schedule_task.json
index 4f866ce1..320f4d71 100644
--- a/src/Infrastructure/BotSharp.Core.Crontab/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/util-crontab-schedule_task.json
+++ b/src/Infrastructure/BotSharp.Core.Crontab/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/util-crontab-schedule_task.json
@@ -8,24 +8,37 @@
"type": "string",
"description": "cron expression include seconds"
},
- "topic": {
+ "title": {
"type": "string",
- "description": "task topic in 1-3 keywords related to business entities"
+ "description": "task short title"
},
"description": {
"type": "string",
- "description": "task description without cron infromation, should include all key business entities"
+ "description": "the task summary"
},
- "script": {
- "type": "string",
- "description": "task related script, commands or provided function with parameters"
- },
- "language": {
- "type": "string",
- "enum": ["sql", "function"],
- "description": "script programming language"
+ "to_do_list": {
+ "type": "array",
+ "description": "task to do list, should include all key business entities",
+ "items": {
+ "type": "object",
+ "properties": {
+ "topic": {
+ "type": "string",
+ "description": "task topic in 1-3 keywords related to the step"
+ },
+ "script": {
+ "type": "string",
+ "description": "task related script, function with parameters or plain text"
+ },
+ "language": {
+ "type": "string",
+ "enum": [ "function", "sql", "python", "text" ],
+ "description": "programming language script, function or plain text"
+ }
+ }
+ }
}
},
- "required": [ "cron_expression", "topic", "description", "script", "language" ]
+ "required": [ "cron_expression", "title", "description", "to_do_list" ]
}
}
\ No newline at end of file
diff --git a/src/Infrastructure/BotSharp.Core.SideCar/Services/BotSharpConversationSideCar.cs b/src/Infrastructure/BotSharp.Core.SideCar/Services/BotSharpConversationSideCar.cs
index 4ddc3a43..59087311 100644
--- a/src/Infrastructure/BotSharp.Core.SideCar/Services/BotSharpConversationSideCar.cs
+++ b/src/Infrastructure/BotSharp.Core.SideCar/Services/BotSharpConversationSideCar.cs
@@ -80,9 +80,9 @@ public class BotSharpConversationSideCar : IConversationSideCar
}
public async Task SendMessage(string agentId, string text,
- PostbackMessageModel? postback = null, List? states = null)
+ PostbackMessageModel? postback = null, List? states = null, List? dialogs = null)
{
- BeforeExecute();
+ BeforeExecute(dialogs);
var response = await InnerExecute(agentId, text, postback, states);
AfterExecute();
return response;
@@ -114,7 +114,7 @@ public class BotSharpConversationSideCar : IConversationSideCar
return response;
}
- private void BeforeExecute()
+ private void BeforeExecute(List? dialogs)
{
enabled = true;
var state = _services.GetRequiredService();
@@ -123,8 +123,8 @@ public class BotSharpConversationSideCar : IConversationSideCar
var node = new ConversationContext
{
State = state.GetCurrentState(),
- Dialogs = new(),
- Breakpoints = new(),
+ Dialogs = dialogs ?? [],
+ Breakpoints = [],
RecursiveCounter = routing.Context.GetRecursiveCounter(),
RoutingStack = routing.Context.GetAgentStack()
};
diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Crontab.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Crontab.cs
new file mode 100644
index 00000000..5d3eb865
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Crontab.cs
@@ -0,0 +1,117 @@
+using System.IO;
+
+namespace BotSharp.Core.Repository;
+
+public partial class FileRepository
+{
+ public bool UpsertCrontabItem(CrontabItem cron)
+ {
+ if (cron == null || string.IsNullOrWhiteSpace(cron.ConversationId))
+ {
+ return false;
+ }
+
+ try
+ {
+ var baseDir = Path.Combine(_dbSettings.FileRepository, _conversationSettings.DataDir, cron.ConversationId);
+ if (!Directory.Exists(baseDir))
+ {
+ return false;
+ }
+
+ var cronFile = Path.Combine(baseDir, CRON_FILE);
+ var json = JsonSerializer.Serialize(cron, _options);
+ File.WriteAllText(cronFile, json);
+ return true;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError($"Error when saving crontab item: {ex.Message}\r\n{ex.InnerException}");
+ return false;
+ }
+ }
+
+ public bool DeleteCrontabItem(string conversationId)
+ {
+ if (string.IsNullOrWhiteSpace(conversationId))
+ {
+ return false;
+ }
+
+ try
+ {
+ var baseDir = Path.Combine(_dbSettings.FileRepository, _conversationSettings.DataDir, conversationId);
+ if (!Directory.Exists(baseDir))
+ {
+ return false;
+ }
+
+ var cronFile = Path.Combine(baseDir, CRON_FILE);
+ if (!File.Exists(cronFile))
+ {
+ return false;
+ }
+
+ File.Delete(cronFile);
+ return true;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError($"Error when deleting crontab item (${conversationId}): {ex.Message}\r\n{ex.InnerException}");
+ return false;
+ }
+ }
+
+
+ public PagedItems GetCrontabItems(CrontabItemFilter filter)
+ {
+
+ if (filter == null)
+ {
+ filter = CrontabItemFilter.Empty();
+ }
+
+ var records = new List();
+ var baseDir = Path.Combine(_dbSettings.FileRepository, _conversationSettings.DataDir);
+
+ if (!Directory.Exists(baseDir))
+ {
+ Directory.CreateDirectory(baseDir);
+ }
+
+ var totalDirs = Directory.GetDirectories(baseDir);
+ foreach (var d in totalDirs)
+ {
+ var file = Path.Combine(d, CRON_FILE);
+ if (!File.Exists(file)) continue;
+
+ var json = File.ReadAllText(file);
+ var record = JsonSerializer.Deserialize(json, _options);
+ if (record == null) continue;
+
+ var matched = true;
+ if (filter?.AgentIds != null)
+ {
+ matched = matched && filter.AgentIds.Contains(record.AgentId);
+ }
+ if (filter?.ConversationIds != null)
+ {
+ matched = matched && filter.ConversationIds.Contains(record.ConversationId);
+ }
+ if (filter?.UserIds != null)
+ {
+ matched = matched && filter.UserIds.Contains(record.UserId);
+ }
+
+ if (!matched) continue;
+
+ records.Add(record);
+ }
+
+ return new PagedItems
+ {
+ Items = records.OrderByDescending(x => x.CreatedTime).Skip(filter.Offset).Take(filter.Size),
+ Count = records.Count(),
+ };
+ }
+}
diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.cs
index 57fbcb91..6a718d65 100644
--- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.cs
+++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.cs
@@ -55,6 +55,8 @@ public partial class FileRepository : IBotSharpRepository
private const string PLUGIN_CONFIG_FILE = "config.json";
private const string STATS_FILE = "stats.json";
+ private const string CRON_FILE = "cron.json";
+
public FileRepository(
IServiceProvider services,
BotSharpDatabaseSettings dbSettings,
@@ -88,7 +90,6 @@ public partial class FileRepository : IBotSharpRepository
private List _agents = new List();
private List _roleAgents = new List();
private List _userAgents = new List();
- private List _conversations = new List();
private PluginConfig? _pluginConfig = null;
private IQueryable Roles
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Hooks/RoutingAgentHook.cs b/src/Infrastructure/BotSharp.Core/Routing/Hooks/RoutingAgentHook.cs
index a847f078..f83afedf 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/Hooks/RoutingAgentHook.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/Hooks/RoutingAgentHook.cs
@@ -1,4 +1,3 @@
-using BotSharp.Abstraction.Functions;
using BotSharp.Abstraction.Routing.Enums;
using BotSharp.Abstraction.Routing.Settings;
@@ -26,6 +25,14 @@ public class RoutingAgentHook : AgentHookBase
var routing = _services.GetRequiredService();
var agents = routing.GetRoutableAgents(_agent.Profiles);
+ // 过滤 Planner
+ var planningRule = _agent.RoutingRules.FirstOrDefault(x => x.Type == "planner");
+ if (planningRule != null)
+ {
+ var planners = agents.Where(x => x.Type == AgentType.Planning && x.Name != planningRule.Field).ToArray();
+ agents = agents.Except(planners).ToArray();
+ }
+
// Postprocess agent required fields, remove it if the states exists
var states = _services.GetRequiredService();
foreach (var agent in agents)
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/HFReasoner.cs b/src/Infrastructure/BotSharp.Core/Routing/Reasoning/HFReasoner.cs
index 0c825a05..e7d9b49e 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/HFReasoner.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/Reasoning/HFReasoner.cs
@@ -24,6 +24,7 @@ namespace BotSharp.Core.Routing.Reasoning;
///
public class HFReasoner : IRoutingReasoner
{
+ public string Name => "Human-Feedback Reasoner";
private readonly IServiceProvider _services;
private readonly ILogger _logger;
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/OneStepForwardReasoner.cs b/src/Infrastructure/BotSharp.Core/Routing/Reasoning/OneStepForwardReasoner.cs
index eb58d3e3..7e6d2624 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/OneStepForwardReasoner.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/Reasoning/OneStepForwardReasoner.cs
@@ -29,7 +29,7 @@ namespace BotSharp.Core.Routing.Reasoning;
///
public class OneStepForwardReasoner : IRoutingReasoner
{
- public string Name => "one-step-forward";
+ public string Name => "One-Step-Forward-Reasoner";
private readonly IServiceProvider _services;
private readonly ILogger _logger;
diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingPlugin.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingPlugin.cs
index f5c2a9d6..c5317ba4 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/RoutingPlugin.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingPlugin.cs
@@ -35,8 +35,7 @@ public class RoutingPlugin : IBotSharpPlugin
services.AddScoped();
services.AddScoped();
- services.AddScoped();
-
+
services.AddScoped();
}
}
diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InstructLoop.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InstructLoop.cs
index 18f330a3..b7dc6cc3 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InstructLoop.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InstructLoop.cs
@@ -102,7 +102,7 @@ public partial class RoutingService
return _services.GetServices().First(x => x.Name == "Naive Reasoner");
}
- var reasoner = _services.GetServices().FirstOrDefault(x => x.GetType().Name.EndsWith(rule.Field));
+ var reasoner = _services.GetServices().FirstOrDefault(x => x.Name == rule.Field);
if (reasoner == null)
{
diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs
index d3eb2b1c..ef32f018 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs
@@ -82,11 +82,10 @@ public partial class RoutingService : IRoutingService
var filter = new AgentFilter
{
- Disabled = false,
- Type = AgentType.Task
+ Disabled = false
};
var agents = db.GetAgents(filter);
- var records = agents.SelectMany(x =>
+ var records = agents.Where(x => x.Type == AgentType.Task || x.Type == AgentType.Planning).SelectMany(x =>
{
x.RoutingRules.ForEach(r =>
{
@@ -108,16 +107,16 @@ public partial class RoutingService : IRoutingService
var filter = new AgentFilter
{
- Disabled = false,
- Type = AgentType.Task
+ Disabled = false
};
var agents = db.GetAgents(filter);
- var routableAgents = agents.Select(x => new RoutableAgent
+ var routableAgents = agents.Where(x => x.Type == AgentType.Task || x.Type == AgentType.Planning).Select(x => new RoutableAgent
{
AgentId = x.Id,
Description = x.Description,
Name = x.Name,
+ Type = x.Type,
Profiles = x.Profiles,
RequiredFields = x.RoutingRules
.Where(p => p.Required)
diff --git a/src/Infrastructure/BotSharp.Core/Using.cs b/src/Infrastructure/BotSharp.Core/Using.cs
index f68cba9b..4a74f1d0 100644
--- a/src/Infrastructure/BotSharp.Core/Using.cs
+++ b/src/Infrastructure/BotSharp.Core/Using.cs
@@ -14,7 +14,7 @@ global using BotSharp.Abstraction.Routing;
global using BotSharp.Abstraction.Plugins;
global using BotSharp.Abstraction.Agents;
global using BotSharp.Abstraction.Conversations;
-global using BotSharp.Abstraction.Knowledges;
+global using BotSharp.Abstraction.Crontab.Models;
global using BotSharp.Abstraction.Users;
global using BotSharp.Abstraction.Roles;
global using BotSharp.Abstraction.Roles.Models;
diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/agent.json b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/agent.json
index 0a82ae0a..ae99df17 100644
--- a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/agent.json
+++ b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/agent.json
@@ -12,7 +12,11 @@
"routingRules": [
{
"type": "reasoner",
- "field": "HFReasoner"
+ "field": "One-Step-Forward-Reasoner"
+ },
+ {
+ "type": "planner",
+ "field": "Sequential-Planner"
}
]
}
\ No newline at end of file
diff --git a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubCrontabHook.cs b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubCrontabHook.cs
index 4b475e73..4f7ef3d2 100644
--- a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubCrontabHook.cs
+++ b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubCrontabHook.cs
@@ -1,5 +1,5 @@
+using BotSharp.Abstraction.Crontab.Models;
using BotSharp.Core.Crontab.Abstraction;
-using BotSharp.Core.Crontab.Models;
using Microsoft.AspNetCore.SignalR;
namespace BotSharp.Plugin.ChatHub.Hooks;
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/CrontabItemDocument.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/CrontabItemDocument.cs
new file mode 100644
index 00000000..10e633d7
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/CrontabItemDocument.cs
@@ -0,0 +1,48 @@
+using BotSharp.Abstraction.Crontab.Models;
+
+namespace BotSharp.Plugin.MongoStorage.Collections;
+
+public class CrontabItemDocument : MongoBase
+{
+ public string UserId { get; set; }
+ public string AgentId { get; set; }
+ public string ConversationId { get; set; }
+ public string ExecutionResult { get; set; }
+ public string Cron { get; set; }
+ public string Title { get; set; }
+ public string Description { get; set; }
+ public IEnumerable Tasks { get; set; } = [];
+ public DateTime CreatedTime { get; set; } = DateTime.UtcNow;
+
+ public static CrontabItem ToDomainModel(CrontabItemDocument item)
+ {
+ return new CrontabItem
+ {
+ UserId = item.UserId,
+ AgentId = item.AgentId,
+ ConversationId = item.ConversationId,
+ ExecutionResult = item.ExecutionResult,
+ Cron = item.Cron,
+ Title = item.Title,
+ Description = item.Description,
+ Tasks = item.Tasks?.Select(x => CronTaskMongoElement.ToDomainElement(x))?.ToArray() ?? [],
+ CreatedTime = item.CreatedTime
+ };
+ }
+
+ public static CrontabItemDocument ToMongoModel(CrontabItem item)
+ {
+ return new CrontabItemDocument
+ {
+ UserId = item.UserId,
+ AgentId = item.AgentId,
+ ConversationId = item.ConversationId,
+ ExecutionResult = item.ExecutionResult,
+ Cron = item.Cron,
+ Title = item.Title,
+ Description = item.Description,
+ Tasks = item.Tasks?.Select(x => CronTaskMongoElement.ToMongoElement(x))?.ToList() ?? [],
+ CreatedTime = item.CreatedTime
+ };
+ }
+}
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Models/CronTaskMongoElement.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/CronTaskMongoElement.cs
new file mode 100644
index 00000000..099286b8
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/CronTaskMongoElement.cs
@@ -0,0 +1,30 @@
+using BotSharp.Abstraction.Crontab.Models;
+
+namespace BotSharp.Plugin.MongoStorage.Models;
+
+public class CronTaskMongoElement
+{
+ public string Topic { get; set; }
+ public string Script { get; set; }
+ public string Language { get; set; }
+
+ public static CronTaskMongoElement ToMongoElement(ScheduleTaskItemArgs model)
+ {
+ return new CronTaskMongoElement
+ {
+ Topic = model.Topic,
+ Script = model.Script,
+ Language = model.Language
+ };
+ }
+
+ public static ScheduleTaskItemArgs ToDomainElement(CronTaskMongoElement model)
+ {
+ return new ScheduleTaskItemArgs
+ {
+ Topic = model.Topic,
+ Script = model.Script,
+ Language = model.Language
+ };
+ }
+}
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/MongoDbContext.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/MongoDbContext.cs
index b91c35fe..89eb18ad 100644
--- a/src/Plugins/BotSharp.Plugin.MongoStorage/MongoDbContext.cs
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/MongoDbContext.cs
@@ -165,4 +165,7 @@ public class MongoDbContext
public IMongoCollection RoleAgents
=> Database.GetCollection($"{_collectionPrefix}_RoleAgents");
+
+ public IMongoCollection CrontabItems
+ => Database.GetCollection($"{_collectionPrefix}_CronTabItems");
}
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Conversation.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Conversation.cs
index ccbfc1af..cdd78ae2 100644
--- a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Conversation.cs
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Conversation.cs
@@ -56,6 +56,7 @@ public partial class MongoRepository
var filterPromptLog = Builders.Filter.In(x => x.ConversationId, conversationIds);
var filterContentLog = Builders.Filter.In(x => x.ConversationId, conversationIds);
var filterStateLog = Builders.Filter.In(x => x.ConversationId, conversationIds);
+ var conbTabItems = Builders.Filter.In(x => x.ConversationId, conversationIds);
var exeLogDeleted = _dc.ExectionLogs.DeleteMany(filterExeLog);
var promptLogDeleted = _dc.LlmCompletionLogs.DeleteMany(filterPromptLog);
@@ -63,11 +64,13 @@ public partial class MongoRepository
var stateLogDeleted = _dc.StateLogs.DeleteMany(filterStateLog);
var statesDeleted = _dc.ConversationStates.DeleteMany(filterSates);
var dialogDeleted = _dc.ConversationDialogs.DeleteMany(filterDialog);
+ var cronDeleted = _dc.CrontabItems.DeleteMany(conbTabItems);
var convDeleted = _dc.Conversations.DeleteMany(filterConv);
return convDeleted.DeletedCount > 0 || dialogDeleted.DeletedCount > 0 || statesDeleted.DeletedCount > 0
|| exeLogDeleted.DeletedCount > 0 || promptLogDeleted.DeletedCount > 0
- || contentLogDeleted.DeletedCount > 0 || stateLogDeleted.DeletedCount > 0;
+ || contentLogDeleted.DeletedCount > 0 || stateLogDeleted.DeletedCount > 0
+ || convDeleted.DeletedCount > 0;
}
[SideCar]
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Crontab.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Crontab.cs
new file mode 100644
index 00000000..a40fc827
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Crontab.cs
@@ -0,0 +1,87 @@
+using BotSharp.Abstraction.Crontab.Models;
+using Microsoft.Extensions.Logging;
+
+namespace BotSharp.Plugin.MongoStorage.Repository;
+
+public partial class MongoRepository
+{
+ public bool UpsertCrontabItem(CrontabItem item)
+ {
+ if (item == null || string.IsNullOrWhiteSpace(item.ConversationId))
+ {
+ return false;
+ }
+
+ try
+ {
+ var cronDoc = CrontabItemDocument.ToMongoModel(item);
+ cronDoc.Id = Guid.NewGuid().ToString();
+
+ var filter = Builders.Filter.Eq(x => x.ConversationId, item.ConversationId);
+ var result = _dc.CrontabItems.ReplaceOne(filter, cronDoc, new ReplaceOptions
+ {
+ IsUpsert = true
+ });
+ return true;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError($"Error when saving crontab item: {ex.Message}\r\n{ex.InnerException}");
+ return false;
+ }
+ }
+
+
+ public bool DeleteCrontabItem(string conversationId)
+ {
+ if (string.IsNullOrWhiteSpace(conversationId))
+ {
+ return false;
+ }
+
+ var filter = Builders.Filter.Eq(x => x.ConversationId, conversationId);
+ var result = _dc.CrontabItems.DeleteMany(filter);
+ return result.DeletedCount > 0;
+ }
+
+
+ public PagedItems GetCrontabItems(CrontabItemFilter filter)
+ {
+ if (filter == null)
+ {
+ filter = CrontabItemFilter.Empty();
+ }
+
+ var cronBuilder = Builders.Filter;
+ var cronFilters = new List>() { cronBuilder.Empty };
+
+ // Filter cron
+ if (filter?.AgentIds != null)
+ {
+ cronFilters.Add(cronBuilder.In(x => x.AgentId, filter.AgentIds));
+ }
+ if (filter?.ConversationIds != null)
+ {
+ cronFilters.Add(cronBuilder.In(x => x.ConversationId, filter.ConversationIds));
+ }
+ if (filter?.UserIds != null)
+ {
+ cronFilters.Add(cronBuilder.In(x => x.UserId, filter.UserIds));
+ }
+
+ // Sort and paginate
+ var filterDef = cronBuilder.And(cronFilters);
+ var sortDef = Builders.Sort.Descending(x => x.CreatedTime);
+
+ var cronDocs = _dc.CrontabItems.Find(filterDef).Sort(sortDef).Skip(filter.Offset).Limit(filter.Size).ToList();
+ var count = _dc.CrontabItems.CountDocuments(filterDef);
+
+ var crontabItems = cronDocs.Select(x => CrontabItemDocument.ToDomainModel(x)).ToList();
+
+ return new PagedItems
+ {
+ Items = crontabItems,
+ Count = (int)count
+ };
+ }
+}
diff --git a/src/Plugins/BotSharp.Plugin.Planner/BotSharp.Plugin.Planner.csproj b/src/Plugins/BotSharp.Plugin.Planner/BotSharp.Plugin.Planner.csproj
index fb183c77..f80327cc 100644
--- a/src/Plugins/BotSharp.Plugin.Planner/BotSharp.Plugin.Planner.csproj
+++ b/src/Plugins/BotSharp.Plugin.Planner/BotSharp.Plugin.Planner.csproj
@@ -19,6 +19,8 @@
+
+
@@ -52,6 +54,12 @@
PreserveNewest
+
+ PreserveNewest
+
+
+ PreserveNewest
+
PreserveNewest
diff --git a/src/Plugins/BotSharp.Plugin.Planner/Enums/PlannerAgentId.cs b/src/Plugins/BotSharp.Plugin.Planner/Enums/PlannerAgentId.cs
new file mode 100644
index 00000000..0776d7f1
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.Planner/Enums/PlannerAgentId.cs
@@ -0,0 +1,9 @@
+using Microsoft.AspNetCore.Http;
+
+namespace BotSharp.Plugin.Planner.Enums;
+
+public class PlannerAgentId
+{
+ public const string TwoStagePlanner = "282a7128-69a1-44b0-878c-a9159b88f3b9";
+ public const string SequentialPlanner = "3e75e818-a139-48a8-9e22-4662548c13a3";
+}
diff --git a/src/Plugins/BotSharp.Plugin.Planner/Functions/PrimaryStagePlanFn.cs b/src/Plugins/BotSharp.Plugin.Planner/Functions/PrimaryStagePlanFn.cs
index 84378158..fa1b7166 100644
--- a/src/Plugins/BotSharp.Plugin.Planner/Functions/PrimaryStagePlanFn.cs
+++ b/src/Plugins/BotSharp.Plugin.Planner/Functions/PrimaryStagePlanFn.cs
@@ -49,8 +49,8 @@ public class PrimaryStagePlanFn : IFunctionCallback
var prompt = await GetFirstStagePlanPrompt(message, task.Requirements, knowledges);
var plannerAgent = new Agent
{
- Id = BuiltInAgentId.Planner,
- Name = "FirstStagePlanner",
+ Id = message.CurrentAgentId,
+ Name = Name,
Instruction = prompt,
TemplateDict = new Dictionary(),
LlmConfig = currentAgent.LlmConfig
@@ -70,7 +70,7 @@ public class PrimaryStagePlanFn : IFunctionCallback
var render = _services.GetRequiredService();
var knowledgeHooks = _services.GetServices();
- var agent = await agentService.GetAgent(BuiltInAgentId.Planner);
+ var agent = await agentService.GetAgent(PlannerAgentId.TwoStagePlanner);
var template = agent.Templates.FirstOrDefault(x => x.Name == "two_stage.1st.plan")?.Content ?? string.Empty;
var responseFormat = JsonSerializer.Serialize(new FirstStagePlan{});
diff --git a/src/Plugins/BotSharp.Plugin.Planner/Functions/SecondaryStagePlanFn.cs b/src/Plugins/BotSharp.Plugin.Planner/Functions/SecondaryStagePlanFn.cs
index be780f51..5044139c 100644
--- a/src/Plugins/BotSharp.Plugin.Planner/Functions/SecondaryStagePlanFn.cs
+++ b/src/Plugins/BotSharp.Plugin.Planner/Functions/SecondaryStagePlanFn.cs
@@ -53,8 +53,8 @@ public class SecondaryStagePlanFn : IFunctionCallback
var plannerAgent = new Agent
{
- Id = BuiltInAgentId.Planner,
- Name = "SecondStagePlanner",
+ Id = PlannerAgentId.TwoStagePlanner,
+ Name = Name,
Instruction = prompt,
TemplateDict = new Dictionary(),
LlmConfig = currentAgent.LlmConfig
diff --git a/src/Plugins/BotSharp.Plugin.Planner/Functions/SummaryPlanFn.cs b/src/Plugins/BotSharp.Plugin.Planner/Functions/SummaryPlanFn.cs
index 2cd16ae9..cfc306f4 100644
--- a/src/Plugins/BotSharp.Plugin.Planner/Functions/SummaryPlanFn.cs
+++ b/src/Plugins/BotSharp.Plugin.Planner/Functions/SummaryPlanFn.cs
@@ -1,8 +1,5 @@
-using BotSharp.Abstraction.Planning;
using BotSharp.Plugin.Planner.TwoStaging;
using BotSharp.Plugin.Planner.TwoStaging.Models;
-using static System.Net.Mime.MediaTypeNames;
-using System.Text.RegularExpressions;
namespace BotSharp.Plugin.Planner.Functions;
@@ -62,8 +59,8 @@ public class SummaryPlanFn : IFunctionCallback
var plannerAgent = new Agent
{
- Id = BuiltInAgentId.Planner,
- Name = "SummaryPlanner",
+ Id = PlannerAgentId.TwoStagePlanner,
+ Name = Name,
Instruction = prompt,
LlmConfig = currentAgent.LlmConfig
};
@@ -93,7 +90,7 @@ public class SummaryPlanFn : IFunctionCallback
var render = _services.GetRequiredService();
var knowledgeHooks = _services.GetServices();
- var agent = await agentService.GetAgent(BuiltInAgentId.Planner);
+ var agent = await agentService.GetAgent(PlannerAgentId.TwoStagePlanner);
var template = agent.Templates.FirstOrDefault(x => x.Name == "two_stage.summarize")?.Content ?? string.Empty;
var additionalRequirements = new List();
diff --git a/src/Plugins/BotSharp.Plugin.Planner/Hooks/PlannerAgentHook.cs b/src/Plugins/BotSharp.Plugin.Planner/Hooks/PlannerAgentHook.cs
index d4bd1594..8c6f2635 100644
--- a/src/Plugins/BotSharp.Plugin.Planner/Hooks/PlannerAgentHook.cs
+++ b/src/Plugins/BotSharp.Plugin.Planner/Hooks/PlannerAgentHook.cs
@@ -2,7 +2,7 @@ namespace BotSharp.Plugin.Planner.Hooks;
public class PlannerAgentHook : AgentHookBase
{
- public override string SelfId => BuiltInAgentId.Planner;
+ public override string SelfId => PlannerAgentId.TwoStagePlanner;
public PlannerAgentHook(IServiceProvider services, AgentSettings settings)
: base(services, settings)
@@ -19,7 +19,7 @@ public class PlannerAgentHook : AgentHookBase
{
var k = hook.GetGlobalKnowledges(new RoleDialogModel(AgentRole.User, template)
{
- CurrentAgentId = BuiltInAgentId.Planner
+ CurrentAgentId = PlannerAgentId.TwoStagePlanner
}).Result;
Knowledges.AddRange(k);
}
diff --git a/src/Plugins/BotSharp.Plugin.Planner/PlannerPlugin.cs b/src/Plugins/BotSharp.Plugin.Planner/PlannerPlugin.cs
index 17d84c1c..b139cde2 100644
--- a/src/Plugins/BotSharp.Plugin.Planner/PlannerPlugin.cs
+++ b/src/Plugins/BotSharp.Plugin.Planner/PlannerPlugin.cs
@@ -1,4 +1,4 @@
-using BotSharp.Abstraction.Planning;
+using BotSharp.Plugin.Planner.Sequential;
using BotSharp.Plugin.Planner.TwoStaging;
namespace BotSharp.Plugin.Planner;
@@ -13,10 +13,15 @@ public class PlannerPlugin : IBotSharpPlugin
public string Description => "Provide AI with different planning approaches to improve AI's ability to solve complex problems.";
public string IconUrl => "https://e7.pngegg.com/pngimages/775/350/png-clipart-action-plan-computer-icons-plan-miscellaneous-text-thumbnail.png";
- public string[] AgentIds => [ BuiltInAgentId.Planner ];
+ public string[] AgentIds =>
+ [
+ PlannerAgentId.TwoStagePlanner,
+ PlannerAgentId.SequentialPlanner
+ ];
public void RegisterDI(IServiceCollection services, IConfiguration config)
{
+ services.AddScoped();
services.AddScoped();
services.AddScoped();
services.AddScoped();
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/SequentialReasoner.cs b/src/Plugins/BotSharp.Plugin.Planner/Sequential/SequentialPlanner.cs
similarity index 91%
rename from src/Infrastructure/BotSharp.Core/Routing/Reasoning/SequentialReasoner.cs
rename to src/Plugins/BotSharp.Plugin.Planner/Sequential/SequentialPlanner.cs
index 77f069fc..043c7380 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/SequentialReasoner.cs
+++ b/src/Plugins/BotSharp.Plugin.Planner/Sequential/SequentialPlanner.cs
@@ -14,26 +14,23 @@
limitations under the License.
******************************************************************************/
-using BotSharp.Abstraction.MLTasks;
-using BotSharp.Abstraction.Routing.Models;
-using BotSharp.Abstraction.Routing.Reasoning;
-using BotSharp.Abstraction.Templating;
-
-namespace BotSharp.Core.Routing.Reasoning;
+namespace BotSharp.Plugin.Planner.Sequential;
///
-/// Sequential tasks focused reasoning approach
+/// A Sequential Planner for a large language model (LLM) is a framework or methodology to execute some list tasks in a predefined order by the user,
+/// LLM can follow to produce an organized and coherent output.
+/// Sequential Planners are useful for tasks that involve multiple stages of reasoning, information retrieval, or interdependent subtasks.
///
-public class SequentialReasoner : IRoutingReasoner
+public class SequentialPlanner : ITaskPlanner
{
private readonly IServiceProvider _services;
private readonly ILogger _logger;
-
+ public string Name => "Sequential-Planner";
public bool HideDialogContext => true;
public int MaxLoopCount => 100;
private FunctionCallFromLlm _lastInst;
- public SequentialReasoner(IServiceProvider services, ILogger logger)
+ public SequentialPlanner(IServiceProvider services, ILogger logger)
{
_services = services;
_logger = logger;
@@ -91,7 +88,7 @@ public class SequentialReasoner : IRoutingReasoner
{
new RoleDialogModel(AgentRole.User, next)
{
- FunctionName = nameof(SequentialReasoner),
+ FunctionName = nameof(SequentialPlanner),
MessageId = messageId
}
};
@@ -158,7 +155,7 @@ public class SequentialReasoner : IRoutingReasoner
if (message.StopCompletion)
{
- context.Empty(reason: $"Agent queue is cleared by {nameof(SequentialReasoner)}");
+ context.Empty(reason: $"Agent queue is cleared by {nameof(SequentialPlanner)}");
return false;
}
@@ -204,7 +201,7 @@ public class SequentialReasoner : IRoutingReasoner
var response = await completion.GetChatCompletions(new Agent
{
Id = router.Id,
- Name = nameof(SequentialReasoner),
+ Name = nameof(SequentialPlanner),
Instruction = systemPrompt
}, dialogs);
diff --git a/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/TwoStageTaskPlanner.cs b/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/TwoStageTaskPlanner.cs
index 47b9c03a..6935bfbf 100644
--- a/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/TwoStageTaskPlanner.cs
+++ b/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/TwoStageTaskPlanner.cs
@@ -1,13 +1,38 @@
-using BotSharp.Abstraction.Infrastructures.Enums;
-using BotSharp.Abstraction.Planning;
-using BotSharp.Core.Routing.Reasoning;
+/*****************************************************************************
+ Copyright 2024 Written by Haiping Chen. All Rights Reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+******************************************************************************/
namespace BotSharp.Plugin.Planner.TwoStaging;
+///
+/// The Two-Stage Planner approach in large language models(LLMs) is an effective strategy to handle complex tasks by breaking them into manageable steps.
+/// This involves creating a high-level plan in the first stage and then drilling down into the details in the second stage.
+///
+/// Primary stage:
+/// The LLM generates a structured overview or roadmap for solving the problem.
+/// The focus here is on creating a broad and logically organized set of actions or categories that guide the overall process.
+///
+/// Secondary stage:
+/// For each step or component in the high-level plan, the LLM elaborates with specific actions, tools, or techniques.
+/// The focus shifts to operationalizing the roadmap.
+///
public partial class TwoStageTaskPlanner : ITaskPlanner
{
private readonly IServiceProvider _services;
private readonly ILogger _logger;
+ public string Name => "Two-Stage-Planner";
public int MaxLoopCount => 10;
public TwoStageTaskPlanner(IServiceProvider services, ILogger logger)
@@ -23,8 +48,8 @@ public partial class TwoStageTaskPlanner : ITaskPlanner
// chat completion
var completion = CompletionProvider.GetChatCompletion(_services,
- provider: router?.LlmConfig?.Provider,
- model: router?.LlmConfig?.Model);
+ provider: router?.LlmConfig?.Provider,
+ model: router?.LlmConfig?.Model);
// text completion
dialogs = new List
@@ -36,12 +61,10 @@ public partial class TwoStageTaskPlanner : ITaskPlanner
}
};
var response = await completion.GetChatCompletions(router, dialogs);
-
inst = response.Content.JsonContent();
// Fix LLM malformed response
ReasonerHelper.FixMalformedResponse(_services, inst);
-
return inst;
}
@@ -99,7 +122,7 @@ public partial class TwoStageTaskPlanner : ITaskPlanner
private async Task GetNextStepPrompt(Agent router)
{
var agentService = _services.GetRequiredService();
- var planner = await agentService.LoadAgent(BuiltInAgentId.Planner);
+ var planner = await agentService.LoadAgent(PlannerAgentId.TwoStagePlanner);
var template = planner.Templates.First(x => x.Name == "two_stage.next").Content;
var states = _services.GetRequiredService();
var render = _services.GetRequiredService();
diff --git a/src/Plugins/BotSharp.Plugin.Planner/Using.cs b/src/Plugins/BotSharp.Plugin.Planner/Using.cs
index 1e6737df..50db1596 100644
--- a/src/Plugins/BotSharp.Plugin.Planner/Using.cs
+++ b/src/Plugins/BotSharp.Plugin.Planner/Using.cs
@@ -18,19 +18,19 @@ global using BotSharp.Abstraction.Conversations;
global using BotSharp.Abstraction.Functions.Models;
global using BotSharp.Abstraction.Repositories;
global using BotSharp.Abstraction.Utilities;
-
global using BotSharp.Abstraction.Conversations.Models;
global using BotSharp.Abstraction.Functions;
global using BotSharp.Abstraction.Routing;
global using BotSharp.Abstraction.Templating;
-
global using BotSharp.Abstraction.Knowledges;
global using BotSharp.Abstraction.Knowledges.Settings;
-global using BotSharp.Abstraction.Knowledges.Enums;
-global using BotSharp.Abstraction.VectorStorage.Models;
-global using BotSharp.Abstraction.VectorStorage.Extensions;
+global using BotSharp.Abstraction.Infrastructures.Enums;
+global using BotSharp.Abstraction.Planning;
+global using BotSharp.Abstraction.MLTasks;
+global using BotSharp.Abstraction.Routing.Models;
+
+global using BotSharp.Core.Infrastructures;
+global using BotSharp.Core.Routing.Reasoning;
global using BotSharp.Plugin.Planner.Hooks;
global using BotSharp.Plugin.Planner.Enums;
-
-global using BotSharp.Core.Infrastructures;
\ No newline at end of file
diff --git a/src/Plugins/BotSharp.Plugin.Planner/data/agents/282a7128-69a1-44b0-878c-a9159b88f3b9/agent.json b/src/Plugins/BotSharp.Plugin.Planner/data/agents/282a7128-69a1-44b0-878c-a9159b88f3b9/agent.json
index 1f91baca..7f837847 100644
--- a/src/Plugins/BotSharp.Plugin.Planner/data/agents/282a7128-69a1-44b0-878c-a9159b88f3b9/agent.json
+++ b/src/Plugins/BotSharp.Plugin.Planner/data/agents/282a7128-69a1-44b0-878c-a9159b88f3b9/agent.json
@@ -1,8 +1,8 @@
{
"id": "282a7128-69a1-44b0-878c-a9159b88f3b9",
- "name": "Planner",
- "description": "Plan feasible implementation steps for complex user task request, including generating sql query",
- "type": "task",
+ "name": "Two-Stage-Planner",
+ "description": "Plan feasible steps for complex user task request, including generating sql query",
+ "type": "planning",
"createdDateTime": "2023-08-27T10:39:00Z",
"updatedDateTime": "2023-08-27T14:39:00Z",
"iconUrl": "https://e7.pngegg.com/pngimages/775/350/png-clipart-action-plan-computer-icons-plan-miscellaneous-text-thumbnail.png",
@@ -13,7 +13,7 @@
"utilities": [],
"llmConfig": {
"provider": "openai",
- "model": "gpt-4o",
+ "model": "gpt-4o-2024-11-20",
"max_recursion_depth": 10
}
}
\ No newline at end of file
diff --git a/src/Plugins/BotSharp.Plugin.Planner/data/agents/282a7128-69a1-44b0-878c-a9159b88f3b9/templates/two_stage.1st.plan.liquid b/src/Plugins/BotSharp.Plugin.Planner/data/agents/282a7128-69a1-44b0-878c-a9159b88f3b9/templates/two_stage.1st.plan.liquid
index 190edf8c..306f4214 100644
--- a/src/Plugins/BotSharp.Plugin.Planner/data/agents/282a7128-69a1-44b0-878c-a9159b88f3b9/templates/two_stage.1st.plan.liquid
+++ b/src/Plugins/BotSharp.Plugin.Planner/data/agents/282a7128-69a1-44b0-878c-a9159b88f3b9/templates/two_stage.1st.plan.liquid
@@ -15,7 +15,8 @@ Thinking process:
4. Output all the subtasks as much detail as possible in JSON: [{{ response_format }}]
5. You can NOT generate the final query before calling function plan_summary.
-Note:If the task includes repeat steps,e.g.same steps for multiple elements, only generate a single detailed solution without repeating steps for each elements. You can add multiple items in the input and output args.
+Note:
+* If the task includes repeat steps,e.g.same steps for multiple elements, only generate a single detailed solution without repeating steps for each elements.
{% if global_knowledges != empty -%}
=====
diff --git a/src/Plugins/BotSharp.Plugin.Planner/data/agents/3e75e818-a139-48a8-9e22-4662548c13a3/agent.json b/src/Plugins/BotSharp.Plugin.Planner/data/agents/3e75e818-a139-48a8-9e22-4662548c13a3/agent.json
new file mode 100644
index 00000000..59231a43
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.Planner/data/agents/3e75e818-a139-48a8-9e22-4662548c13a3/agent.json
@@ -0,0 +1,19 @@
+{
+ "id": "3e75e818-a139-48a8-9e22-4662548c13a3",
+ "name": "Sequential-Planner",
+ "description": "Plan an ordered plan steps to execute some tasks in a predefined order by the user",
+ "type": "planning",
+ "createdDateTime": "2023-08-27T10:39:00Z",
+ "updatedDateTime": "2023-08-27T14:39:00Z",
+ "iconUrl": "https://www.shutterstock.com/image-vector/sequential-process-glyph-icon-order-260nw-1015790182.jpg",
+ "disabled": false,
+ "isPublic": true,
+ "profiles": [ "planning" ],
+ "mergeUtility": true,
+ "utilities": [],
+ "llmConfig": {
+ "provider": "openai",
+ "model": "gpt-4o-2024-11-20",
+ "max_recursion_depth": 10
+ }
+}
\ No newline at end of file
diff --git a/src/Plugins/BotSharp.Plugin.Planner/data/agents/3e75e818-a139-48a8-9e22-4662548c13a3/instructions/instruction.liquid b/src/Plugins/BotSharp.Plugin.Planner/data/agents/3e75e818-a139-48a8-9e22-4662548c13a3/instructions/instruction.liquid
new file mode 100644
index 00000000..25e26106
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.Planner/data/agents/3e75e818-a139-48a8-9e22-4662548c13a3/instructions/instruction.liquid
@@ -0,0 +1,15 @@
+You are a Task Planner. you will breakdown user business requirements into excutable sub-steps.
+Follow the instructions below to plan and execute tasks:
+
+1. Look at all the steps first, think carefully, and decide which step to do first.
+2. Look at the description of each step, and use the existing functions and tools to plan the execution steps.
+
+{% if global_knowledges != empty -%}
+=====
+Global Knowledge:
+Current date time is: {{ "now" | date: "%Y-%m-%d %H:%M" }}
+{% for k in global_knowledges %}
+{{ k }}
+{% endfor %}
+=====
+{%- endif %}
\ No newline at end of file
diff --git a/src/Plugins/BotSharp.Plugin.SqlDriver/Hooks/SqlDriverAgentHook.cs b/src/Plugins/BotSharp.Plugin.SqlDriver/Hooks/SqlDriverAgentHook.cs
index 53b7866f..14205493 100644
--- a/src/Plugins/BotSharp.Plugin.SqlDriver/Hooks/SqlDriverAgentHook.cs
+++ b/src/Plugins/BotSharp.Plugin.SqlDriver/Hooks/SqlDriverAgentHook.cs
@@ -4,7 +4,7 @@ namespace BotSharp.Plugin.SqlDriver.Hooks;
public class SqlDriverAgentHook : AgentHookBase, IAgentHook
{
- public override string SelfId => BuiltInAgentId.Planner;
+ public override string SelfId => string.Empty;
public SqlDriverAgentHook(IServiceProvider services, AgentSettings settings)
: base(services, settings)
diff --git a/src/Plugins/BotSharp.Plugin.SqlDriver/Hooks/SqlDriverCrontabHook.cs b/src/Plugins/BotSharp.Plugin.SqlDriver/Hooks/SqlDriverCrontabHook.cs
index 64629fcb..7f645cd9 100644
--- a/src/Plugins/BotSharp.Plugin.SqlDriver/Hooks/SqlDriverCrontabHook.cs
+++ b/src/Plugins/BotSharp.Plugin.SqlDriver/Hooks/SqlDriverCrontabHook.cs
@@ -1,6 +1,7 @@
+using BotSharp.Abstraction.Crontab.Models;
+using BotSharp.Abstraction.Models;
+using BotSharp.Abstraction.SideCar;
using BotSharp.Core.Crontab.Abstraction;
-using BotSharp.Core.Crontab.Models;
-using Microsoft.EntityFrameworkCore.Query;
namespace BotSharp.Plugin.SqlDriver.Hooks;
@@ -16,16 +17,22 @@ public class SqlDriverCrontabHook : ICrontabHook
public async Task OnCronTriggered(CrontabItem item)
{
- if (item.Language != "sql")
+ /*var conv = _services.GetRequiredService();
+ conv.SetConversationId("abd9df25-2210-4e4d-80d7-48b6a3b905a8", []);
+
+ if (item.Language == "text")
+ {
+ var sidecar = _services.GetService();
+ var response = await sidecar.SendMessage(BuiltInAgentId.AIAssistant, item.Description, states: new List());
+ return;
+ }
+ else if (item.Language != "sql")
{
return;
}
_logger.LogWarning($"Crontab item triggered: {item.Topic}. Run {item.Language}: {item.Script}");
- var conv = _services.GetRequiredService();
- conv.SetConversationId("73a9ee27-d597-4739-958f-3bd79760ac8e", []);
-
var message = new RoleDialogModel(AgentRole.User, $"Run the query")
{
FunctionName = "sql_select",
@@ -42,6 +49,6 @@ public class SqlDriverCrontabHook : ICrontabHook
item.ConversationId = conv.ConversationId;
item.AgentId = BuiltInAgentId.SqlDriver;
item.UserId = "41021346";
- item.ExecutionResult = message.Content;
+ item.ExecutionResult = message.Content;*/
}
}
diff --git a/src/WebStarter/WebStarter.csproj b/src/WebStarter/WebStarter.csproj
index a8f819d6..cb107490 100644
--- a/src/WebStarter/WebStarter.csproj
+++ b/src/WebStarter/WebStarter.csproj
@@ -1,4 +1,4 @@
-
+
$(TargetFramework)
@@ -29,6 +29,7 @@
+
diff --git a/src/WebStarter/appsettings.json b/src/WebStarter/appsettings.json
index 8c4cd9aa..c3d4bdd5 100644
--- a/src/WebStarter/appsettings.json
+++ b/src/WebStarter/appsettings.json
@@ -328,6 +328,7 @@
"Assemblies": [
"BotSharp.Core",
"BotSharp.Core.SideCar",
+ "BotSharp.Core.Crontab",
"BotSharp.Logger",
"BotSharp.Plugin.MongoStorage",
"BotSharp.Plugin.Dashboard",