Merge branch 'SciSharp:master' into master

This commit is contained in:
hchen2020 2024-11-12 16:53:38 -06:00 committed by GitHub
commit aefde062b0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 129 additions and 71 deletions

View file

@ -2,7 +2,7 @@ namespace BotSharp.Abstraction.Planning;
public interface IPlanningHook
{
Task<string> GetSummaryAdditionalRequirements(string planner)
Task<string> GetSummaryAdditionalRequirements(string planner, RoleDialogModel message)
=> Task.FromResult(string.Empty);
Task OnPlanningCompleted(string planner, RoleDialogModel msg)

View file

@ -1,7 +0,0 @@
namespace BotSharp.Abstraction.Repositories;
public interface IDatabaseHook
{
// Get database type
string GetDatabaseType(RoleDialogModel message);
}

View file

@ -1,4 +1,5 @@
using BotSharp.Abstraction.Repositories.Enums;
using BotSharp.Abstraction.Users.Enums;
using System.IO;
namespace BotSharp.Core.Agents.Services;
@ -16,6 +17,12 @@ public partial class AgentService
return refreshResult;
}
var user = _db.GetUserById(_user.Id);
if (!UserConstant.AdminRoles.Contains(user.Role))
{
return "Unauthorized user.";
}
var agentDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
dbSettings.FileRepository,
_agentSettings.DataDir);
@ -25,10 +32,8 @@ public partial class AgentService
refreshResult = $"Cannot find the directory: {agentDir}";
return refreshResult;
}
var user = _db.GetUserById(_user.Id);
var refreshedAgents = new List<string>();
foreach (var dir in Directory.GetDirectories(agentDir))
{
try

View file

@ -1,38 +0,0 @@
using System.Text.Json.Serialization;
namespace BotSharp.Core.Routing.Planning;
public class FirstStagePlan
{
[JsonPropertyName("task_detail")]
public string Task { get; set; } = "";
[JsonPropertyName("reason")]
public string Reason { get; set; } = "";
[JsonPropertyName("step")]
public int Step { get; set; } = -1;
[JsonPropertyName("need_breakdown_task")]
public bool ContainMultipleSteps { get; set; } = false;
[JsonPropertyName("need_lookup_dictionary")]
public bool NeedLookupDictionary { get; set; } = false;
[JsonPropertyName("related_tables")]
public string[] Tables { get; set; } = new string[0];
[JsonPropertyName("related_urls")]
public string[] Urls { get; set; } = new string[0];
[JsonPropertyName("input_args")]
public JsonDocument[] Parameters { get; set; } = new JsonDocument[0];
[JsonPropertyName("output_results")]
public string[] Results { get; set; } = new string[0];
public override string ToString()
{
return $"STEP {Step}: {Task}";
}
}

View file

@ -1,6 +1,4 @@
using BotSharp.Abstraction.Plugins.Models;
using BotSharp.Abstraction.Repositories.Enums;
using BotSharp.Abstraction.Users.Enums;
using BotSharp.Plugin.MongoStorage.Repository;
namespace BotSharp.Plugin.MongoStorage;
@ -31,14 +29,4 @@ public class MongoStoragePlugin : IBotSharpPlugin
services.AddScoped<IBotSharpRepository, MongoRepository>();
}
}
public bool AttachMenu(List<PluginMenuDef> menu)
{
var section = menu.First(x => x.Label == "Apps");
menu.Add(new PluginMenuDef("MongoDB", icon: "bx bx-data", link: "page/mongodb", weight: section.Weight + 10)
{
Roles = new List<string> { UserRole.Root, UserRole.Admin }
});
return true;
}
}

View file

@ -88,7 +88,7 @@ public class SummaryPlanFn : IFunctionCallback
var additionalRequirements = new List<string>();
await HookEmitter.Emit<IPlanningHook>(_services, async x =>
{
var requirement = await x.GetSummaryAdditionalRequirements(nameof(TwoStageTaskPlanner));
var requirement = await x.GetSummaryAdditionalRequirements(nameof(TwoStageTaskPlanner), message);
additionalRequirements.Add(requirement);
});

View file

@ -20,6 +20,9 @@ public class FirstStagePlan
[JsonPropertyName("related_tables")]
public string[] Tables { get; set; } = [];
[JsonPropertyName("has_found_relevant_knowledge")]
public bool HasFoundRelevantKnowledge { get; set; } = false;
//[JsonPropertyName("related_urls")]
//public string[] Urls { get; set; } = [];

View file

@ -1,4 +1,4 @@
The user is dealing with a complex problem, and you need to break this complex problem into several small tasks to more easily solve the user's needs.
You are planning to convert the user requirement into sql statements. The user is dealing with a complex problem, and you need to break this complex problem into several small tasks to more easily solve the user's needs.
Use the TwoStagePlanner approach to plan the overall implementation steps, follow the below steps strictly.
1. Call plan_primary_stage to generate the primary plan.
@ -13,7 +13,7 @@ Use the TwoStagePlanner approach to plan the overall implementation steps, follo
*** IMPORTANT ***
Don't run the planning process repeatedly if you have already got the result of user's request.
Function verify_dictionary_term CAN'T generate INSERT SQL Statement.
The table name must come from the relevant knowledge. has_found_relevant_knowledge must be true.
{% if global_knowledges != empty -%}
=====

View file

@ -34,6 +34,7 @@
<None Remove="data\agents\beda4c12-e1ec-4b4b-b328-3df4a6687c4f\templates\database.summarize.redshift.liquid" />
<None Remove="data\agents\beda4c12-e1ec-4b4b-b328-3df4a6687c4f\templates\database.summarize.sqlserver.liquid" />
<None Remove="data\agents\beda4c12-e1ec-4b4b-b328-3df4a6687c4f\templates\query_result_formatting.liquid" />
<None Remove="data\agents\beda4c12-e1ec-4b4b-b328-3df4a6687c4f\templates\render_buttons.liquid" />
<None Remove="data\agents\beda4c12-e1ec-4b4b-b328-3df4a6687c4f\templates\sql_statement_correctness.liquid" />
</ItemGroup>
@ -86,6 +87,9 @@
<Content Include="data\agents\beda4c12-e1ec-4b4b-b328-3df4a6687c4f\templates\database.summarize.sqlserver.liquid">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="data\agents\beda4c12-e1ec-4b4b-b328-3df4a6687c4f\templates\render_buttons.liquid">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="data\agents\beda4c12-e1ec-4b4b-b328-3df4a6687c4f\templates\sql_statement_correctness.liquid">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>

View file

@ -2,6 +2,7 @@ using BotSharp.Abstraction.Agents.Enums;
using BotSharp.Abstraction.Repositories;
using BotSharp.Abstraction.Routing;
using BotSharp.Core.Infrastructures;
using BotSharp.Plugin.SqlDriver.Interfaces;
using BotSharp.Plugin.SqlDriver.Models;
using Dapper;
using Microsoft.Data.SqlClient;
@ -30,7 +31,7 @@ public class ExecuteQueryFn : IFunctionCallback
{
var args = JsonSerializer.Deserialize<ExecuteQueryArgs>(message.FunctionArgs);
var refinedArgs = await RefineSqlStatement(message, args);
var dbHook = _services.GetRequiredService<IDatabaseHook>();
var dbHook = _services.GetRequiredService<ISqlDriverHook>();
var dbType = dbHook.GetDatabaseType(message);
try

View file

@ -1,4 +1,4 @@
using BotSharp.Abstraction.Repositories;
using BotSharp.Plugin.SqlDriver.Interfaces;
using BotSharp.Plugin.SqlDriver.Models;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
@ -30,7 +30,7 @@ public class GetTableDefinitionFn : IFunctionCallback
var args = JsonSerializer.Deserialize<SqlStatement>(message.FunctionArgs);
var tables = args.Tables;
var agentService = _services.GetRequiredService<IAgentService>();
var dbHook = _services.GetRequiredService<IDatabaseHook>();
var dbHook = _services.GetRequiredService<ISqlDriverHook>();
var dbType = dbHook.GetDatabaseType(message);
// Get table DDL from database

View file

@ -0,0 +1,12 @@
namespace BotSharp.Plugin.SqlDriver.Hooks;
public class SqlDriverConversationHook : ConversationHookBase, IConversationHook
{
public override Task OnResponseGenerated(RoleDialogModel message)
{
// Render function buttons
return base.OnResponseGenerated(message);
}
}

View file

@ -1,7 +1,13 @@
using BotSharp.Abstraction.Agents.Enums;
using BotSharp.Abstraction.Messaging.Enums;
using BotSharp.Abstraction.Messaging.Models.RichContent.Template;
using BotSharp.Abstraction.Messaging.Models.RichContent;
using BotSharp.Abstraction.Messaging;
using BotSharp.Abstraction.Planning;
using BotSharp.Abstraction.Routing;
using BotSharp.Core.Infrastructures;
using System.Text.RegularExpressions;
using BotSharp.Plugin.SqlDriver.Interfaces;
namespace BotSharp.Plugin.SqlDriver.Hooks;
@ -16,9 +22,19 @@ public class SqlDriverPlanningHook : IPlanningHook
public async Task OnPlanningCompleted(string planner, RoleDialogModel msg)
{
var settings = _services.GetRequiredService<SqlDriverSetting>();
await HookEmitter.Emit<ISqlDriverHook>(_services, async (hook) =>
{
await hook.SqlGenerated(msg);
});
var settings = _services.GetRequiredService<SqlDriverSetting>();
if (!settings.ExecuteSqlSelectAutonomous)
{
var conversationStateService = _services.GetRequiredService<IConversationStateService>();
var conversationId = conversationStateService.GetConversationId();
msg.PostbackFunctionName = "execute_sql";
msg.RichContent = BuildRunQueryButton(planner, msg.Content);
msg.StopCompletion = true;
return;
}
@ -42,8 +58,60 @@ public class SqlDriverPlanningHook : IPlanningHook
msg.FunctionArgs = response.FunctionArgs;
msg.Content = response.Content;
msg.StopCompletion = response.StopCompletion;
}
/*var routing = _services.GetRequiredService<IRoutingService>();
await routing.InvokeAgent(BuiltInAgentId.SqlDriver, wholeDialogs);*/
public async Task<string> GetSummaryAdditionalRequirements(string planner, RoleDialogModel message)
{
var settings = _services.GetRequiredService<SqlDriverSetting>();
var sqlHooks = _services.GetServices<ISqlDriverHook>();
var dbType = sqlHooks.Any() ?
sqlHooks.First().GetDatabaseType(message) :
settings.DatabaseType;
var agent = await _services.GetRequiredService<IAgentService>()
.LoadAgent(BuiltInAgentId.SqlDriver);
return agent.Templates.FirstOrDefault(x => x.Name == $"database.summarize.{dbType}")?.Content ?? string.Empty;
}
private RichContent<IRichMessage> BuildRunQueryButton(string conversationId, string text)
{
string pattern = @"```sql\s*([\s\S]*?)\s*```";
var sql = Regex.Match(text, pattern).Groups[1].Value;
var state = _services.GetRequiredService<IConversationStateService>();
var deleteTable = state.GetState("tmp_table");
var deleteSql = $"DROP TABLE IF EXISTS {deleteTable};";
return new RichContent<IRichMessage>
{
FillPostback = true,
Editor = EditorTypeEnum.Text,
Recipient = new Recipient
{
Id = conversationId
},
Message = new ButtonTemplateMessage
{
Text = text,
Buttons = new List<ElementButton>
{
new ElementButton
{
Type = "text",
Title = "Execute the SQL Statement",
Payload = sql,
IsPrimary = true
},
new ElementButton
{
Type = "text",
Title = "Purge Cache",
Payload = deleteSql
}
}.ToArray()
}
};
}
}

View file

@ -57,7 +57,7 @@ public class SqlExecutorHook : AgentHookBase, IAgentHook
var fns = agent?.Functions?.Where(x => _targetSqlExecutorFunctions.Contains(x.Name))?.ToList();
var prompt = agent?.Templates?.FirstOrDefault(x => x.Name.IsEqualTo(SQL_EXECUTOR_TEMPLATE))?.Content ?? string.Empty;
var dbType = GetDatabaseType();
var dbType = GetDatabaseType(); //need change-> using hook?
var render = _services.GetRequiredService<ITemplateRender>();
prompt = render.Render(prompt, new Dictionary<string, object>
{

View file

@ -0,0 +1,10 @@
namespace BotSharp.Plugin.SqlDriver.Interfaces;
public interface ISqlDriverHook
{
// Get database type
string GetDatabaseType(RoleDialogModel message);
Task SqlGenerated(RoleDialogModel message);
Task SqlExecuting(RoleDialogModel message);
Task SqlExecuted(RoleDialogModel message);
}

View file

@ -31,5 +31,6 @@ public class SqlDriverPlugin : IBotSharpPlugin
services.AddScoped<IPlanningHook, SqlDriverPlanningHook>();
services.AddScoped<IAgentHook, SqlDictionaryLookupHook>();
services.AddScoped<IAgentHook, GetTableDefinitionHook>();
services.AddScoped<IConversationHook, SqlDriverConversationHook>();
}
}

View file

@ -0,0 +1,11 @@
Determine whether to render the following button based on the text.
sql_executable: When the text contains an executable sql statement, set it to true
contains_tmp_table: When the text contains a table named tmp, set it to true
is_sql_template
Output should be json format
{
"sql_executable": false,
"contains_tmp_table": false,
"is_sql_template": false
}