2025-01-18 04:06:51 +00:00
using BotSharp.Plugin.Planner.SqlGeneration ;
2024-12-16 23:22:28 +00:00
using BotSharp.Plugin.Planner.TwoStaging ;
using BotSharp.Plugin.Planner.TwoStaging.Models ;
namespace BotSharp.Plugin.Planner.Functions ;
public class SqlGenerationFn : IFunctionCallback
{
public string Name = > "sql_generation" ;
public string Indication = > "Organizing and summarizing the final SQL statements." ;
private readonly IServiceProvider _services ;
private readonly ILogger < SqlGenerationFn > _logger ;
public SqlGenerationFn (
IServiceProvider services ,
ILogger < SqlGenerationFn > logger )
{
_services = services ;
_logger = logger ;
}
public async Task < bool > Execute ( RoleDialogModel message )
{
var fn = _services . GetRequiredService < IRoutingService > ( ) ;
var agentService = _services . GetRequiredService < IAgentService > ( ) ;
var states = _services . GetRequiredService < IConversationStateService > ( ) ;
states . SetState ( "max_tokens" , "4096" ) ;
var currentAgent = await agentService . LoadAgent ( message . CurrentAgentId ) ;
var taskRequirement = states . GetState ( "requirement_detail" ) ;
// Get table names
var steps = states . GetState ( "planning_result" ) . JsonArrayContent < SecondStagePlan > ( ) ;
var allTables = new List < string > ( ) ;
var ddlStatements = string . Empty ;
var domainKnowledge = states . GetState ( "planning_result" ) ;
domainKnowledge + = "\r\n" + states . GetState ( "domain_knowledges" ) ;
var dictionaryItems = states . GetState ( "dictionary_items" ) ;
var excelImportResult = states . GetState ( "excel_import_result" ) ;
foreach ( var step in steps )
{
allTables . AddRange ( step . Tables ) ;
}
var distinctTables = allTables . Distinct ( ) . ToList ( ) ;
var msgCopy = RoleDialogModel . From ( message ) ;
msgCopy . FunctionArgs = JsonSerializer . Serialize ( new
{
tables = distinctTables ,
} ) ;
await fn . InvokeFunction ( "sql_table_definition" , msgCopy ) ;
ddlStatements + = "\r\n" + msgCopy . Content ;
states . SetState ( "table_ddls" , ddlStatements ) ;
// Summarize and generate query
2025-01-18 04:06:51 +00:00
var prompt = await GetSqlGenerationPrompt ( msgCopy , taskRequirement , domainKnowledge , dictionaryItems , ddlStatements , excelImportResult ) ;
_logger . LogInformation ( $"SQL Generation plan prompt:\r\n{prompt}" ) ;
2024-12-16 23:22:28 +00:00
var plannerAgent = new Agent
{
2025-01-18 04:06:51 +00:00
Id = PlannerAgentId . SqlPlanner ,
2024-12-16 23:22:28 +00:00
Name = Name ,
Instruction = prompt ,
LlmConfig = currentAgent . LlmConfig
} ;
var summary = await GetAiResponse ( plannerAgent ) ;
message . Content = summary . Content ;
/ * await HookEmitter . Emit < IPlanningHook > ( _services , async hook = >
await hook . OnPlanningCompleted ( nameof ( TwoStageTaskPlanner ) , message )
) ; * /
return true ;
}
2025-01-18 04:06:51 +00:00
private async Task < string > GetSqlGenerationPrompt ( RoleDialogModel message , string taskDescription , string domainKnowledge , string dictionaryItems , string ddlStatement , string excelImportResult )
2024-12-16 23:22:28 +00:00
{
var agentService = _services . GetRequiredService < IAgentService > ( ) ;
var render = _services . GetRequiredService < ITemplateRender > ( ) ;
var knowledgeHooks = _services . GetServices < IKnowledgeHook > ( ) ;
2025-01-18 04:06:51 +00:00
var agent = await agentService . GetAgent ( PlannerAgentId . SqlPlanner ) ;
var template = agent . Templates . FirstOrDefault ( x = > x . Name = = "sql.generation" ) ? . Content ? ? string . Empty ;
2024-12-16 23:22:28 +00:00
var additionalRequirements = new List < string > ( ) ;
await HookEmitter . Emit < IPlanningHook > ( _services , async x = >
{
2025-01-18 04:06:51 +00:00
var requirement = await x . GetSummaryAdditionalRequirements ( nameof ( SqlGenerationPlanner ) , message ) ;
2024-12-16 23:22:28 +00:00
additionalRequirements . Add ( requirement ) ;
2025-05-15 07:25:08 +00:00
} , message . CurrentAgentId ) ;
2024-12-16 23:22:28 +00:00
var globalKnowledges = new List < string > ( ) ;
foreach ( var hook in knowledgeHooks )
{
var k = await hook . GetGlobalKnowledges ( message ) ;
globalKnowledges . AddRange ( k ) ;
}
return render . Render ( template , new Dictionary < string , object >
{
{ "task_description" , taskDescription } ,
{ "summary_requirements" , string . Join ( "\r\n" , additionalRequirements ) } ,
{ "global_knowledges" , globalKnowledges } ,
{ "domain_knowledges" , domainKnowledge } ,
{ "dictionary_items" , dictionaryItems } ,
{ "table_structure" , ddlStatement } ,
{ "excel_import_result" , excelImportResult }
} ) ;
}
private async Task < RoleDialogModel > GetAiResponse ( Agent plannerAgent )
{
var conv = _services . GetRequiredService < IConversationService > ( ) ;
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).\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 ,
model : plannerAgent . LlmConfig . Model ) ;
return await completion . GetChatCompletions ( plannerAgent , wholeDialogs ) ;
}
}