Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ExecuteSqlSelectAutonomous #646

Merged
merged 18 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ public class MessageInfo : ICacheKey
public string StepId { get; set; } = Guid.NewGuid().ToString();

public string GetCacheKey()
=> $"{nameof(MessageInfo)}-{ContextId}";
=> $"{nameof(MessageInfo)}";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace BotSharp.Abstraction.Planning;

public interface IPlanningHook
{
Task<string> GetSummaryAdditionalRequirements(string planner)
=> Task.FromResult(string.Empty);
Task OnPlanningCompleted(string planner, RoleDialogModel msg)
=> Task.CompletedTask;
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public interface IBotSharpRepository

#region User
User? GetUserByEmail(string email) => throw new NotImplementedException();
User? GetUserByPhone(string phone) => throw new NotImplementedException();
User? GetUserById(string id) => throw new NotImplementedException();
User? GetUserByUserName(string userName) => throw new NotImplementedException();
void CreateUser(User user) => throw new NotImplementedException();
Expand Down
1 change: 1 addition & 0 deletions src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@
<PackageReference Include="DistributedLock.Redis" Version="1.0.3" />
<PackageReference Include="EntityFrameworkCore.BootKit" Version="8.5.1" />
<PackageReference Include="Fluid.Core" Version="2.11.1" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
<PackageReference Include="Nanoid" Version="3.1.0" />
</ItemGroup>
Expand Down
6 changes: 4 additions & 2 deletions src/Infrastructure/BotSharp.Core/BotSharpCoreExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ public static IServiceCollection AddBotSharpCore(this IServiceCollection service
var cacheSettings = new SharpCacheSettings();
config.Bind("SharpCache", cacheSettings);
services.AddSingleton(x => cacheSettings);
services.AddSingleton<ICacheService, CacheService>();

services.AddSingleton<ICacheService, RedisCacheService>();

services.AddMemoryCache();

RegisterPlugins(services, config);
ConfigureBotSharpOptions(services, configOptions);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using BotSharp.Abstraction.Infrastructures;
using Microsoft.Extensions.Caching.Memory;

namespace BotSharp.Core.Infrastructures;

public class MemoryCacheService : ICacheService
{
private static IMemoryCache _cache = new MemoryCache(new MemoryCacheOptions
{
});
private readonly BotSharpDatabaseSettings _settings;

public MemoryCacheService(BotSharpDatabaseSettings settings)
{
_settings = settings;
}

public async Task<T?> GetAsync<T>(string key)
{
return (T?)(_cache.Get(key) ?? default(T));
}

public async Task<object> GetAsync(string key, Type type)
{
return _cache.Get(key) ?? default;
}

public async Task SetAsync<T>(string key, T value, TimeSpan? expiry)
{
_cache.Set(key, value, new MemoryCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = expiry
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@

namespace BotSharp.Core.Infrastructures;

public class CacheService : ICacheService
public class RedisCacheService : ICacheService
{
private readonly BotSharpDatabaseSettings _settings;
private static ConnectionMultiplexer redis = null!;

public CacheService(BotSharpDatabaseSettings settings)
public RedisCacheService(BotSharpDatabaseSettings settings)
{
_settings = settings;
}
Expand Down Expand Up @@ -68,6 +68,11 @@ public async Task SetAsync<T>(string key, T value, TimeSpan? expiry)
return;
}

if (redis == null)
{
redis = ConnectionMultiplexer.Connect(_settings.Redis);
}

var db = redis.GetDatabase();
await db.StringSetAsync(key, JsonConvert.SerializeObject(value), expiry);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ public partial class FileRepository
return Users.FirstOrDefault(x => x.Email == email.ToLower());
}

public User? GetUserByPhone(string phone)
{
return Users.FirstOrDefault(x => x.Phone == phone);
}

public User? GetUserById(string id = null)
{
return Users.FirstOrDefault(x => x.Id == id || (x.ExternalId != null && x.ExternalId == id));
Expand Down
37 changes: 33 additions & 4 deletions src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -156,12 +156,10 @@ record = db.GetUserByUserName(id);
return default;
}

#if !DEBUG
if (!isAuthenticatedByHook && Utilities.HashTextMd5($"{password}{record.Salt}") != record.Password)
{
return default;
}
#endif

var accessToken = GenerateJwtToken(record);
var jwt = new JwtSecurityTokenHandler().ReadJwtToken(accessToken);
Expand Down Expand Up @@ -325,8 +323,24 @@ public async Task<bool> VerifyEmailExisting(string email)

public async Task<bool> SendVerificationCodeResetPassword(User user)
{
if (!string.IsNullOrEmpty(user.Email) && !string.IsNullOrEmpty(user.Phone))
{
return false;
}

var db = _services.GetRequiredService<IBotSharpRepository>();
var record = db.GetUserByEmail(user.Email);

User? record = null;

if (!string.IsNullOrEmpty(user.Email))
{
record = db.GetUserByEmail(user.Email);
}

if (!string.IsNullOrEmpty(user.Phone))
{
record = db.GetUserByPhone(user.Phone);
}
if (record == null)
{
return false;
Expand All @@ -349,8 +363,23 @@ public async Task<bool> SendVerificationCodeResetPassword(User user)

public async Task<bool> ResetUserPassword(User user)
{
if (!string.IsNullOrEmpty(user.Email) && !string.IsNullOrEmpty(user.Phone))
{
return false;
}
var db = _services.GetRequiredService<IBotSharpRepository>();
var record = db.GetUserByEmail(user.Email);

User? record = null;

if (!string.IsNullOrEmpty(user.Email))
{
record = db.GetUserByEmail(user.Email);
}

if (!string.IsNullOrEmpty(user.Phone))
{
record = db.GetUserByPhone(user.Phone);
}

if (record == null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public async Task<bool> VerifyEmailExisting([FromQuery] string email)
}
[AllowAnonymous]
[HttpPost("/user/verifycode")]
public async Task<bool> SendVerificationCodeResetPassword([FromQuery] UserCreationModel user)
public async Task<bool> SendVerificationCodeResetPassword([FromBody] UserCreationModel user)
{
return await _userService.SendVerificationCodeResetPassword(user.ToUser());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ public partial class MongoRepository
return user != null ? user.ToUser() : null;
}

public User? GetUserByPhone(string phone)
{
var user = _dc.Users.AsQueryable().FirstOrDefault(x => x.Phone == phone);
return user != null ? user.ToUser() : null;
}

public User? GetUserById(string id)
{
var user = _dc.Users.AsQueryable()
Expand Down
12 changes: 10 additions & 2 deletions src/Plugins/BotSharp.Plugin.Planner/BotSharp.Plugin.Planner.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
<None Remove="data\agents\282a7128-69a1-44b0-878c-a9159b88f3b9\functions\plan_secondary_stage.json" />
<None Remove="data\agents\282a7128-69a1-44b0-878c-a9159b88f3b9\functions\plan_summary.json" />
<None Remove="data\agents\282a7128-69a1-44b0-878c-a9159b88f3b9\instructions\instruction.liquid" />
<None Remove="data\agents\282a7128-69a1-44b0-878c-a9159b88f3b9\templates\two_stage.1st.next.liquid" />
<None Remove="data\agents\282a7128-69a1-44b0-878c-a9159b88f3b9\templates\database.summarize.MySql.liquid" />
<None Remove="data\agents\282a7128-69a1-44b0-878c-a9159b88f3b9\templates\database.summarize.SqlServer.liquid" />
<None Remove="data\agents\282a7128-69a1-44b0-878c-a9159b88f3b9\templates\two_stage.2nd.plan.liquid" />
<None Remove="data\agents\282a7128-69a1-44b0-878c-a9159b88f3b9\templates\two_stage.next.liquid" />
<None Remove="data\agents\282a7128-69a1-44b0-878c-a9159b88f3b9\templates\two_stage.summarize.liquid" />
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\planner_prompt.two_stage.1st.plan.liquid" />
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\plan_primary_stage.fn.liquid" />
Expand All @@ -41,7 +43,13 @@
<Content Include="data\agents\282a7128-69a1-44b0-878c-a9159b88f3b9\instructions\instruction.liquid">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="data\agents\282a7128-69a1-44b0-878c-a9159b88f3b9\templates\two_stage.1st.next.liquid">
<Content Include="data\agents\282a7128-69a1-44b0-878c-a9159b88f3b9\templates\database.summarize.mysql.liquid">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="data\agents\282a7128-69a1-44b0-878c-a9159b88f3b9\templates\database.summarize.sqlserver.liquid">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="data\agents\282a7128-69a1-44b0-878c-a9159b88f3b9\templates\two_stage.next.liquid">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="data\agents\282a7128-69a1-44b0-878c-a9159b88f3b9\templates\two_stage.2nd.plan.liquid">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace BotSharp.Plugin.Planner.Functions;
public class PrimaryStagePlanFn : IFunctionCallback
{
public string Name => "plan_primary_stage";

public string Indication => "Currently analyzing and breaking down user requirements.";
private readonly IServiceProvider _services;
private readonly ILogger<PrimaryStagePlanFn> _logger;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace BotSharp.Plugin.Planner.Functions;
public class SecondaryStagePlanFn : IFunctionCallback
{
public string Name => "plan_secondary_stage";

public string Indication => "Further analyzing and breaking down user sub-needs.";
private readonly IServiceProvider _services;
private readonly ILogger<SecondaryStagePlanFn> _logger;

Expand Down
24 changes: 15 additions & 9 deletions src/Plugins/BotSharp.Plugin.Planner/Functions/SummaryPlanFn.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
using BotSharp.Abstraction.Planning;
using BotSharp.Plugin.Planner.TwoStaging;
using BotSharp.Plugin.Planner.TwoStaging.Models;

namespace BotSharp.Plugin.Planner.Functions;

public class SummaryPlanFn : IFunctionCallback
{
public string Name => "plan_summary";

public string Indication => "Organizing and summarizing the final output results.";
private readonly IServiceProvider _services;
private readonly ILogger<SummaryPlanFn> _logger;

Expand Down Expand Up @@ -62,7 +64,9 @@ public async Task<bool> Execute(RoleDialogModel message)

var summary = await GetAiResponse(plannerAgent);
message.Content = summary.Content;
message.StopCompletion = true;

await HookEmitter.Emit<IPlanningHook>(_services, x =>
x.OnPlanningCompleted(nameof(TwoStageTaskPlanner), message));

return true;
}
Expand All @@ -74,18 +78,20 @@ private async Task<string> GetSummaryPlanPrompt(string taskDescription, string r

var agent = await agentService.GetAgent(BuiltInAgentId.Planner);
var template = agent.Templates.FirstOrDefault(x => x.Name == "two_stage.summarize")?.Content ?? string.Empty;
var responseFormat = JsonSerializer.Serialize(new FirstStagePlan

var additionalRequirements = new List<string>();
await HookEmitter.Emit<IPlanningHook>(_services, async x =>
{
Parameters = [JsonDocument.Parse("{}")],
Results = [""]
var requirement = await x.GetSummaryAdditionalRequirements(nameof(TwoStageTaskPlanner));
additionalRequirements.Add(requirement);
});

return render.Render(template, new Dictionary<string, object>
{
{ "table_structure", ddlStatement },
{ "task_description", taskDescription },
{ "summary_requirements", string.Join("\r\n",additionalRequirements) },
{ "relevant_knowledges", relevantKnowledge },
{ "response_format", responseFormat }
{ "table_structure", ddlStatement },
});
}
private async Task<RoleDialogModel> GetAiResponse(Agent plannerAgent)
Expand All @@ -94,8 +100,8 @@ private async Task<RoleDialogModel> GetAiResponse(Agent plannerAgent)
var wholeDialogs = conv.GetDialogHistory();

// Append text
wholeDialogs.Last().Content += "\n\nIf the table structure didn't mention auto incremental, the data field id needs to insert id manually and you need to use max(id) instead of LAST_INSERT_ID function.\nFor example, you should use SET @id = select max(id) from table;";
wholeDialogs.Last().Content += "\n\nTry if you can generate a single query to fulfill the needs";
wholeDialogs.Last().Content += "\n\nIf the table structure didn't mention auto incremental, the data field id needs to insert id manually and you need to use max(id).\nFor example, you should use SET @id = select max(id) from table;";
wholeDialogs.Last().Content += "\n\nTry if you can generate a single query to fulfill the needs.";

var completion = CompletionProvider.GetChatCompletion(_services,
provider: plannerAgent.LlmConfig.Provider,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ namespace BotSharp.Plugin.Planner.TwoStaging.Models;
public class SecondStagePlan
{
[JsonPropertyName("related_tables")]
public string[] Tables { get; set; } = new string[0];
public string[] Tables { get; set; } = [];

[JsonPropertyName("description")]
public string Description { get; set; } = "";
Expand All @@ -12,8 +12,8 @@ public class SecondStagePlan
public string Tool { get; set; } = "";

[JsonPropertyName("input_args")]
public JsonDocument[] Parameters { get; set; } = new JsonDocument[0];
public JsonDocument[] Parameters { get; set; } = [];

[JsonPropertyName("output_results")]
public string[] Results { get; set; } = new string[0];
public string[] Results { get; set; } = [];
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ public TwoStageTaskPlanner(IServiceProvider services, ILogger<TwoStageTaskPlanne

public async Task<FunctionCallFromLlm> GetNextInstruction(Agent router, string messageId, List<RoleDialogModel> dialogs)
{
var nextStepPrompt = await GetNextStepPrompt(router);
var inst = new FunctionCallFromLlm();
var nextStepPrompt = await GetNextStepPrompt(router);

// chat completion
var completion = CompletionProvider.GetChatCompletion(_services,
Expand Down Expand Up @@ -125,7 +125,7 @@ private async Task<string> GetNextStepPrompt(Agent router)
{
var agentService = _services.GetRequiredService<IAgentService>();
var planner = await agentService.LoadAgent(BuiltInAgentId.Planner);
var template = planner.Templates.First(x => x.Name == "two_stage.1st.next").Content;
var template = planner.Templates.First(x => x.Name == "two_stage.next").Content;
var states = _services.GetRequiredService<IConversationStateService>();
var render = _services.GetRequiredService<ITemplateRender>();
return render.Render(template, new Dictionary<string, object>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
"profiles": [ "planning" ],
"utilities": [ "two-stage-planner" ],
"llmConfig": {
"provider": "anthropic",
"model": "claude-3-5-sonnet-20240620",
"provider": "azure-openai",
"model": "gpt-4o",
"max_recursion_depth": 10
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ Use the TwoStagePlanner approach to plan the overall implementation steps, follo
2. If need_additional_information is true, call plan_secondary_stage for the specific primary stage.
3. You must call plan_summary as the last planning step to summarize the final query.

*** IMPORTANT ***
Don't run the planning process repeatedly if you have already got the result of user's request.


{% if global_knowledges != empty -%}
=====
Global Knowledge:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Try if you can generate a single query to fulfill the needs. The step should contains all needed parameters.
The parameters can be extracted from the original task.
If not, generate the query step by step based on the planning.

The query must exactly based on the provided table structure. And carefully review the foreign keys to make sure you include all the accurate information.

Note: Output should be only the sql query with sql comments that can be directly run in mysql database with version 8.0.

Don't use the sql statement that specify target table for update in FROM clause.
For example, you CAN'T write query as below:
INSERT INTO data_Service (Id, Name)
VALUES ((SELECT MAX(Id) + 1 FROM data_Service), 'HVAC');

If the table structure didn't mention auto incremental, the data field id needs to insert id manually and you need to use max(id) instead of LAST_INSERT_ID function.
For example, you should use SET @id = select max(id) from table;

* the alias of the table name in the sql query should be identical.
*** the generated sql query MUST be basedd on the provided table structure. ***
Loading