diff --git a/src/Infrastructure/BotSharp.Abstraction/Knowledges/IKnowledgeHook.cs b/src/Infrastructure/BotSharp.Abstraction/Knowledges/IKnowledgeHook.cs index 4d94a52a..aefcdec6 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Knowledges/IKnowledgeHook.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Knowledges/IKnowledgeHook.cs @@ -4,5 +4,9 @@ namespace BotSharp.Abstraction.Knowledges; public interface IKnowledgeHook { - Task> CollectChunkedKnowledge(); + Task> CollectChunkedKnowledge() + => Task.FromResult(new List()); + + Task> GetRelevantKnowledges() + => Task.FromResult(new List()); } diff --git a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj index 75287927..8be55d68 100644 --- a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj +++ b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj @@ -55,6 +55,9 @@ + + + @@ -76,6 +79,15 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + PreserveNewest diff --git a/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/FirstStagePlan.cs b/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/FirstStagePlan.cs new file mode 100644 index 00000000..6b4bb672 --- /dev/null +++ b/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/FirstStagePlan.cs @@ -0,0 +1,32 @@ +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("contain_multiple_steps")] + public bool ContainMultipleSteps { get; set; } = false; + + [JsonPropertyName("related_tables")] + public string[] Tables { 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}"; + } +} diff --git a/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/FirstStagePlanParameter.cs b/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/FirstStagePlanParameter.cs new file mode 100644 index 00000000..7bececc6 --- /dev/null +++ b/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/FirstStagePlanParameter.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +public class FirstStagePlanParameter +{ + [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 $"INPUTS:\r\n{JsonSerializer.Serialize(Parameters)}\r\n\r\nOUTPUTS:\r\n{JsonSerializer.Serialize(Results)}"; + } +} \ No newline at end of file diff --git a/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/SecondStagePlan.cs b/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/SecondStagePlan.cs new file mode 100644 index 00000000..f180c043 --- /dev/null +++ b/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/SecondStagePlan.cs @@ -0,0 +1,21 @@ +using System.Text.Json.Serialization; + +namespace BotSharp.Core.Routing.Planning; + +public class SecondStagePlan +{ + [JsonPropertyName("related_tables")] + public string[] Tables { get; set; } = new string[0]; + + [JsonPropertyName("description")] + public string Description { get; set; } = ""; + + [JsonPropertyName("tool_name")] + public string Tool { get; set; } = ""; + + [JsonPropertyName("input_args")] + public JsonDocument[] Parameters { get; set; } = new JsonDocument[0]; + + [JsonPropertyName("output_results")] + public string[] Results { get; set; } = new string[0]; +} diff --git a/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/SecondStagePlanParameter.cs b/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/SecondStagePlanParameter.cs new file mode 100644 index 00000000..1d043740 --- /dev/null +++ b/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/SecondStagePlanParameter.cs @@ -0,0 +1,4 @@ +public class SecondStagePlanParameter : FirstStagePlanParameter +{ + +} diff --git a/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/TwoStagePlanner.FirstStage.cs b/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/TwoStagePlanner.FirstStage.cs new file mode 100644 index 00000000..be01cb59 --- /dev/null +++ b/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/TwoStagePlanner.FirstStage.cs @@ -0,0 +1,82 @@ +using BotSharp.Abstraction.Agents.Models; +using BotSharp.Abstraction.MLTasks; +using BotSharp.Abstraction.Templating; + +namespace BotSharp.Core.Routing.Planning; + +public partial class TwoStagePlanner +{ + private async Task GetFirstStagePlanAsync(Agent router, string messageId, List dialogs) + { + var firstStagePlanPrompt = await GetFirstStagePlanPrompt(router); + + var plan = new FirstStagePlan[0]; + + var llmProviderService = _services.GetRequiredService(); + var model = llmProviderService.GetProviderModel("azure-openai", "gpt-4"); + + // chat completion + var completion = CompletionProvider.GetChatCompletion(_services, + provider: "azure-openai", + model: model.Name); + + string text = string.Empty; + + try + { + var response = await completion.GetChatCompletions(new Agent + { + Id = router.Id, + Name = nameof(TwoStagePlanner), + Instruction = firstStagePlanPrompt + }, dialogs); + + text = response.Content; + plan = response.Content.JsonArrayContent(); + } + catch (Exception ex) + { + _logger.LogError($"{ex.Message}: {text}"); + } + + return plan; + } + + private async Task GetFirstStagePlanPrompt(Agent router) + { + var template = router.Templates.First(x => x.Name == "planner_prompt.two_stage.1st.plan").Content; + var responseFormat = JsonSerializer.Serialize(new FirstStagePlan + { + Parameters = new JsonDocument[]{ JsonDocument.Parse("{}") }, + Results = new string[] { "" } + }); + + var relevantKnowledges = new List(); + var hooks = _services.GetServices(); + foreach (var hook in hooks) + { + var k = await hook.GetRelevantKnowledges(); + relevantKnowledges.AddRange(k); + } + + var render = _services.GetRequiredService(); + return render.Render(template, new Dictionary + { + { "response_format", responseFormat }, + { "relevant_knowledges", relevantKnowledges.ToArray() } + }); + } + + private string GetFirstStageNextPrompt(Agent router) + { + var template = router.Templates.First(x => x.Name == "planner_prompt.first_stage.next").Content; + var responseFormat = JsonSerializer.Serialize(new FirstStagePlan + { + }); + var render = _services.GetRequiredService(); + return render.Render(template, new Dictionary + { + { "response_format", responseFormat }, + }); + } +} diff --git a/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/TwoStagePlanner.GetContext.cs b/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/TwoStagePlanner.GetContext.cs new file mode 100644 index 00000000..998bcd91 --- /dev/null +++ b/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/TwoStagePlanner.GetContext.cs @@ -0,0 +1,14 @@ +namespace BotSharp.Core.Routing.Planning; + +public partial class TwoStagePlanner +{ + public string GetContext() + { + var content = ""; + foreach (var c in _executionContext) + { + content += $"* {c}\r\n"; + } + return content; + } +} diff --git a/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/TwoStagePlanner.SecondStage.cs b/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/TwoStagePlanner.SecondStage.cs new file mode 100644 index 00000000..31ad6608 --- /dev/null +++ b/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/TwoStagePlanner.SecondStage.cs @@ -0,0 +1,83 @@ +using BotSharp.Abstraction.Agents.Models; +using BotSharp.Abstraction.MLTasks; +using BotSharp.Abstraction.Templating; + +namespace BotSharp.Core.Routing.Planning; + +public partial class TwoStagePlanner +{ + private async Task GetSecondStagePlanAsync(Agent router, string messageId, FirstStagePlan plan1st, List dialogs) + { + var secondStagePrompt = GetSecondStagePlanPrompt(router, plan1st); + var firstStageSystemPrompt = await GetFirstStagePlanPrompt(router); + + var plan = new SecondStagePlan[0]; + + var llmProviderService = _services.GetRequiredService(); + var model = llmProviderService.GetProviderModel("azure-openai", "gpt-4"); + + // chat completion + var completion = CompletionProvider.GetChatCompletion(_services, + provider: "azure-openai", + model: model.Name); + + string text = string.Empty; + + var conversations = dialogs.Where(x => x.Role != AgentRole.Function).ToList(); + conversations.Add(new RoleDialogModel(AgentRole.User, secondStagePrompt) + { + CurrentAgentId = router.Id, + MessageId = messageId, + }); + + try + { + var response = await completion.GetChatCompletions(new Agent + { + Id = router.Id, + Name = nameof(TwoStagePlanner), + Instruction = firstStageSystemPrompt + }, conversations); + + text = response.Content; + plan = response.Content.JsonArrayContent(); + } + catch (Exception ex) + { + _logger.LogError($"{ex.Message}: {text}"); + } + + return plan; + } + + private string GetSecondStageTaskPrompt(Agent router, SecondStagePlan plan) + { + var template = router.Templates.First(x => x.Name == "planner_prompt.two_stage.2nd.task").Content; + var render = _services.GetRequiredService(); + return render.Render(template, new Dictionary + { + { "task_description", plan.Description }, + { "related_tables", plan.Tables }, + { "input_arguments", JsonSerializer.Serialize(plan.Parameters) }, + { "output_results", JsonSerializer.Serialize(plan.Results) }, + }); + } + + private string GetSecondStagePlanPrompt(Agent router, FirstStagePlan plan) + { + var template = router.Templates.First(x => x.Name == "planner_prompt.two_stage.2nd.plan").Content; + var responseFormat = JsonSerializer.Serialize(new SecondStagePlan + { + Tool = "tool name if task solution provided", + Parameters = new JsonDocument[] { JsonDocument.Parse("{}") }, + Results = new string[] { "" } + }); + var context = GetContext(); + var render = _services.GetRequiredService(); + return render.Render(template, new Dictionary + { + { "task_description", plan.Task }, + { "response_format", responseFormat } + }); + } +} diff --git a/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/TwoStagePlanner.cs b/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/TwoStagePlanner.cs new file mode 100644 index 00000000..5688fce4 --- /dev/null +++ b/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/TwoStagePlanner.cs @@ -0,0 +1,170 @@ +using BotSharp.Abstraction.Agents.Models; +using BotSharp.Abstraction.Functions.Models; +using BotSharp.Abstraction.Routing; +using BotSharp.Abstraction.Routing.Models; +using BotSharp.Abstraction.Routing.Planning; +using System.IO; + +namespace BotSharp.Core.Routing.Planning; + +public partial class TwoStagePlanner : IPlaner +{ + private readonly IServiceProvider _services; + private readonly ILogger _logger; + public int MaxLoopCount => 100; + private bool _isTaskCompleted; + private string _md5; + + private Queue _plan1st = new Queue(); + private Queue _plan2nd = new Queue(); + + private List _executionContext = new List(); + + public TwoStagePlanner(IServiceProvider services, ILogger logger) + { + _services = services; + _logger = logger; + } + + public async Task GetNextInstruction(Agent router, string messageId, List dialogs) + { + var tempDir = Path.Combine(Path.GetTempPath(), "botsharp", "cache"); + if (_plan1st.IsNullOrEmpty() && _plan2nd.IsNullOrEmpty()) + { + Directory.CreateDirectory(tempDir); + _md5 = Utilities.HashText(string.Join(".", dialogs.Where(x => x.Role == AgentRole.User)), "botsharp"); + var filePath = Path.Combine(tempDir, $"{_md5}-1st.json"); + FirstStagePlan[] items = new FirstStagePlan[0]; + if (File.Exists(filePath)) + { + var cache = File.ReadAllText(filePath); + items = JsonSerializer.Deserialize(cache); + } + else + { + items = await GetFirstStagePlanAsync(router, messageId, dialogs); + + var cache = JsonSerializer.Serialize(items); + File.WriteAllText(filePath, cache); + } + + foreach (var item in items) + { + _plan1st.Enqueue(item); + }; + } + + // Get Second Stage Plan + if (_plan2nd.IsNullOrEmpty()) + { + var plan1 = _plan1st.Dequeue(); + + if (plan1.ContainMultipleSteps) + { + var filePath = Path.Combine(tempDir, $"{_md5}-2nd-{plan1.Step}.json"); + SecondStagePlan[] items = new SecondStagePlan[0]; + if (File.Exists(filePath)) + { + var cache = File.ReadAllText(filePath); + items = JsonSerializer.Deserialize(cache); + } + else + { + items = await GetSecondStagePlanAsync(router, messageId, plan1, dialogs); + + var cache = JsonSerializer.Serialize(items); + File.WriteAllText(filePath, cache); + } + + foreach (var item in items) + { + _plan2nd.Enqueue(item); + } + } + else + { + _plan2nd.Enqueue(new SecondStagePlan + { + Description = plan1.Task, + Tables = plan1.Tables, + Parameters = plan1.Parameters, + Results = plan1.Results, + }); + } + } + + var plan2 = _plan2nd.Dequeue(); + + var secondStagePrompt = GetSecondStageTaskPrompt(router, plan2); + var inst = new FunctionCallFromLlm + { + AgentName = "SQL Driver", + Response = secondStagePrompt, + Function = "route_to_agent" + }; + + inst.HandleDialogsByPlanner = true; + _isTaskCompleted = _plan1st.IsNullOrEmpty() && _plan2nd.IsNullOrEmpty(); + + return inst; + } + + public List BeforeHandleContext(FunctionCallFromLlm inst, RoleDialogModel message, List dialogs) + { + var question = inst.Response; + if (_executionContext.Count > 0) + { + var content = GetContext(); + question = $"CONTEXT:\r\n{content}\r\n" + inst.Response; + } + else + { + question = $"CONTEXT:\r\n{question}"; + } + + var taskAgentDialogs = new List + { + new RoleDialogModel(AgentRole.User, question) + { + MessageId = message.MessageId, + } + }; + + return taskAgentDialogs; + } + + public bool AfterHandleContext(List dialogs, List taskAgentDialogs) + { + dialogs.AddRange(taskAgentDialogs.Skip(1)); + + // Keep execution context + _executionContext.Add(taskAgentDialogs.Last().Content); + + return true; + } + + public async Task AgentExecuting(Agent router, FunctionCallFromLlm inst, RoleDialogModel message, List dialogs) + { + dialogs.Add(new RoleDialogModel(AgentRole.User, inst.Response) + { + MessageId = message.MessageId, + CurrentAgentId = router.Id + }); + return true; + } + + public async Task AgentExecuted(Agent router, FunctionCallFromLlm inst, RoleDialogModel message, List dialogs) + { + var context = _services.GetRequiredService(); + + if (message.StopCompletion || _isTaskCompleted) + { + context.Empty(); + return false; + } + + var routing = _services.GetRequiredService(); + routing.ResetRecursiveCounter(); + return true; + } +} diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingPlugin.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingPlugin.cs index 586a9943..410070d1 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingPlugin.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingPlugin.cs @@ -38,5 +38,6 @@ public class RoutingPlugin : IBotSharpPlugin services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); } } diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.two_stage.1st.plan.liquid b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.two_stage.1st.plan.liquid new file mode 100644 index 00000000..2fc1ffd4 --- /dev/null +++ b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.two_stage.1st.plan.liquid @@ -0,0 +1,15 @@ +You are a Task Planner. you will breakdown user business requirements into small executable sub-tasks. + +Thinking process: +1. Reference to "Task Solutions" if there is relevant solutions; +2. Breakdown task into subtasks. The subtask should contains all needed parameters for subsequent steps. +3. Input argument must reference to corresponding variable name that retrieved by previous steps, variable name must start with '@'; +4. Output all the subtasks as much detail as possible in JSON: {{ response_format }} + +{% if relevant_knowledges != empty -%} +===== +Task Solutions: +{% for k in relevant_knowledges %} +{{ k }} +{% endfor %} +{%- endif %} diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.two_stage.2nd.plan.liquid b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.two_stage.2nd.plan.liquid new file mode 100644 index 00000000..a87b479f --- /dev/null +++ b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.two_stage.2nd.plan.liquid @@ -0,0 +1,6 @@ +Reference to "Task Solutions". Breakdown task into multiple steps. +The step should contains all needed parameters. +The parameters can be extracted from the original task. +Output all the steps as much detail as possible in JSON: [{{ response_format }}] + +TASK: {{ task_description }} \ No newline at end of file diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.two_stage.2nd.task.liquid b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.two_stage.2nd.task.liquid new file mode 100644 index 00000000..0e833d53 --- /dev/null +++ b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.two_stage.2nd.task.liquid @@ -0,0 +1,8 @@ +{{ task_description }} + +{% if related_tables != empty -%} +Relevant tables: +{% for t in related_tables -%} +- {{ t }}{{ "\r\n" }} +{%- endfor %} +{%- endif %} \ No newline at end of file diff --git a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs index 27cff56d..90fbcefa 100644 --- a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs +++ b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs @@ -44,7 +44,7 @@ public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook public override async Task OnMessageReceived(RoleDialogModel message) { var conversationId = _state.GetConversationId(); - var log = $"MessageId: {message.MessageId} ==>\r\n{message.Role}: {message.Content}"; + var log = $"{message.Role}: {message.Content}"; await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", BuildContentLog(conversationId, _user.UserName, log, ContentLogSource.UserInput, message)); } @@ -85,7 +85,6 @@ public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook var conversationId = _state.GetConversationId(); var agent = await _agentService.LoadAgent(message.CurrentAgentId); var log = $"{message.FunctionName}({message.FunctionArgs})\r\n => {message.Content}"; - log += $"\r\n<== MessageId: {message.MessageId}"; await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", BuildContentLog(conversationId, agent?.Name, log, ContentLogSource.FunctionCall, message)); } @@ -130,7 +129,6 @@ public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook var richContent = JsonSerializer.Serialize(message.RichContent, _serializerOptions); log += $"\r\n{richContent}"; } - log += $"\r\n<== MessageId: {message.MessageId}"; await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", BuildContentLog(conv.ConversationId, agent?.Name, log, ContentLogSource.AgentResponse, message)); } diff --git a/src/Plugins/BotSharp.Plugin.Dashboard/BotSharp.Plugin.Dashboard.csproj b/src/Plugins/BotSharp.Plugin.Dashboard/BotSharp.Plugin.Dashboard.csproj index 5736c64f..6a3b789a 100644 --- a/src/Plugins/BotSharp.Plugin.Dashboard/BotSharp.Plugin.Dashboard.csproj +++ b/src/Plugins/BotSharp.Plugin.Dashboard/BotSharp.Plugin.Dashboard.csproj @@ -3,6 +3,10 @@ netstandard2.1 enable + $(LangVersion) + $(BotSharpVersion) + $(GeneratePackageOnBuild) + $(SolutionDir)packages diff --git a/src/Plugins/BotSharp.Plugin.SqlDriver/Models/LookupDictionary.cs b/src/Plugins/BotSharp.Plugin.SqlDriver/Models/LookupDictionary.cs index cf7d6345..4f6b6496 100644 --- a/src/Plugins/BotSharp.Plugin.SqlDriver/Models/LookupDictionary.cs +++ b/src/Plugins/BotSharp.Plugin.SqlDriver/Models/LookupDictionary.cs @@ -10,6 +10,9 @@ public class LookupDictionary [JsonPropertyName("keyword")] public string Keyword { get; set; } + [JsonPropertyName("reason")] + public string Reason { get; set; } + [JsonPropertyName("columns")] public string[] Columns { get; set; } } diff --git a/src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/beda4c12-e1ec-4b4b-b328-3df4a6687c4f/functions.json b/src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/beda4c12-e1ec-4b4b-b328-3df4a6687c4f/functions.json index 85703028..df6e1a4c 100644 --- a/src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/beda4c12-e1ec-4b4b-b328-3df4a6687c4f/functions.json +++ b/src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/beda4c12-e1ec-4b4b-b328-3df4a6687c4f/functions.json @@ -139,6 +139,10 @@ "type": "string", "description": "table name" }, + "reason": { + "type": "string", + "description": "the reason why you need to call lookup_dictionary" + }, "columns": { "type": "array", "description": "columns", @@ -148,7 +152,7 @@ } } }, - "required": [ "table", "columns", "keyword" ] + "required": [ "table", "keyword", "reason", "columns" ] } } ] \ No newline at end of file