BotSharp/src/Plugins/BotSharp.Plugin.Planner/Functions/SummaryPlanFn.cs

126 lines
5.2 KiB
C#
Raw Normal View History

2024-09-17 11:32:11 +00:00
using BotSharp.Abstraction.Planning;
using BotSharp.Plugin.Planner.TwoStaging;
2024-08-29 21:33:32 +00:00
using BotSharp.Plugin.Planner.TwoStaging.Models;
namespace BotSharp.Plugin.Planner.Functions;
public class SummaryPlanFn : IFunctionCallback
{
public string Name => "plan_summary";
2024-09-18 02:27:47 +00:00
public string Indication => "Organizing and summarizing the final output results.";
2024-08-29 21:33:32 +00:00
private readonly IServiceProvider _services;
2024-09-04 16:04:19 +00:00
private readonly ILogger<SummaryPlanFn> _logger;
2024-08-29 21:33:32 +00:00
2024-09-04 16:04:19 +00:00
public SummaryPlanFn(
IServiceProvider services,
ILogger<SummaryPlanFn> logger)
2024-08-29 21:33:32 +00:00
{
_services = services;
_logger = logger;
}
public async Task<bool> Execute(RoleDialogModel message)
{
2024-09-04 15:16:05 +00:00
var fn = _services.GetRequiredService<IRoutingService>();
var agentService = _services.GetRequiredService<IAgentService>();
2024-08-29 21:33:32 +00:00
var state = _services.GetRequiredService<IConversationStateService>();
2024-09-04 16:04:19 +00:00
2024-08-29 21:33:32 +00:00
state.SetState("max_tokens", "4096");
2024-09-05 01:11:25 +00:00
var currentAgent = await agentService.LoadAgent(message.CurrentAgentId);
2024-09-05 00:27:19 +00:00
var taskRequirement = state.GetState("requirement_detail");
2024-08-29 21:33:32 +00:00
2024-09-05 00:27:19 +00:00
// Get table names
2024-09-24 15:45:57 +00:00
var states = _services.GetRequiredService<IConversationStateService>();
var steps = states.GetState("planning_result").JsonArrayContent<SecondStagePlan>();
2024-09-04 16:04:19 +00:00
var allTables = new List<string>();
2024-09-30 23:25:32 +00:00
var ddlStatements = string.Empty;
2024-09-24 15:45:57 +00:00
var relevantKnowledge = states.GetState("planning_result");
2024-09-30 20:14:37 +00:00
var dictionaryItems = states.GetState("dictionary_items");
var excelImportResult = states.GetState("excel_import_result");
2024-09-24 15:45:57 +00:00
2024-09-04 15:16:05 +00:00
foreach (var step in steps)
{
allTables.AddRange(step.Tables);
}
var distinctTables = allTables.Distinct().ToList();
2024-09-30 23:25:32 +00:00
var msgCopy = RoleDialogModel.From(message);
msgCopy.FunctionArgs = JsonSerializer.Serialize(new
{
tables = distinctTables,
});
await fn.InvokeFunction("sql_table_definition", msgCopy);
ddlStatements += "\r\n" + msgCopy.Content;
2024-09-04 16:04:19 +00:00
// Summarize and generate query
var summaryPlanPrompt = await GetSummaryPlanPrompt(msgCopy, taskRequirement, relevantKnowledge, dictionaryItems, ddlStatements, excelImportResult);
2024-09-04 16:04:19 +00:00
_logger.LogInformation($"Summary plan prompt:\r\n{summaryPlanPrompt}");
2024-08-30 21:12:20 +00:00
2024-08-29 21:33:32 +00:00
var plannerAgent = new Agent
{
Id = BuiltInAgentId.Planner,
2024-09-04 16:04:19 +00:00
Name = "Planner Summary",
Instruction = summaryPlanPrompt,
2024-09-04 15:16:05 +00:00
LlmConfig = currentAgent.LlmConfig
2024-08-29 21:33:32 +00:00
};
2024-09-04 16:04:19 +00:00
var summary = await GetAiResponse(plannerAgent);
message.Content = summary.Content;
2024-09-17 11:32:11 +00:00
await HookEmitter.Emit<IPlanningHook>(_services, x =>
x.OnPlanningCompleted(nameof(TwoStageTaskPlanner), message));
2024-08-29 21:33:32 +00:00
return true;
}
private async Task<string> GetSummaryPlanPrompt(RoleDialogModel message, string taskDescription, string relevantKnowledge, string dictionaryItems, string ddlStatement, string excelImportResult)
2024-08-29 21:33:32 +00:00
{
var agentService = _services.GetRequiredService<IAgentService>();
var render = _services.GetRequiredService<ITemplateRender>();
var knowledgeHooks = _services.GetServices<IKnowledgeHook>();
2024-08-30 21:12:20 +00:00
2024-09-05 01:12:55 +00:00
var agent = await agentService.GetAgent(BuiltInAgentId.Planner);
var template = agent.Templates.FirstOrDefault(x => x.Name == "two_stage.summarize")?.Content ?? string.Empty;
2024-09-17 11:32:11 +00:00
var additionalRequirements = new List<string>();
await HookEmitter.Emit<IPlanningHook>(_services, async x =>
2024-08-29 21:33:32 +00:00
{
2024-09-17 11:32:11 +00:00
var requirement = await x.GetSummaryAdditionalRequirements(nameof(TwoStageTaskPlanner));
additionalRequirements.Add(requirement);
2024-08-29 21:33:32 +00:00
});
var globalKnowledges = new List<string>();
foreach (var hook in knowledgeHooks)
{
var k = await hook.GetGlobalKnowledges(message);
globalKnowledges.AddRange(k);
}
2024-08-29 21:33:32 +00:00
return render.Render(template, new Dictionary<string, object>
{
2024-09-05 00:27:19 +00:00
{ "task_description", taskDescription },
2024-09-30 23:25:32 +00:00
{ "summary_requirements", string.Join("\r\n", additionalRequirements) },
{ "global_knowledges", globalKnowledges },
2024-09-05 00:27:19 +00:00
{ "relevant_knowledges", relevantKnowledge },
2024-10-01 06:18:11 +00:00
{ "dictionary_items", dictionaryItems },
2024-09-17 11:32:11 +00:00
{ "table_structure", ddlStatement },
{ "excel_import_result",excelImportResult }
2024-08-29 21:33:32 +00:00
});
}
2024-08-30 21:12:20 +00:00
private async Task<RoleDialogModel> GetAiResponse(Agent plannerAgent)
2024-08-29 21:33:32 +00:00
{
var conv = _services.GetRequiredService<IConversationService>();
var wholeDialogs = conv.GetDialogHistory();
2024-08-30 21:12:20 +00:00
2024-09-05 00:27:19 +00:00
// Append text
2024-09-17 11:32:11 +00:00
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.";
2024-08-29 21:33:32 +00:00
var completion = CompletionProvider.GetChatCompletion(_services,
provider: plannerAgent.LlmConfig.Provider,
model: plannerAgent.LlmConfig.Model);
return await completion.GetChatCompletions(plannerAgent, wholeDialogs);
}
}