Merge pull request #688 from iceljc/master

add instruct
This commit is contained in:
iceljc 2024-10-17 18:19:41 -05:00 committed by GitHub
commit 2167988584
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 305 additions and 245 deletions

View file

@ -4,5 +4,23 @@ namespace BotSharp.Abstraction.Instructs;
public interface IInstructService
{
/// <summary>
/// Execute completion by using specified instruction or template
/// </summary>
/// <param name="agentId">Agent (static agent)</param>
/// <param name="message">Additional message provided by user</param>
/// <param name="templateName">Template name</param>
/// <param name="instruction">System prompt</param>
/// <returns></returns>
Task<InstructResult> Execute(string agentId, RoleDialogModel message, string? templateName = null, string? instruction = null);
/// <summary>
/// A generic way to execute completion by using specified instruction or template
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="instruction"></param>
/// <param name="agentId"></param>
/// <param name="options"></param>
/// <returns></returns>
Task<T?> Instruct<T>(string instruction, string agentId, InstructOptions options) where T : class;
}

View file

@ -0,0 +1,29 @@
namespace BotSharp.Abstraction.Instructs.Models;
public class InstructOptions
{
/// <summary>
/// Llm provider
/// </summary>
public string Provider { get; set; } = null!;
/// <summary>
/// Llm model
/// </summary>
public string Model { get; set; } = null!;
/// <summary>
/// Conversation id. When this field is not null, it will get dialogs from conversation.
/// </summary>
public string? ConversationId { get; set; }
/// <summary>
/// The single message. It can be append to the whole dialogs or sent alone.
/// </summary>
public string? Message { get; set; }
/// <summary>
/// Data to fill in prompt
/// </summary>
public Dictionary<string, object> Data { get; set; } = new();
}

View file

@ -1,19 +0,0 @@
namespace BotSharp.Abstraction.Knowledges.Models;
public class GenerateKnowledge
{
[JsonPropertyName("question")]
public string Question { get; set; } = string.Empty;
[JsonPropertyName("answer")]
public string Answer { get; set; } = string.Empty;
[JsonPropertyName("refined_collection")]
public string RefinedCollection { get; set; } = string.Empty;
[JsonPropertyName("refine_answer")]
public Boolean RefineAnswer { get; set; } = false;
[JsonPropertyName("existing_answer")]
public string ExistingAnswer { get; set; } = string.Empty;
}

View file

@ -372,10 +372,10 @@ public class ConversationStateService : IConversationStateService, IDisposable
private bool CheckArgType(string name, string value)
{
var agentTypes = AgentService.AgentParameterTypes.SelectMany(p => p.Value).ToList();
var filed = agentTypes.FirstOrDefault(t => t.Key == name);
if (filed.Key != null)
var found = agentTypes.FirstOrDefault(t => t.Key == name);
if (found.Key != null)
{
return filed.Value switch
return found.Value switch
{
"boolean" => bool.TryParse(value, out _),
"number" => long.TryParse(value, out _),

View file

@ -0,0 +1,100 @@
using BotSharp.Abstraction.Instructs;
using BotSharp.Abstraction.Instructs.Models;
using BotSharp.Abstraction.MLTasks;
namespace BotSharp.Core.Instructs;
public partial class InstructService
{
public async Task<InstructResult> Execute(string agentId, RoleDialogModel message, string? templateName = null, string? instruction = null)
{
var agentService = _services.GetRequiredService<IAgentService>();
Agent agent = await agentService.LoadAgent(agentId);
if (agent.Disabled)
{
var content = $"This agent ({agent.Name}) is disabled, please install the corresponding plugin ({agent.Plugin.Name}) to activate this agent.";
return new InstructResult
{
MessageId = message.MessageId,
Text = content
};
}
// Trigger before completion hooks
var hooks = _services.GetServices<IInstructHook>();
foreach (var hook in hooks)
{
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agentId)
{
continue;
}
await hook.BeforeCompletion(agent, message);
// Interrupted by hook
if (message.StopCompletion)
{
return new InstructResult
{
MessageId = message.MessageId,
Text = message.Content
};
}
}
// Render prompt
var prompt = string.IsNullOrEmpty(templateName) ?
agentService.RenderedInstruction(agent) :
agentService.RenderedTemplate(agent, templateName);
var completer = CompletionProvider.GetCompletion(_services,
agentConfig: agent.LlmConfig);
var response = new InstructResult
{
MessageId = message.MessageId
};
if (completer is ITextCompletion textCompleter)
{
var result = await textCompleter.GetCompletion(prompt, agentId, message.MessageId);
response.Text = result;
}
else if (completer is IChatCompletion chatCompleter)
{
if (instruction == "#TEMPLATE#")
{
instruction = prompt;
prompt = message.Content;
}
var result = await chatCompleter.GetChatCompletions(new Agent
{
Id = agentId,
Name = agent.Name,
Instruction = instruction
}, new List<RoleDialogModel>
{
new RoleDialogModel(AgentRole.User, prompt)
{
CurrentAgentId = agentId,
MessageId = message.MessageId
}
});
response.Text = result.Content;
}
foreach (var hook in hooks)
{
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agentId)
{
continue;
}
await hook.AfterCompletion(agent, response);
}
return response;
}
}

View file

@ -0,0 +1,110 @@
using BotSharp.Abstraction.Instructs.Models;
using BotSharp.Abstraction.Templating;
using System.Collections;
using System.Reflection;
namespace BotSharp.Core.Instructs;
public partial class InstructService
{
public async Task<T?> Instruct<T>(string instruction, string agentId, InstructOptions options) where T : class
{
var prompt = GetPrompt(instruction, options.Data);
var response = await GetAiResponse(agentId, prompt, options);
if (string.IsNullOrWhiteSpace(response.Content)) return null;
var type = typeof(T);
T? result = null;
try
{
if (IsStringType(type))
{
result = response.Content as T;
}
else if (IsListType(type))
{
var text = response.Content.JsonArrayContent();
if (!string.IsNullOrWhiteSpace(text))
{
result = JsonSerializer.Deserialize<T>(text, _options.JsonSerializerOptions);
}
}
else
{
var text = response.Content.JsonContent();
if (!string.IsNullOrWhiteSpace(text))
{
result = JsonSerializer.Deserialize<T>(text, _options.JsonSerializerOptions);
}
}
}
catch (Exception ex)
{
_logger.LogWarning($"Error when getting ai response, {ex.Message}\r\n{ex.InnerException}");
}
return result;
}
private string GetPrompt(string instruction, Dictionary<string, object> data)
{
var render = _services.GetRequiredService<ITemplateRender>();
return render.Render(instruction, data ?? new Dictionary<string, object>());
}
private async Task<RoleDialogModel> GetAiResponse(string agentId, string prompt, InstructOptions options)
{
var agentService = _services.GetRequiredService<IAgentService>();
var agent = await agentService.LoadAgent(agentId);
var localAgent = new Agent
{
Id = agentId,
Name = agent.Name,
Instruction = prompt,
TemplateDict = new()
};
var messages = BuildDialogs(options);
var completion = CompletionProvider.GetChatCompletion(_services, provider: options.Provider, model: options.Model);
return await completion.GetChatCompletions(localAgent, messages);
}
private List<RoleDialogModel> BuildDialogs(InstructOptions options)
{
var messages = new List<RoleDialogModel>();
if (!string.IsNullOrWhiteSpace(options.ConversationId))
{
var conv = _services.GetRequiredService<IConversationService>();
var dialogs = conv.GetDialogHistory();
messages.AddRange(dialogs);
}
if (!string.IsNullOrWhiteSpace(options.Message))
{
messages.Add(new RoleDialogModel(AgentRole.User, options.Message));
}
return messages;
}
private bool IsStringType(Type? type)
{
if (type == null) return false;
return type == typeof(string);
}
private bool IsListType(Type? type)
{
if (type == null) return false;
var interfaces = type.GetTypeInfo().ImplementedInterfaces;
return type.IsArray || interfaces.Any(x => x.Name == typeof(IEnumerable).Name);
}
}

View file

@ -1,118 +1,21 @@
using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Instructs;
using BotSharp.Abstraction.Instructs.Models;
using BotSharp.Abstraction.MLTasks;
using BotSharp.Abstraction.Options;
namespace BotSharp.Core.Instructs;
public partial class InstructService : IInstructService
{
private readonly IServiceProvider _services;
private readonly ILogger _logger;
private readonly BotSharpOptions _options;
private readonly ILogger<InstructService> _logger;
public InstructService(IServiceProvider services, ILogger<InstructService> logger)
public InstructService(
IServiceProvider services,
BotSharpOptions options,
ILogger<InstructService> logger)
{
_services = services;
_options = options;
_logger = logger;
}
/// <summary>
/// Execute completion by using specified instruction or template
/// </summary>
/// <param name="agentId">Agent (static agent)</param>
/// <param name="message">Additional message provided by user</param>
/// <param name="templateName">Template name</param>
/// <param name="instruction">System prompt</param>
/// <returns></returns>
public async Task<InstructResult> Execute(string agentId, RoleDialogModel message, string? templateName = null, string? instruction = null)
{
var agentService = _services.GetRequiredService<IAgentService>();
Agent agent = await agentService.LoadAgent(agentId);
if (agent.Disabled)
{
var content = $"This agent ({agent.Name}) is disabled, please install the corresponding plugin ({agent.Plugin.Name}) to activate this agent.";
return new InstructResult
{
MessageId = message.MessageId,
Text = content
};
}
// Trigger before completion hooks
var hooks = _services.GetServices<IInstructHook>();
foreach (var hook in hooks)
{
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agentId)
{
continue;
}
await hook.BeforeCompletion(agent, message);
// Interrupted by hook
if (message.StopCompletion)
{
return new InstructResult
{
MessageId = message.MessageId,
Text = message.Content
};
}
}
// Render prompt
var prompt = string.IsNullOrEmpty(templateName) ?
agentService.RenderedInstruction(agent) :
agentService.RenderedTemplate(agent, templateName);
var completer = CompletionProvider.GetCompletion(_services,
agentConfig: agent.LlmConfig);
var response = new InstructResult
{
MessageId = message.MessageId
};
if (completer is ITextCompletion textCompleter)
{
var result = await textCompleter.GetCompletion(prompt, agentId, message.MessageId);
response.Text = result;
}
else if (completer is IChatCompletion chatCompleter)
{
if (instruction == "#TEMPLATE#")
{
instruction = prompt;
prompt = message.Content;
}
var result = await chatCompleter.GetChatCompletions(new Agent
{
Id = agentId,
Name = agent.Name,
Instruction = instruction
}, new List<RoleDialogModel>
{
new RoleDialogModel(AgentRole.User, prompt)
{
CurrentAgentId = agentId,
MessageId = message.MessageId
}
});
response.Text = result.Content;
}
foreach (var hook in hooks)
{
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agentId)
{
continue;
}
await hook.AfterCompletion(agent, response);
}
return response;
}
}

View file

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>$(TargetFramework)</TargetFramework>
@ -21,7 +21,7 @@
<None Remove="data\agents\01acc3e5-0af7-49e6-ad7a-a760bd12dc40\functions\confirm_knowledge_persistence.json" />
<None Remove="data\agents\01acc3e5-0af7-49e6-ad7a-a760bd12dc40\functions\memorize_knowledge.json" />
<None Remove="data\agents\01acc3e5-0af7-49e6-ad7a-a760bd12dc40\instructions\instruction.liquid" />
<None Remove="data\agents\01acc3e5-0af7-49e6-ad7a-a760bd12dc40\templates\knowledge.generation.liquid" />
<None Remove="data\agents\01acc3e5-0af7-49e6-ad7a-a760bd12dc40\templates\knowledge.generation.plain.liquid" />
<None Remove="data\agents\01acc3e5-0af7-49e6-ad7a-a760bd12dc40\templates\knowledge.generation.refine.liquid" />
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\knowledge_retrieval.fn.liquid" />
</ItemGroup>
@ -42,7 +42,7 @@
<Content Include="data\agents\01acc3e5-0af7-49e6-ad7a-a760bd12dc40\templates\knowledge.generation.refine.liquid">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="data\agents\01acc3e5-0af7-49e6-ad7a-a760bd12dc40\templates\knowledge.generation.liquid">
<Content Include="data\agents\01acc3e5-0af7-49e6-ad7a-a760bd12dc40\templates\knowledge.generation.plain.liquid">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\functions\knowledge_retrieval.json">

View file

@ -1,90 +0,0 @@
using BotSharp.Abstraction.Templating;
using BotSharp.Core.Infrastructures;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace BotSharp.Plugin.KnowledgeBase.Functions;
public class GenerateKnowledgeFn : IFunctionCallback
{
public string Name => "generate_knowledge";
public string Indication => "generating knowledge";
private readonly IServiceProvider _services;
private readonly KnowledgeBaseSettings _settings;
public GenerateKnowledgeFn(IServiceProvider services, KnowledgeBaseSettings settings)
{
_services = services;
_settings = settings;
}
public async Task<bool> Execute(RoleDialogModel message)
{
var args = JsonSerializer.Deserialize<GenerateKnowledge>(message.FunctionArgs ?? "{}");
var agentService = _services.GetRequiredService<IAgentService>();
var llmAgent = await agentService.GetAgent(BuiltInAgentId.Planner);
var refineKnowledge = args.RefinedCollection;
String generateKnowledgePrompt;
if (args.RefineAnswer == true)
{
generateKnowledgePrompt = await GetRefineKnowledgePrompt(args.Question, args.Answer, args.ExistingAnswer);
}
else
{
generateKnowledgePrompt = await GetGenerateKnowledgePrompt(args.Question, args.Answer);
}
var agent = new Agent
{
Id = message.CurrentAgentId ?? string.Empty,
Name = "knowledge_generator",
Instruction = generateKnowledgePrompt,
LlmConfig = llmAgent.LlmConfig
};
var response = await GetAiResponse(agent);
message.Data = response.Content.JsonArrayContent<ExtractedKnowledge>();
message.Content = response.Content;
return true;
}
private async Task<string> GetGenerateKnowledgePrompt(string userQuestions, string sqlAnswer)
{
var agentService = _services.GetRequiredService<IAgentService>();
var render = _services.GetRequiredService<ITemplateRender>();
var agent = await agentService.GetAgent(BuiltInAgentId.Learner);
var template = agent.Templates.FirstOrDefault(x => x.Name == "knowledge.generation")?.Content ?? string.Empty;
return render.Render(template, new Dictionary<string, object>
{
{ "user_questions", userQuestions },
{ "sql_answer", sqlAnswer },
});
}
private async Task<string> GetRefineKnowledgePrompt(string userQuestion, string sqlAnswer, string existionAnswer)
{
var agentService = _services.GetRequiredService<IAgentService>();
var render = _services.GetRequiredService<ITemplateRender>();
var agent = await agentService.GetAgent(BuiltInAgentId.Learner);
var template = agent.Templates.FirstOrDefault(x => x.Name == "knowledge.generation.refine")?.Content ?? string.Empty;
return render.Render(template, new Dictionary<string, object>
{
{ "user_question", userQuestion },
{ "new_answer", sqlAnswer },
{ "existing_answer", existionAnswer}
});
}
private async Task<RoleDialogModel> GetAiResponse(Agent agent)
{
var text = "Generate question and answer pair";
var message = new RoleDialogModel(AgentRole.User, text);
var completion = CompletionProvider.GetChatCompletion(_services,
provider: agent.LlmConfig.Provider,
model: agent.LlmConfig.Model);
return await completion.GetChatCompletions(agent, new List<RoleDialogModel> { message });
}
}

View file

@ -6,10 +6,13 @@ 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;
public PrimaryStagePlanFn(IServiceProvider services, ILogger<PrimaryStagePlanFn> logger)
public PrimaryStagePlanFn(
IServiceProvider services,
ILogger<PrimaryStagePlanFn> logger)
{
_services = services;
_logger = logger;
@ -38,12 +41,12 @@ public class PrimaryStagePlanFn : IFunctionCallback
// Get first stage planning prompt
var currentAgent = await agentService.LoadAgent(message.CurrentAgentId);
var firstPlanningPrompt = await GetFirstStagePlanPrompt(message, task.Requirements, knowledges);
var prompt = await GetFirstStagePlanPrompt(message, task.Requirements, knowledges);
var plannerAgent = new Agent
{
Id = BuiltInAgentId.Planner,
Name = "planning_1st",
Instruction = firstPlanningPrompt,
Name = "FirstStagePlanner",
Instruction = prompt,
TemplateDict = new Dictionary<string, object>(),
LlmConfig = currentAgent.LlmConfig
};

View file

@ -1,5 +1,4 @@
using BotSharp.Plugin.Planner.TwoStaging.Models;
using System.Threading.Tasks;
namespace BotSharp.Plugin.Planner.Functions;
@ -7,10 +6,13 @@ 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;
public SecondaryStagePlanFn(IServiceProvider services, ILogger<SecondaryStagePlanFn> logger)
public SecondaryStagePlanFn(
IServiceProvider services,
ILogger<SecondaryStagePlanFn> logger)
{
_services = services;
_logger = logger;
@ -25,7 +27,7 @@ public class SecondaryStagePlanFn : IFunctionCallback
var msgSecondary = RoleDialogModel.From(message);
var collectionName = knowledgeSettings.Default.CollectionName;
var planPrimary = states.GetState("planning_result");
var planResult = states.GetState("planning_result");
var taskSecondary = JsonSerializer.Deserialize<SecondaryBreakdownTask>(msgSecondary.FunctionArgs);
@ -43,14 +45,14 @@ public class SecondaryStagePlanFn : IFunctionCallback
// Get second stage planning prompt
var currentAgent = await agentService.LoadAgent(message.CurrentAgentId);
var secondPlanningPrompt = await GetSecondStagePlanPrompt(taskSecondary.TaskDescription, planPrimary, knowledgeResults, message);
_logger.LogInformation(secondPlanningPrompt);
var prompt = await GetSecondStagePlanPrompt(taskSecondary.TaskDescription, planResult, knowledgeResults, message);
_logger.LogInformation(prompt);
var plannerAgent = new Agent
{
Id = BuiltInAgentId.Planner,
Name = "planning_2nd",
Instruction = secondPlanningPrompt,
Name = "SecondStagePlanner",
Instruction = prompt,
TemplateDict = new Dictionary<string, object>(),
LlmConfig = currentAgent.LlmConfig
};
@ -63,7 +65,7 @@ public class SecondaryStagePlanFn : IFunctionCallback
return true;
}
private async Task<string> GetSecondStagePlanPrompt(string taskDescription, string planPrimary, string knowledgeResults, RoleDialogModel message)
private async Task<string> GetSecondStagePlanPrompt(string taskDescription, string planResult, string knowledgeResults, RoleDialogModel message)
{
var agentService = _services.GetRequiredService<IAgentService>();
var render = _services.GetRequiredService<ITemplateRender>();
@ -79,7 +81,7 @@ public class SecondaryStagePlanFn : IFunctionCallback
return render.Render(template, new Dictionary<string, object>
{
{ "task_description", taskDescription },
{ "primary_plan", planPrimary },
{ "primary_plan", planResult },
{ "additional_knowledge", knowledgeResults },
{ "response_format", responseFormat }
});

View file

@ -8,6 +8,7 @@ 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;
@ -34,7 +35,7 @@ public class SummaryPlanFn : IFunctionCallback
var steps = states.GetState("planning_result").JsonArrayContent<SecondStagePlan>();
var allTables = new List<string>();
var ddlStatements = string.Empty;
var relevantKnowledge = states.GetState("planning_result");
var planResult = states.GetState("planning_result");
var dictionaryItems = states.GetState("dictionary_items");
var excelImportResult = states.GetState("excel_import_result");
@ -53,14 +54,14 @@ public class SummaryPlanFn : IFunctionCallback
ddlStatements += "\r\n" + msgCopy.Content;
// Summarize and generate query
var summaryPlanPrompt = await GetSummaryPlanPrompt(msgCopy, taskRequirement, relevantKnowledge, dictionaryItems, ddlStatements, excelImportResult);
_logger.LogInformation($"Summary plan prompt:\r\n{summaryPlanPrompt}");
var prompt = await GetSummaryPlanPrompt(msgCopy, taskRequirement, planResult, dictionaryItems, ddlStatements, excelImportResult);
_logger.LogInformation($"Summary plan prompt:\r\n{prompt}");
var plannerAgent = new Agent
{
Id = BuiltInAgentId.Planner,
Name = "Planner Summary",
Instruction = summaryPlanPrompt,
Name = "SummaryPlanner",
Instruction = prompt,
LlmConfig = currentAgent.LlmConfig
};
@ -105,7 +106,7 @@ public class SummaryPlanFn : IFunctionCallback
{ "relevant_knowledges", relevantKnowledge },
{ "dictionary_items", dictionaryItems },
{ "table_structure", ddlStatement },
{ "excel_import_result",excelImportResult }
{ "excel_import_result", excelImportResult }
});
}
private async Task<RoleDialogModel> GetAiResponse(Agent plannerAgent)

View file

@ -17,12 +17,12 @@
</ItemGroup>
<ItemGroup>
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\functions\sql_dictionary_lookup.json" />
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\functions\sql_select.json" />
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\functions\sql_table_definition.json" />
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\sql_dictionary_lookup.fn.liquid" />
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\functions\verify_dictionary_term.json" />
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\sql_executor.fn.liquid" />
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\sql_table_definition.fn.liquid" />
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\verify_dictionary_term.fn.liquid" />
<None Remove="data\agents\beda4c12-e1ec-4b4b-b328-3df4a6687c4f\agent.json" />
<None Remove="data\agents\beda4c12-e1ec-4b4b-b328-3df4a6687c4f\functions\execute_sql.json" />
<None Remove="data\agents\beda4c12-e1ec-4b4b-b328-3df4a6687c4f\functions\lookup_dictionary.json" />
@ -37,10 +37,10 @@
<Content Include="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\functions\sql_table_definition.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\functions\sql_dictionary_lookup.json">
<Content Include="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\functions\verify_dictionary_term.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\sql_dictionary_lookup.fn.liquid">
<Content Include="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\verify_dictionary_term.fn.liquid">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="data\agents\beda4c12-e1ec-4b4b-b328-3df4a6687c4f\functions\sql_table_definition.json">

View file

@ -7,12 +7,15 @@ using static Dapper.SqlMapper;
namespace BotSharp.Plugin.SqlDriver.Functions;
public class LookupDictionaryFn : IFunctionCallback
public class VerifyDictionaryTerm : IFunctionCallback
{
public string Name => "verify_dictionary_term";
public string Indication => "Verifying dictionary term";
private readonly IServiceProvider _services;
public LookupDictionaryFn(IServiceProvider services)
public VerifyDictionaryTerm(IServiceProvider services)
{
_services = services;
}