From c42af085fbc7c849ba8c70b40178c454fe5175b6 Mon Sep 17 00:00:00 2001 From: Haiping Chen Date: Sat, 27 Jan 2024 08:58:51 -0600 Subject: [PATCH 01/13] Fixed google search in WebDriver #268 --- .gitignore | 6 +++- .../BotSharp.Plugin.KnowledgeBase.csproj | 4 +-- .../BotSharp.Plugin.PaddleSharp.csproj | 12 +++---- .../BotSharp.Plugin.RoutingSpeeder.csproj | 4 +-- .../BotSharp.Plugin.SqlDriver.csproj | 6 ++-- .../BotSharp.Plugin.WeChat.csproj | 4 +-- .../BotSharp.Plugin.WebDriver.csproj | 4 +-- .../PlaywrightDriver/PlaywrightInstance.cs | 5 +++ .../PlaywrightWebDriver.ChangeListValue.cs | 17 +-------- .../PlaywrightWebDriver.InputUserText.cs | 36 ++++++++++++------- .../PlaywrightDriver/PlaywrightWebDriver.cs | 20 +++++++++++ .../LlmContexts/BrowsingContextIn.cs | 3 ++ .../Models/MarkupProperties.cs | 9 +++++ .../WebDriverService.AssembleMarkup.cs | 33 +++++++++++++++++ .../BotSharp.Plugin.WebDriver/Using.cs | 4 ++- .../agent.json | 1 + .../functions.json | 12 ++++--- src/WebStarter/WebStarter.csproj | 2 +- .../BotSharp.Plugin.PizzaBot.csproj | 4 +++ 19 files changed, 134 insertions(+), 52 deletions(-) create mode 100644 src/Plugins/BotSharp.Plugin.WebDriver/Models/MarkupProperties.cs create mode 100644 src/Plugins/BotSharp.Plugin.WebDriver/Services/WebDriverService.AssembleMarkup.cs diff --git a/.gitignore b/.gitignore index cb5e824e..ab28c2e0 100644 --- a/.gitignore +++ b/.gitignore @@ -286,6 +286,10 @@ __pycache__/ /docs/_build *.bin -/src/WebStarter/data/conversations +src/WebStarter/Properties/PublishProfiles +src/WebStarter/Properties/ServiceDependencies XMLs logs +wwwroot +appsettings.Production.json +*.csproj.user \ No newline at end of file diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/BotSharp.Plugin.KnowledgeBase.csproj b/src/Plugins/BotSharp.Plugin.KnowledgeBase/BotSharp.Plugin.KnowledgeBase.csproj index 7f15d294..bb24ad19 100644 --- a/src/Plugins/BotSharp.Plugin.KnowledgeBase/BotSharp.Plugin.KnowledgeBase.csproj +++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/BotSharp.Plugin.KnowledgeBase.csproj @@ -1,4 +1,4 @@ - + netstandard2.1 @@ -35,7 +35,7 @@ - + diff --git a/src/Plugins/BotSharp.Plugin.PaddleSharp/BotSharp.Plugin.PaddleSharp.csproj b/src/Plugins/BotSharp.Plugin.PaddleSharp/BotSharp.Plugin.PaddleSharp.csproj index fe8739a4..6dcaf95e 100644 --- a/src/Plugins/BotSharp.Plugin.PaddleSharp/BotSharp.Plugin.PaddleSharp.csproj +++ b/src/Plugins/BotSharp.Plugin.PaddleSharp/BotSharp.Plugin.PaddleSharp.csproj @@ -1,4 +1,4 @@ - + netstandard2.1 @@ -12,14 +12,14 @@ - - - + + + - + - + diff --git a/src/Plugins/BotSharp.Plugin.RoutingSpeeder/BotSharp.Plugin.RoutingSpeeder.csproj b/src/Plugins/BotSharp.Plugin.RoutingSpeeder/BotSharp.Plugin.RoutingSpeeder.csproj index 4bc9a6af..0dc946cb 100644 --- a/src/Plugins/BotSharp.Plugin.RoutingSpeeder/BotSharp.Plugin.RoutingSpeeder.csproj +++ b/src/Plugins/BotSharp.Plugin.RoutingSpeeder/BotSharp.Plugin.RoutingSpeeder.csproj @@ -1,4 +1,4 @@ - + netstandard2.1 @@ -30,7 +30,7 @@ - + diff --git a/src/Plugins/BotSharp.Plugin.SqlDriver/BotSharp.Plugin.SqlDriver.csproj b/src/Plugins/BotSharp.Plugin.SqlDriver/BotSharp.Plugin.SqlDriver.csproj index 929d4d61..aa5124f8 100644 --- a/src/Plugins/BotSharp.Plugin.SqlDriver/BotSharp.Plugin.SqlDriver.csproj +++ b/src/Plugins/BotSharp.Plugin.SqlDriver/BotSharp.Plugin.SqlDriver.csproj @@ -1,4 +1,4 @@ - + netstandard2.1 @@ -11,8 +11,8 @@ - - + + diff --git a/src/Plugins/BotSharp.Plugin.WeChat/BotSharp.Plugin.WeChat.csproj b/src/Plugins/BotSharp.Plugin.WeChat/BotSharp.Plugin.WeChat.csproj index 1aff09b8..b2c19ae1 100644 --- a/src/Plugins/BotSharp.Plugin.WeChat/BotSharp.Plugin.WeChat.csproj +++ b/src/Plugins/BotSharp.Plugin.WeChat/BotSharp.Plugin.WeChat.csproj @@ -27,8 +27,8 @@ - - + + diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/BotSharp.Plugin.WebDriver.csproj b/src/Plugins/BotSharp.Plugin.WebDriver/BotSharp.Plugin.WebDriver.csproj index 205f32bf..7c4d6a76 100644 --- a/src/Plugins/BotSharp.Plugin.WebDriver/BotSharp.Plugin.WebDriver.csproj +++ b/src/Plugins/BotSharp.Plugin.WebDriver/BotSharp.Plugin.WebDriver.csproj @@ -1,4 +1,4 @@ - + netstandard2.1 @@ -11,7 +11,7 @@ - + diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightInstance.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightInstance.cs index 0df3c6ee..b8e2e5b2 100644 --- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightInstance.cs +++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightInstance.cs @@ -16,6 +16,11 @@ public class PlaywrightInstance : IDisposable { _playwright = await Playwright.CreateAsync(); + /*_browser = await _playwright.Chromium.LaunchPersistentContextAsync(@"C:\Users\haipi\AppData\Local\Google\Chrome\User Data", new BrowserTypeLaunchPersistentContextOptions + { + Headless = false, + Channel = "chrome", + });*/ _browser = await _playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions { Headless = false, diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.ChangeListValue.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.ChangeListValue.cs index d3cb5c7d..7df51ec5 100644 --- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.ChangeListValue.cs +++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.ChangeListValue.cs @@ -58,22 +58,7 @@ public partial class PlaywrightWebDriver var driverService = _services.GetRequiredService(); var htmlElementContextOut = await driverService.LocateElement(agent, string.Join("", str), context.ElementName, messageId); - - if (htmlElementContextOut.Index < 0) - { - throw new Exception($"Can't locate the web element {context.ElementName}."); - } - - ILocator element = default; - if (!string.IsNullOrEmpty(htmlElementContextOut.ElementId)) - { - // await _instance.Page.WaitForSelectorAsync($"#{htmlElementContextOut.ElementId}", new PageWaitForSelectorOptions { Timeout = 3 }); - element = _instance.Page.Locator($"#{htmlElementContextOut.ElementId}"); - } - else - { - element = _instance.Page.Locator(htmlElementContextOut.TagName).Nth(htmlElementContextOut.Index); - } + ILocator element = Locator(htmlElementContextOut); try { diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.InputUserText.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.InputUserText.cs index 80c288a5..630c7d13 100644 --- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.InputUserText.cs +++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.InputUserText.cs @@ -1,11 +1,11 @@ -using BotSharp.Plugin.WebDriver.Services; - namespace BotSharp.Plugin.WebDriver.Drivers.PlaywrightDriver; public partial class PlaywrightWebDriver { public async Task InputUserText(Agent agent, BrowsingContextIn context, string messageId) { + var driverService = _services.GetRequiredService(); + // Retrieve the page raw html and infer the element path var body = await _instance.Page.QuerySelectorAsync("body"); @@ -14,32 +14,44 @@ public partial class PlaywrightWebDriver foreach (var input in inputs) { var text = await input.TextContentAsync(); + var id = await input.GetAttributeAsync("id"); var name = await input.GetAttributeAsync("name"); var type = await input.GetAttributeAsync("type"); - str.Add($"{text}"); + str.Add(driverService.AssembleMarkup("input", new MarkupProperties + { + Id = id, + Name = name, + Type = type, + Text = text + })); } inputs = await body.QuerySelectorAllAsync("textarea"); foreach (var input in inputs) { var text = await input.TextContentAsync(); + var id = await input.GetAttributeAsync("id"); var name = await input.GetAttributeAsync("name"); var type = await input.GetAttributeAsync("type"); - str.Add($""); + str.Add(driverService.AssembleMarkup("textarea", new MarkupProperties + { + Id = id, + Name = name, + Type = type, + Text = text + })); } - - var driverService = _services.GetRequiredService(); + var htmlElementContextOut = await driverService.LocateElement(agent, string.Join("", str), context.ElementName, messageId); + ILocator element = Locator(htmlElementContextOut); - if (htmlElementContextOut.Index < 0) - { - throw new Exception($"Can't locate the web element {context.ElementName}."); - } - - var element = _instance.Page.Locator(htmlElementContextOut.TagName).Nth(htmlElementContextOut.Index); try { await element.FillAsync(context.InputText); + if (context.PressEnter) + { + await element.PressAsync("Enter"); + } } catch (Exception ex) { diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.cs index abfc300f..c513bf1c 100644 --- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.cs +++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.cs @@ -11,4 +11,24 @@ public partial class PlaywrightWebDriver _services = services; _instance = instance; } + + private ILocator Locator(HtmlElementContextOut context) + { + ILocator element = default; + if (!string.IsNullOrEmpty(context.ElementId)) + { + // await _instance.Page.WaitForSelectorAsync($"#{htmlElementContextOut.ElementId}", new PageWaitForSelectorOptions { Timeout = 3 }); + element = _instance.Page.Locator($"#{context.ElementId}"); + } + else + { + if (context.Index < 0) + { + throw new Exception($"Can't locate the web element {context.Index}."); + } + element = _instance.Page.Locator(context.TagName).Nth(context.Index); + } + + return element; + } } diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/LlmContexts/BrowsingContextIn.cs b/src/Plugins/BotSharp.Plugin.WebDriver/LlmContexts/BrowsingContextIn.cs index 73c2753b..efd327eb 100644 --- a/src/Plugins/BotSharp.Plugin.WebDriver/LlmContexts/BrowsingContextIn.cs +++ b/src/Plugins/BotSharp.Plugin.WebDriver/LlmContexts/BrowsingContextIn.cs @@ -13,6 +13,9 @@ public class BrowsingContextIn [JsonPropertyName("input_text")] public string? InputText { get; set; } + [JsonPropertyName("press_enter")] + public bool PressEnter { get; set; } + [JsonPropertyName("update_value")] public string? UpdateValue { get; set; } diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Models/MarkupProperties.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Models/MarkupProperties.cs new file mode 100644 index 00000000..5b7071e7 --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.WebDriver/Models/MarkupProperties.cs @@ -0,0 +1,9 @@ +namespace BotSharp.Plugin.WebDriver.Models; + +internal class MarkupProperties +{ + public string Id { get; set; } + public string Name { get; set; } + public string Type { get; set; } + public string Text { get; set; } +} diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Services/WebDriverService.AssembleMarkup.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Services/WebDriverService.AssembleMarkup.cs new file mode 100644 index 00000000..14eb5c6c --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.WebDriver/Services/WebDriverService.AssembleMarkup.cs @@ -0,0 +1,33 @@ +using BotSharp.Plugin.WebDriver.LlmContexts; + +namespace BotSharp.Plugin.WebDriver.Services; + +public partial class WebDriverService +{ + internal string AssembleMarkup(string tagName, MarkupProperties properties) + { + var html = $"<{tagName}"; + if (!string.IsNullOrEmpty(properties.Id)) + { + html += $" id=\"{properties.Id}\""; + } + + if (!string.IsNullOrEmpty(properties.Name)) + { + html += $" name=\"{properties.Name}\""; + } + + if (!string.IsNullOrEmpty(properties.Type)) + { + html += $" type=\"{properties.Type}\""; + } + + if (!string.IsNullOrEmpty(properties.Text)) + { + html += $">{properties.Text}"; + return html; + } + + return html + $">"; + } +} diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Using.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Using.cs index ca78d12b..9a0e6ecc 100644 --- a/src/Plugins/BotSharp.Plugin.WebDriver/Using.cs +++ b/src/Plugins/BotSharp.Plugin.WebDriver/Using.cs @@ -14,4 +14,6 @@ global using BotSharp.Abstraction.Templating; global using BotSharp.Plugin.WebDriver.LlmContexts; global using Microsoft.Extensions.DependencyInjection; global using System.Linq; -global using BotSharp.Abstraction.Utilities; \ No newline at end of file +global using BotSharp.Abstraction.Utilities; +global using BotSharp.Plugin.WebDriver.Models; +global using BotSharp.Plugin.WebDriver.Services; \ No newline at end of file diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/agent.json b/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/agent.json index e06597f9..6ed53683 100644 --- a/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/agent.json +++ b/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/agent.json @@ -6,6 +6,7 @@ "createdDateTime": "2024-01-02T00:00:00Z", "updatedDateTime": "2024-01-02T00:00:00Z", "isPublic": true, + "profiles": [ "default" ], "llmConfig": { "max_recursion_depth": 10 } diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/functions.json b/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/functions.json index 49e4770b..87723841 100644 --- a/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/functions.json +++ b/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/functions.json @@ -51,10 +51,14 @@ "type": "string", "description": "the html input box element name." }, - "input_text": { - "type": "string", - "description": "non-sensitive text user provided." - } + "input_text": { + "type": "string", + "description": "non-sensitive text user provided." + }, + "press_enter": { + "type": "boolean", + "description": "whether to press ENTER" + } }, "required": ["element_name", "input_text"] } diff --git a/src/WebStarter/WebStarter.csproj b/src/WebStarter/WebStarter.csproj index a4d90290..d4e6e764 100644 --- a/src/WebStarter/WebStarter.csproj +++ b/src/WebStarter/WebStarter.csproj @@ -1,4 +1,4 @@ - + net6.0 diff --git a/tests/BotSharp.Plugin.PizzaBot/BotSharp.Plugin.PizzaBot.csproj b/tests/BotSharp.Plugin.PizzaBot/BotSharp.Plugin.PizzaBot.csproj index 77ba7e96..415fcd70 100644 --- a/tests/BotSharp.Plugin.PizzaBot/BotSharp.Plugin.PizzaBot.csproj +++ b/tests/BotSharp.Plugin.PizzaBot/BotSharp.Plugin.PizzaBot.csproj @@ -105,4 +105,8 @@ + + + + From 2445cb31e0486191f1f97a7c0d3ad05ab7acba53 Mon Sep 17 00:00:00 2001 From: Haiping Chen Date: Sat, 27 Jan 2024 09:20:02 -0600 Subject: [PATCH 02/13] #268 --- .../PlaywrightWebDriver.ChangeListValue.cs | 5 +++- .../PlaywrightWebDriver.ClickButton.cs | 27 ++++++++++--------- .../PlaywrightWebDriver.InputUserText.cs | 5 +++- .../Models/MarkupProperties.cs | 8 +++--- 4 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.ChangeListValue.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.ChangeListValue.cs index 7df51ec5..75e8ad6a 100644 --- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.ChangeListValue.cs +++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.ChangeListValue.cs @@ -57,7 +57,10 @@ public partial class PlaywrightWebDriver } var driverService = _services.GetRequiredService(); - var htmlElementContextOut = await driverService.LocateElement(agent, string.Join("", str), context.ElementName, messageId); + var htmlElementContextOut = await driverService.LocateElement(agent, + string.Join("", str), + context.ElementName, + messageId); ILocator element = Locator(htmlElementContextOut); try diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.ClickButton.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.ClickButton.cs index d7fbed3d..82e9683d 100644 --- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.ClickButton.cs +++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.ClickButton.cs @@ -1,11 +1,11 @@ -using BotSharp.Plugin.WebDriver.Services; - namespace BotSharp.Plugin.WebDriver.Drivers.PlaywrightDriver; public partial class PlaywrightWebDriver { public async Task ClickElement(Agent agent, BrowsingContextIn context, string messageId) { + var driverService = _services.GetRequiredService(); + // Retrieve the page raw html and infer the element path var body = await _instance.Page.QuerySelectorAsync("body"); @@ -23,18 +23,19 @@ public partial class PlaywrightWebDriver var text = await btn.TextContentAsync(); var name = await btn.GetAttributeAsync("name"); var id = await btn.GetAttributeAsync("id"); - str.Add($""); + str.Add(driverService.AssembleMarkup("button", new MarkupProperties + { + Id = id, + Name = name, + Text = text + })); } - var driverService = _services.GetRequiredService(); - var htmlElementContextOut = await driverService.LocateElement(agent, string.Join("", str), context.ElementName, messageId); - - var tags = await _instance.Page.QuerySelectorAllAsync(htmlElementContextOut.TagName); - var button = tags[htmlElementContextOut.Index]; - if (button.AsElement() == null) - { - throw new Exception($"Can't find web element {context.ElementName}"); - } - await button.ClickAsync(); + var htmlElementContextOut = await driverService.LocateElement(agent, + string.Join("", str), + context.ElementName, + messageId); + ILocator element = Locator(htmlElementContextOut); + await element.ClickAsync(); } } diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.InputUserText.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.InputUserText.cs index 630c7d13..5362602f 100644 --- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.InputUserText.cs +++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.InputUserText.cs @@ -42,7 +42,10 @@ public partial class PlaywrightWebDriver })); } - var htmlElementContextOut = await driverService.LocateElement(agent, string.Join("", str), context.ElementName, messageId); + var htmlElementContextOut = await driverService.LocateElement(agent, + string.Join("", str), + context.ElementName, + messageId); ILocator element = Locator(htmlElementContextOut); try diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Models/MarkupProperties.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Models/MarkupProperties.cs index 5b7071e7..410bf50c 100644 --- a/src/Plugins/BotSharp.Plugin.WebDriver/Models/MarkupProperties.cs +++ b/src/Plugins/BotSharp.Plugin.WebDriver/Models/MarkupProperties.cs @@ -2,8 +2,8 @@ namespace BotSharp.Plugin.WebDriver.Models; internal class MarkupProperties { - public string Id { get; set; } - public string Name { get; set; } - public string Type { get; set; } - public string Text { get; set; } + public string? Id { get; set; } + public string? Name { get; set; } + public string? Type { get; set; } + public string? Text { get; set; } } From 2b6c2353b671ada3f951232ebb2d803ed2186a96 Mon Sep 17 00:00:00 2001 From: Haiping Chen Date: Sat, 27 Jan 2024 19:02:33 -0600 Subject: [PATCH 03/13] Add pizza bot router. --- README.md | 1 + .../screenshots/agent-builder-agents.png | Bin 127348 -> 109574 bytes .../Agents/Models/Agent.cs | 3 -- .../Agents/Services/AgentService.GetAgents.cs | 8 ----- .../BotSharp.Core/BotSharp.Core.csproj | 18 +++++++++- .../agent.json | 5 ++- .../agent.json | 11 ++++++ .../instruction.liquid | 0 .../templates/instruction.executor.liquid | 0 .../templates/instruction.reviewer.liquid | 0 .../Controllers/AgentController.cs | 22 +++++++++--- .../Controllers/ConversationController.cs | 4 +++ .../ViewModels/Agents/AgentViewModel.cs | 1 - .../Conversations/ConversationViewModel.cs | 6 ++-- .../agent.json | 8 ++++- .../BotSharp.Plugin.PizzaBot.csproj | 32 +++++------------- .../PizzaBotPlugin.cs | 1 + .../agent.json | 18 ++++++++++ .../templates/task.place_pizza_order.liquid | 0 .../agent.json | 2 +- .../agent.json | 2 +- .../agent.json | 10 ------ .../agent.json | 3 +- 23 files changed, 94 insertions(+), 61 deletions(-) create mode 100644 src/Infrastructure/BotSharp.Core/data/agents/dfd9b46d-d00c-40af-8a75-3fbdc2b89869/agent.json rename {tests/BotSharp.Plugin.PizzaBot => src/Infrastructure/BotSharp.Core}/data/agents/dfd9b46d-d00c-40af-8a75-3fbdc2b89869/instruction.liquid (100%) rename {tests/BotSharp.Plugin.PizzaBot => src/Infrastructure/BotSharp.Core}/data/agents/dfd9b46d-d00c-40af-8a75-3fbdc2b89869/templates/instruction.executor.liquid (100%) rename {tests/BotSharp.Plugin.PizzaBot => src/Infrastructure/BotSharp.Core}/data/agents/dfd9b46d-d00c-40af-8a75-3fbdc2b89869/templates/instruction.reviewer.liquid (100%) create mode 100644 tests/BotSharp.Plugin.PizzaBot/data/agents/8970b1e5-d260-4e2c-90b1-f1415a257c18/agent.json rename tests/BotSharp.Plugin.PizzaBot/data/agents/{dfd9b46d-d00c-40af-8a75-3fbdc2b89869 => 8970b1e5-d260-4e2c-90b1-f1415a257c18}/templates/task.place_pizza_order.liquid (100%) delete mode 100644 tests/BotSharp.Plugin.PizzaBot/data/agents/dfd9b46d-d00c-40af-8a75-3fbdc2b89869/agent.json diff --git a/README.md b/README.md index 12541290..aa892ce0 100644 --- a/README.md +++ b/README.md @@ -103,6 +103,7 @@ BotSharp uses component design, the kernel is kept to a minimum, and business fu #### Tools - BotSharp.Plugin.RoutingSpeeder +- BotSharp.Plugin.WebDriver - BotSharp.Plugin.PizzaBot #### UIs diff --git a/docs/static/screenshots/agent-builder-agents.png b/docs/static/screenshots/agent-builder-agents.png index 5f8643a9f2cbfc4aa557fe7d4ec270b0308b584f..db66149426975cf30dea04b73cbc781e56ff7070 100644 GIT binary patch literal 109574 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%0A&Jt$)|KXO%=m5pN8o0ht(lu}U+Ky4IS(*jm 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 diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs index a36ccc26..6b18b652 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs @@ -62,9 +62,6 @@ public class Agent public bool IsPublic { get; set; } - [JsonIgnore] - public bool IsHost { get; set; } - [JsonIgnore] public PluginDef Plugin { get; set; } diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs index 15be18f9..6f840edb 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs @@ -13,20 +13,12 @@ public partial class AgentService { var agents = _db.GetAgents(filter); - // Set IsRouter var routeSetting = _services.GetRequiredService(); foreach (var agent in agents) { agent.Plugin = GetPlugin(agent.Id); } - // Set IsHost - var agentSetting = _services.GetRequiredService(); - foreach (var agent in agents) - { - agent.IsHost = agentSetting.HostAgentId == agent.Id; - } - agents = agents.Where(x => x.Installed).ToList(); var pager = filter?.Pager ?? new Pagination(); return new PagedItems diff --git a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj index fadeacd1..8f706a7b 100644 --- a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj +++ b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj @@ -1,4 +1,4 @@ - + netstandard2.1 @@ -55,6 +55,10 @@ + + + + @@ -86,6 +90,18 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + PreserveNewest diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01e2fc5c-2c89-4ec7-8470-7688608b496c/agent.json b/src/Infrastructure/BotSharp.Core/data/agents/01e2fc5c-2c89-4ec7-8470-7688608b496c/agent.json index b17531f4..d75a4483 100644 --- a/src/Infrastructure/BotSharp.Core/data/agents/01e2fc5c-2c89-4ec7-8470-7688608b496c/agent.json +++ b/src/Infrastructure/BotSharp.Core/data/agents/01e2fc5c-2c89-4ec7-8470-7688608b496c/agent.json @@ -5,8 +5,7 @@ "type": "task", "createdDateTime": "2024-01-15T10:39:32Z", "updatedDateTime": "2024-01-15T14:39:32Z", - "iconUrl": "/images/users/bot.png", + "iconUrl": "/images/logo.png", "disabled": false, - "isPublic": true, - "profiles": [ "standalone" ] + "isPublic": true } \ No newline at end of file diff --git a/src/Infrastructure/BotSharp.Core/data/agents/dfd9b46d-d00c-40af-8a75-3fbdc2b89869/agent.json b/src/Infrastructure/BotSharp.Core/data/agents/dfd9b46d-d00c-40af-8a75-3fbdc2b89869/agent.json new file mode 100644 index 00000000..e9bac6f5 --- /dev/null +++ b/src/Infrastructure/BotSharp.Core/data/agents/dfd9b46d-d00c-40af-8a75-3fbdc2b89869/agent.json @@ -0,0 +1,11 @@ +{ + "id": "dfd9b46d-d00c-40af-8a75-3fbdc2b89869", + "name": "Evaluator", + "description": "Evaluate the performance of the LLM agents", + "createdDateTime": "2023-08-18T00:00:00Z", + "updatedDateTime": "2023-08-18T00:00:00Z", + "disabled": true, + "llmConfig": { + "model": "gpt-35-turbo-instruct" + } +} \ No newline at end of file diff --git a/tests/BotSharp.Plugin.PizzaBot/data/agents/dfd9b46d-d00c-40af-8a75-3fbdc2b89869/instruction.liquid b/src/Infrastructure/BotSharp.Core/data/agents/dfd9b46d-d00c-40af-8a75-3fbdc2b89869/instruction.liquid similarity index 100% rename from tests/BotSharp.Plugin.PizzaBot/data/agents/dfd9b46d-d00c-40af-8a75-3fbdc2b89869/instruction.liquid rename to src/Infrastructure/BotSharp.Core/data/agents/dfd9b46d-d00c-40af-8a75-3fbdc2b89869/instruction.liquid diff --git a/tests/BotSharp.Plugin.PizzaBot/data/agents/dfd9b46d-d00c-40af-8a75-3fbdc2b89869/templates/instruction.executor.liquid b/src/Infrastructure/BotSharp.Core/data/agents/dfd9b46d-d00c-40af-8a75-3fbdc2b89869/templates/instruction.executor.liquid similarity index 100% rename from tests/BotSharp.Plugin.PizzaBot/data/agents/dfd9b46d-d00c-40af-8a75-3fbdc2b89869/templates/instruction.executor.liquid rename to src/Infrastructure/BotSharp.Core/data/agents/dfd9b46d-d00c-40af-8a75-3fbdc2b89869/templates/instruction.executor.liquid diff --git a/tests/BotSharp.Plugin.PizzaBot/data/agents/dfd9b46d-d00c-40af-8a75-3fbdc2b89869/templates/instruction.reviewer.liquid b/src/Infrastructure/BotSharp.Core/data/agents/dfd9b46d-d00c-40af-8a75-3fbdc2b89869/templates/instruction.reviewer.liquid similarity index 100% rename from tests/BotSharp.Plugin.PizzaBot/data/agents/dfd9b46d-d00c-40af-8a75-3fbdc2b89869/templates/instruction.reviewer.liquid rename to src/Infrastructure/BotSharp.Core/data/agents/dfd9b46d-d00c-40af-8a75-3fbdc2b89869/templates/instruction.reviewer.liquid diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs index 9183be01..35873b9e 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs @@ -25,23 +25,37 @@ public class AgentController : ControllerBase [HttpGet("/agent/{id}")] public async Task GetAgent([FromRoute] string id) { - var agent = await _agentService.GetAgent(id); - return AgentViewModel.FromAgent(agent); + var agents = await GetAgents(new AgentFilter + { + AgentIds = new List { id } + }); + return agents.Items.First(); } - + [HttpGet("/agents")] public async Task> GetAgents([FromQuery] AgentFilter filter) { + var agentSetting = _services.GetRequiredService(); var pagedAgents = await _agentService.GetAgents(filter); + + // prerender agent var items = new List(); foreach (var agent in pagedAgents.Items) { var renderedAgent = await _agentService.LoadAgent(agent.Id); items.Add(renderedAgent); } + + // Set IsHost + var agents = items.Select(x => AgentViewModel.FromAgent(x)).ToList(); + foreach(var agent in agents) + { + agent.IsHost = agentSetting.HostAgentId == agent.Id; + } + return new PagedItems { - Items = items.Select(x => AgentViewModel.FromAgent(x)).ToList(), + Items = agents, Count = pagedAgents.Count }; } diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs index 58378ba5..af921621 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs @@ -37,6 +37,7 @@ public class ConversationController : ControllerBase var conversations = await service.GetConversations(filter); var userService = _services.GetRequiredService(); + var agentService = _services.GetRequiredService(); var list = conversations.Items .Select(x => ConversationViewModel.FromSession(x)) .ToList(); @@ -45,6 +46,9 @@ public class ConversationController : ControllerBase { var user = await userService.GetUser(item.User.Id); item.User = UserViewModel.FromUser(user); + + var agent = await agentService.GetAgent(item.AgentId); + item.AgentName = agent.Name; } return new PagedItems diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs index 3c35b3af..536f5b5d 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs @@ -62,7 +62,6 @@ public class AgentViewModel Responses = agent.Responses, Samples = agent.Samples, IsPublic= agent.IsPublic, - IsHost = agent.IsHost, Disabled = agent.Disabled, IconUrl = agent.IconUrl, Profiles = agent.Profiles ?? new List(), diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/ConversationViewModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/ConversationViewModel.cs index a863763e..0823023d 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/ConversationViewModel.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/ConversationViewModel.cs @@ -9,13 +9,13 @@ public class ConversationViewModel [JsonPropertyName("agent_id")] public string AgentId { get; set; } + [JsonPropertyName("agent_name")] + public string AgentName { get; set; } + public string Title { get; set; } = string.Empty; public UserViewModel User { get; set; } = new UserViewModel(); - [JsonPropertyName("unread_msg_count")] - public int UnreadMsgCount { get; set; } - public string Event { get; set; } public string Channel { get; set; } = ConversationChannel.OpenAPI; diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/agent.json b/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/agent.json index 6ed53683..290a88d0 100644 --- a/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/agent.json +++ b/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/agent.json @@ -9,5 +9,11 @@ "profiles": [ "default" ], "llmConfig": { "max_recursion_depth": 10 - } + }, + "routingRules": [ + { + "type": "fallback", + "redirectTo": "01e2fc5c-2c89-4ec7-8470-7688608b496c" + } + ] } \ No newline at end of file diff --git a/tests/BotSharp.Plugin.PizzaBot/BotSharp.Plugin.PizzaBot.csproj b/tests/BotSharp.Plugin.PizzaBot/BotSharp.Plugin.PizzaBot.csproj index 415fcd70..4328eb4d 100644 --- a/tests/BotSharp.Plugin.PizzaBot/BotSharp.Plugin.PizzaBot.csproj +++ b/tests/BotSharp.Plugin.PizzaBot/BotSharp.Plugin.PizzaBot.csproj @@ -20,6 +20,8 @@ + + @@ -27,11 +29,6 @@ - - - - - @@ -42,6 +39,12 @@ + + PreserveNewest + + + PreserveNewest + PreserveNewest @@ -63,21 +66,6 @@ PreserveNewest - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - PreserveNewest @@ -105,8 +93,4 @@ - - - - diff --git a/tests/BotSharp.Plugin.PizzaBot/PizzaBotPlugin.cs b/tests/BotSharp.Plugin.PizzaBot/PizzaBotPlugin.cs index d3d4c3a6..6fa37ce6 100644 --- a/tests/BotSharp.Plugin.PizzaBot/PizzaBotPlugin.cs +++ b/tests/BotSharp.Plugin.PizzaBot/PizzaBotPlugin.cs @@ -11,6 +11,7 @@ public class PizzaBotPlugin : IBotSharpPlugin public string IconUrl => "https://cdn-icons-png.flaticon.com/512/6978/6978255.png"; public string[] AgentIds => new[] { + "8970b1e5-d260-4e2c-90b1-f1415a257c18", "b284db86-e9c2-4c25-a59e-4649797dd130", "c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd", "dfd9b46d-d00c-40af-8a75-3fbdc2b89869", diff --git a/tests/BotSharp.Plugin.PizzaBot/data/agents/8970b1e5-d260-4e2c-90b1-f1415a257c18/agent.json b/tests/BotSharp.Plugin.PizzaBot/data/agents/8970b1e5-d260-4e2c-90b1-f1415a257c18/agent.json new file mode 100644 index 00000000..e57ba894 --- /dev/null +++ b/tests/BotSharp.Plugin.PizzaBot/data/agents/8970b1e5-d260-4e2c-90b1-f1415a257c18/agent.json @@ -0,0 +1,18 @@ +{ + "id": "8970b1e5-d260-4e2c-90b1-f1415a257c18", + "name": "Pizza Bot", + "description": "AI assistant that can help customer place pizza order.", + "type": "routing", + "createdDateTime": "2023-08-18T10:39:32.2349685Z", + "updatedDateTime": "2023-08-18T14:39:32.2349686Z", + "iconUrl": "https://cdn-icons-png.flaticon.com/512/6978/6978255.png", + "disabled": true, + "isPublic": true, + "profiles": [ "pizza" ], + "routingRules": [ + { + "type": "planner", + "field": "NaviePlanner" + } + ] +} \ No newline at end of file diff --git a/tests/BotSharp.Plugin.PizzaBot/data/agents/dfd9b46d-d00c-40af-8a75-3fbdc2b89869/templates/task.place_pizza_order.liquid b/tests/BotSharp.Plugin.PizzaBot/data/agents/8970b1e5-d260-4e2c-90b1-f1415a257c18/templates/task.place_pizza_order.liquid similarity index 100% rename from tests/BotSharp.Plugin.PizzaBot/data/agents/dfd9b46d-d00c-40af-8a75-3fbdc2b89869/templates/task.place_pizza_order.liquid rename to tests/BotSharp.Plugin.PizzaBot/data/agents/8970b1e5-d260-4e2c-90b1-f1415a257c18/templates/task.place_pizza_order.liquid diff --git a/tests/BotSharp.Plugin.PizzaBot/data/agents/b284db86-e9c2-4c25-a59e-4649797dd130/agent.json b/tests/BotSharp.Plugin.PizzaBot/data/agents/b284db86-e9c2-4c25-a59e-4649797dd130/agent.json index 09c08cb6..949e201c 100644 --- a/tests/BotSharp.Plugin.PizzaBot/data/agents/b284db86-e9c2-4c25-a59e-4649797dd130/agent.json +++ b/tests/BotSharp.Plugin.PizzaBot/data/agents/b284db86-e9c2-4c25-a59e-4649797dd130/agent.json @@ -4,7 +4,7 @@ "createdDateTime": "2023-08-18T14:39:32.2349685Z", "updatedDateTime": "2023-08-18T14:39:32.2349686Z", "id": "b284db86-e9c2-4c25-a59e-4649797dd130", - "allowRouting": true, + "disabled": true, "isPublic": true, "profiles": [ "pizza" ], "routingRules": [ diff --git a/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/agent.json b/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/agent.json index 23323f63..4751fb78 100644 --- a/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/agent.json +++ b/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/agent.json @@ -4,7 +4,7 @@ "createdDateTime": "2023-07-26T02:29:25.123224Z", "updatedDateTime": "2023-07-26T02:29:25.123274Z", "id": "c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd", - "allowRouting": true, + "disabled": true, "isPublic": true, "profiles": [ "pizza" ] } \ No newline at end of file diff --git a/tests/BotSharp.Plugin.PizzaBot/data/agents/dfd9b46d-d00c-40af-8a75-3fbdc2b89869/agent.json b/tests/BotSharp.Plugin.PizzaBot/data/agents/dfd9b46d-d00c-40af-8a75-3fbdc2b89869/agent.json deleted file mode 100644 index 26f15972..00000000 --- a/tests/BotSharp.Plugin.PizzaBot/data/agents/dfd9b46d-d00c-40af-8a75-3fbdc2b89869/agent.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "EvaluationAgent", - "description": "Evaluate the performance of the LLM agents", - "createdDateTime": "2023-08-18T00:00:00Z", - "updatedDateTime": "2023-08-18T00:00:00Z", - "id": "dfd9b46d-d00c-40af-8a75-3fbdc2b89869", - "llmConfig": { - "model": "gpt-35-turbo-instruct" - } - } \ No newline at end of file diff --git a/tests/BotSharp.Plugin.PizzaBot/data/agents/fe8c60aa-b114-4ef3-93cb-a8efeac80f75/agent.json b/tests/BotSharp.Plugin.PizzaBot/data/agents/fe8c60aa-b114-4ef3-93cb-a8efeac80f75/agent.json index eba914f7..af5d6cd9 100644 --- a/tests/BotSharp.Plugin.PizzaBot/data/agents/fe8c60aa-b114-4ef3-93cb-a8efeac80f75/agent.json +++ b/tests/BotSharp.Plugin.PizzaBot/data/agents/fe8c60aa-b114-4ef3-93cb-a8efeac80f75/agent.json @@ -4,8 +4,9 @@ "createdDateTime": "2023-07-26T02:29:25.123224Z", "updatedDateTime": "2023-07-26T02:29:25.123274Z", "id": "fe8c60aa-b114-4ef3-93cb-a8efeac80f75", - "allowRouting": true, + "disabled": true, "isPublic": true, + "profiles": [ "pizza" ], "routingRules": [ { "field": "order_number", From e2abe6a5fdd945e2c44f94fe8ae38fbe9f231f35 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Sun, 28 Jan 2024 19:33:40 -0600 Subject: [PATCH 04/13] add truncate message --- .../Conversations/IConversationService.cs | 1 + .../Models/TruncateMessageRequest.cs | 6 ++ .../Models/MessageConfig.cs | 2 +- .../Repositories/IBotSharpRepository.cs | 1 + .../ConversationService.TruncateMessage.cs | 13 ++++ .../Repository/BotSharpDbContext.cs | 5 ++ .../FileRepository.Conversation.cs | 76 ++++++++++++++++++- .../Controllers/ConversationController.cs | 16 +++- .../MongoRepository.Conversation.cs | 38 ++++++++++ 9 files changed, 154 insertions(+), 4 deletions(-) create mode 100644 src/Infrastructure/BotSharp.Abstraction/Conversations/Models/TruncateMessageRequest.cs create mode 100644 src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.TruncateMessage.cs diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs index d41a8831..0e1d4787 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs @@ -13,6 +13,7 @@ public interface IConversationService Task UpdateConversationTitle(string id, string title); Task> GetLastConversations(); Task DeleteConversation(string id); + Task TruncateConversation(string conversationId, string messageId); /// /// Send message to LLM diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/TruncateMessageRequest.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/TruncateMessageRequest.cs new file mode 100644 index 00000000..088697cd --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/TruncateMessageRequest.cs @@ -0,0 +1,6 @@ +namespace BotSharp.Abstraction.Conversations.Models; + +public class TruncateMessageRequest +{ + public string? TruncateMessageId { get; set; } +} diff --git a/src/Infrastructure/BotSharp.Abstraction/Models/MessageConfig.cs b/src/Infrastructure/BotSharp.Abstraction/Models/MessageConfig.cs index 95d72492..438cc060 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Models/MessageConfig.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Models/MessageConfig.cs @@ -1,6 +1,6 @@ namespace BotSharp.Abstraction.Models; -public class MessageConfig +public class MessageConfig : TruncateMessageRequest { /// /// Completion Provider diff --git a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs index cd800cf9..e74ad6a8 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs @@ -46,6 +46,7 @@ public interface IBotSharpRepository PagedItems GetConversations(ConversationFilter filter); void UpdateConversationTitle(string conversationId, string title); List GetLastConversations(); + bool TruncateConversation(string conversationId, string messageId); #endregion #region Execution Log diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.TruncateMessage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.TruncateMessage.cs new file mode 100644 index 00000000..ca2719d3 --- /dev/null +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.TruncateMessage.cs @@ -0,0 +1,13 @@ +using BotSharp.Abstraction.Repositories; + +namespace BotSharp.Core.Conversations.Services; + +public partial class ConversationService : IConversationService +{ + public async Task TruncateConversation(string conversationId, string messageId) + { + var db = _services.GetRequiredService(); + var isSaved = db.TruncateConversation(conversationId, messageId); + return await Task.FromResult(isSaved); + } +} diff --git a/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs b/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs index c8b75e7e..43e44c7a 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs @@ -178,6 +178,11 @@ public class BotSharpDbContext : Database, IBotSharpRepository { throw new NotImplementedException(); } + + public bool TruncateConversation(string conversationId, string messageId) + { + throw new NotImplementedException(); + } #endregion diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Conversation.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Conversation.cs index 76122be6..8131bdd2 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Conversation.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Conversation.cs @@ -1,5 +1,6 @@ using BotSharp.Abstraction.Repositories.Filters; using BotSharp.Abstraction.Repositories.Models; +using System.Globalization; using System.IO; namespace BotSharp.Core.Repository @@ -256,6 +257,35 @@ namespace BotSharp.Core.Repository } + public bool TruncateConversation(string conversationId, string messageId) + { + if (string.IsNullOrEmpty(conversationId) || string.IsNullOrEmpty(messageId)) return false; + + var dialogs = new List(); + var convDir = FindConversationDirectory(conversationId); + if (string.IsNullOrEmpty(convDir)) return false; + + var dialogDir = Path.Combine(convDir, DIALOG_FILE); + dialogs = CollectDialogElements(dialogDir); + if (dialogs.IsNullOrEmpty()) return false; + + var foundIdx = dialogs.FindIndex(x => x.MetaData?.MessageId == messageId); + if (foundIdx < 0) return false; + + // Handle truncated dialogs + var isSaved = HandleTruncatedDialogs(dialogDir, dialogs, foundIdx); + if (!isSaved) return false; + + // Handle truncated states + var refTime = dialogs.ElementAt(foundIdx).MetaData.CreateTime; + var stateDir = Path.Combine(convDir, STATE_FILE); + var states = CollectConversationStates(stateDir); + isSaved = HandleTruncatedStates(stateDir, states, refTime); + + return isSaved; + } + + #region Private methods private string? FindConversationDirectory(string conversationId) { @@ -304,8 +334,9 @@ namespace BotSharp.Core.Repository foreach (var element in dialogs) { var meta = element.MetaData; + var createTime = meta.CreateTime.ToString("MM/dd/yyyy hh:mm:ss.fff tt", CultureInfo.InvariantCulture); var source = meta.FunctionName ?? meta.SenderId; - var metaStr = $"{meta.CreateTime}|{meta.Role}|{meta.AgentId}|{meta.MessageId}|{source}"; + var metaStr = $"{createTime}|{meta.Role}|{meta.AgentId}|{meta.MessageId}|{source}"; dialogTexts.Add(metaStr); var content = $" - {element.Content}"; dialogTexts.Add(content); @@ -325,6 +356,49 @@ namespace BotSharp.Core.Repository states = JsonSerializer.Deserialize>(stateStr, _options); return states ?? new List(); } + + private bool HandleTruncatedDialogs(string dialogDir, List dialogs, int foundIdx) + { + var truncatedDialogs = dialogs.Where((x, idx) => idx < foundIdx).ToList(); + var isSaved = SaveTruncatedDialogs(dialogDir, truncatedDialogs); + return isSaved; + } + + private bool HandleTruncatedStates(string stateDir, List states, DateTime refTime) + { + var truncatedStates = new List(); + foreach (var state in states) + { + var values = state.Values.Where(x => x.UpdateTime < refTime).ToList(); + if (values.Count == 0) continue; + + state.Values = values; + truncatedStates.Add(state); + } + + var isSaved = SaveTruncatedStates(stateDir, truncatedStates); + return isSaved; + } + + private bool SaveTruncatedDialogs(string dialogDir, List dialogs) + { + if (string.IsNullOrEmpty(dialogDir) || dialogs == null) return false; + if (!File.Exists(dialogDir)) File.Create(dialogDir); + + var texts = ParseDialogElements(dialogs); + File.WriteAllLines(dialogDir, texts); + return true; + } + + private bool SaveTruncatedStates(string stateDir, List states) + { + if (string.IsNullOrEmpty(stateDir) || states == null) return false; + if (!File.Exists(stateDir)) File.Create(stateDir); + + var stateStr = JsonSerializer.Serialize(states, _options); + File.WriteAllText(stateDir, stateStr); + return true; + } #endregion } } diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs index af921621..ae65fde9 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs @@ -114,14 +114,26 @@ public class ConversationController : ControllerBase return response; } + [HttpDelete("/conversation/{conversationId}/message/{messageId}")] + public async Task DeleteConversationMessage([FromRoute] string conversationId, [FromRoute] string messageId) + { + var conversationService = _services.GetRequiredService(); + var response = await conversationService.TruncateConversation(conversationId, messageId); + return response; + } + [HttpPost("/conversation/{agentId}/{conversationId}")] public async Task SendMessage([FromRoute] string agentId, [FromRoute] string conversationId, [FromBody] NewMessageModel input) { - var inputMsg = new RoleDialogModel(AgentRole.User, input.Text); - var conv = _services.GetRequiredService(); + if (!string.IsNullOrEmpty(input.TruncateMessageId)) + { + await conv.TruncateConversation(conversationId, input.TruncateMessageId); + } + + var inputMsg = new RoleDialogModel(AgentRole.User, input.Text); conv.SetConversationId(conversationId, input.States); conv.States.SetState("channel", input.Channel) .SetState("provider", input.Provider) diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Conversation.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Conversation.cs index 15a2406b..0a1c2530 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Conversation.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Conversation.cs @@ -263,4 +263,42 @@ public partial class MongoRepository UpdatedTime = c.UpdatedTime }).ToList(); } + + public bool TruncateConversation(string conversationId, string messageId) + { + if (string.IsNullOrEmpty(conversationId) || string.IsNullOrEmpty(messageId)) return false; + + var dialogFilter = Builders.Filter.Eq(x => x.ConversationId, conversationId); + var foundDialog = _dc.ConversationDialogs.Find(dialogFilter).FirstOrDefault(); + if (foundDialog == null || foundDialog.Dialogs.IsNullOrEmpty()) return false; + + var foundIdx = foundDialog.Dialogs.FindIndex(x => x.MetaData?.MessageId == messageId); + if (foundIdx < 0) return false; + + // Handle truncated dialogs + var truncatedDialogs = foundDialog.Dialogs.Where((x, idx) => idx < foundIdx).ToList(); + + // Handle truncated states + var refTime = foundDialog.Dialogs.ElementAt(foundIdx).MetaData.CreateTime; + var stateFilter = Builders.Filter.Eq(x => x.ConversationId, conversationId); + var foundStates = _dc.ConversationStates.Find(stateFilter).FirstOrDefault(); + if (foundStates == null || foundStates.States.IsNullOrEmpty()) return false; + + var truncatedStates = new List(); + foreach (var state in foundStates.States) + { + var values = state.Values.Where(x => x.UpdateTime < refTime).ToList(); + if (values.Count == 0) continue; + + state.Values = values; + truncatedStates.Add(state); + } + + // Save + foundDialog.Dialogs = truncatedDialogs; + foundStates.States = truncatedStates; + _dc.ConversationDialogs.ReplaceOne(dialogFilter, foundDialog); + _dc.ConversationStates.ReplaceOne(stateFilter, foundStates); + return true; + } } From 910ab43fbdc88df7994bc061abd8b1b7836a33e8 Mon Sep 17 00:00:00 2001 From: Visagan Guruparan <103048@smsassist.com> Date: Sun, 28 Jan 2024 22:18:40 -0600 Subject: [PATCH 05/13] Add new plugin for dashboard metrics --- BotSharp.sln | 11 ++++ .../Repositories/IBotSharpRepository.cs | 4 +- .../Statistics/Model/Statistics.cs | 13 +++++ .../Statistics/Settings/StatisticsSettings.cs | 11 ++++ .../Repository/BotSharpDbContext.cs | 7 ++- .../FileRepository/FileRepository.Stats.cs | 57 +++++++++++++++++++ .../FileRepository/FileRepository.cs | 1 + .../Controllers/PluginController.cs | 1 - .../BotSharp.Plugin.Dashboard.csproj | 12 ++++ .../DashboardPlugin.cs | 32 +++++++++++ .../Hooks/StatsConversationHook.cs | 20 +++++++ .../BotSharp.Plugin.Dashboard/Using.cs | 13 +++++ .../Repository/MongoRepository.Stats.cs | 16 ++++++ src/WebStarter/WebStarter.csproj | 3 +- src/WebStarter/appsettings.json | 5 +- 15 files changed, 201 insertions(+), 5 deletions(-) create mode 100644 src/Infrastructure/BotSharp.Abstraction/Statistics/Model/Statistics.cs create mode 100644 src/Infrastructure/BotSharp.Abstraction/Statistics/Settings/StatisticsSettings.cs create mode 100644 src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Stats.cs create mode 100644 src/Plugins/BotSharp.Plugin.Dashboard/BotSharp.Plugin.Dashboard.csproj create mode 100644 src/Plugins/BotSharp.Plugin.Dashboard/DashboardPlugin.cs create mode 100644 src/Plugins/BotSharp.Plugin.Dashboard/Hooks/StatsConversationHook.cs create mode 100644 src/Plugins/BotSharp.Plugin.Dashboard/Using.cs create mode 100644 src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Stats.cs diff --git a/BotSharp.sln b/BotSharp.sln index e161ed0d..0c99deee 100644 --- a/BotSharp.sln +++ b/BotSharp.sln @@ -81,6 +81,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotSharp.Plugin.HttpHandler EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotSharp.Plugin.SqlDriver", "src\Plugins\BotSharp.Plugin.SqlDriver\BotSharp.Plugin.SqlDriver.csproj", "{D775DB67-A4B4-44E5-9144-522689590057}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.Plugin.Dashboard", "src\Plugins\BotSharp.Plugin.Dashboard\BotSharp.Plugin.Dashboard.csproj", "{267998C1-55C2-4ADC-8361-2CDFA5EA6D6C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -313,6 +315,14 @@ Global {D775DB67-A4B4-44E5-9144-522689590057}.Release|Any CPU.Build.0 = Release|Any CPU {D775DB67-A4B4-44E5-9144-522689590057}.Release|x64.ActiveCfg = Release|Any CPU {D775DB67-A4B4-44E5-9144-522689590057}.Release|x64.Build.0 = Release|Any CPU + {267998C1-55C2-4ADC-8361-2CDFA5EA6D6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {267998C1-55C2-4ADC-8361-2CDFA5EA6D6C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {267998C1-55C2-4ADC-8361-2CDFA5EA6D6C}.Debug|x64.ActiveCfg = Debug|Any CPU + {267998C1-55C2-4ADC-8361-2CDFA5EA6D6C}.Debug|x64.Build.0 = Debug|Any CPU + {267998C1-55C2-4ADC-8361-2CDFA5EA6D6C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {267998C1-55C2-4ADC-8361-2CDFA5EA6D6C}.Release|Any CPU.Build.0 = Release|Any CPU + {267998C1-55C2-4ADC-8361-2CDFA5EA6D6C}.Release|x64.ActiveCfg = Release|Any CPU + {267998C1-55C2-4ADC-8361-2CDFA5EA6D6C}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -353,6 +363,7 @@ Global {5CA3335E-E6AD-46FD-B277-29BBC3A16500} = {E29DC6C4-5E57-48C5-BCB0-6B8F84782749} {32D9E720-6FE6-4F29-94B1-B10B05BFAD75} = {51AFE054-AE99-497D-A593-69BAEFB5106F} {D775DB67-A4B4-44E5-9144-522689590057} = {51AFE054-AE99-497D-A593-69BAEFB5106F} + {267998C1-55C2-4ADC-8361-2CDFA5EA6D6C} = {51AFE054-AE99-497D-A593-69BAEFB5106F} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {A9969D89-C98B-40A5-A12B-FC87E55B3A19} diff --git a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs index e74ad6a8..5ca241e6 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs @@ -48,7 +48,9 @@ public interface IBotSharpRepository List GetLastConversations(); bool TruncateConversation(string conversationId, string messageId); #endregion - + #region Statistics + void IncrementConversationCount(); + #endregion #region Execution Log void AddExecutionLogs(string conversationId, List logs); List GetExecutionLogs(string conversationId); diff --git a/src/Infrastructure/BotSharp.Abstraction/Statistics/Model/Statistics.cs b/src/Infrastructure/BotSharp.Abstraction/Statistics/Model/Statistics.cs new file mode 100644 index 00000000..5f4f1e5c --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Statistics/Model/Statistics.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace BotSharp.Abstraction.Statistics.Model +{ + public class Statistics + { + public string Id { get; set; } = string.Empty; + public int ConversationCount { get; set; } + public DateTime UpdatedDateTime { get; set; } + } +} diff --git a/src/Infrastructure/BotSharp.Abstraction/Statistics/Settings/StatisticsSettings.cs b/src/Infrastructure/BotSharp.Abstraction/Statistics/Settings/StatisticsSettings.cs new file mode 100644 index 00000000..2758dfc3 --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Statistics/Settings/StatisticsSettings.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace BotSharp.Abstraction.Statistics.Settings +{ + public class StatisticsSettings + { + public string DataDir { get; set; } + } +} diff --git a/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs b/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs index 43e44c7a..8adf711a 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs @@ -184,7 +184,12 @@ public class BotSharpDbContext : Database, IBotSharpRepository throw new NotImplementedException(); } #endregion - + #region Stats + public void IncrementConversationCount() + { + throw new NotImplementedException(); + } + #endregion #region User public User? GetUserByEmail(string email) diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Stats.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Stats.cs new file mode 100644 index 00000000..f67da60e --- /dev/null +++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Stats.cs @@ -0,0 +1,57 @@ +using BotSharp.Abstraction.Statistics.Model; +using System.IO; + +namespace BotSharp.Core.Repository +{ + public partial class FileRepository + { + public void IncrementConversationCount() + { + var statsFileDirectory = FindCurrentStatsDirectory(); + if (statsFileDirectory == null) + { + statsFileDirectory = CreateStatsFileDirectory(); + } + var fileName = GenerateStatsFileName(); + var statsFile = Path.Combine(statsFileDirectory, fileName); + if (!File.Exists(statsFile)) + { + File.WriteAllText(statsFile, JsonSerializer.Serialize(new Statistics() + { + Id = Guid.NewGuid().ToString(), + UpdatedDateTime = DateTime.UtcNow + }, _options)); + } + var json = File.ReadAllText(statsFile); + var stats = JsonSerializer.Deserialize(json, _options); + stats.ConversationCount += 1; + stats.UpdatedDateTime = DateTime.UtcNow; + File.WriteAllText(statsFile, JsonSerializer.Serialize(stats, _options)); + } + public string? CreateStatsFileDirectory() + { + var dir = GenerateStatsDirectoryName(); + if (!Directory.Exists(dir)) + { + Directory.CreateDirectory(dir); + } + return dir; + } + private string? FindCurrentStatsDirectory() + { + var dir = GenerateStatsDirectoryName(); + if (!Directory.Exists(dir)) return null; + + return dir; + } + private string GenerateStatsDirectoryName() + { + return Path.Combine(_dbSettings.FileRepository, "stats", DateTime.UtcNow.Year.ToString(), DateTime.UtcNow.ToString("MM")); + } + private string GenerateStatsFileName() + { + var fileName = DateTime.UtcNow.ToString("MMdd"); + return $"{fileName}-{STATS_FILE}"; + } + } +} diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.cs index 6874ed02..1cd0ae4d 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.cs @@ -29,6 +29,7 @@ public partial class FileRepository : IBotSharpRepository private const string USER_FILE = "user.json"; private const string USER_AGENT_FILE = "agents.json"; private const string CONVERSATION_FILE = "conversation.json"; + private const string STATS_FILE = "stats.json"; private const string DIALOG_FILE = "dialogs.txt"; private const string STATE_FILE = "state.json"; private const string EXECUTION_LOG_FILE = "execution.log"; diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/PluginController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/PluginController.cs index 54cdae14..3b3256c5 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/PluginController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/PluginController.cs @@ -28,7 +28,6 @@ public class PluginController : ControllerBase { var menu = new List { - new PluginMenuDef("Dashboard", link: "/page/dashboard", icon: "bx bx-home-circle", weight: 1), new PluginMenuDef("Apps", weight: 5) { IsHeader = true, diff --git a/src/Plugins/BotSharp.Plugin.Dashboard/BotSharp.Plugin.Dashboard.csproj b/src/Plugins/BotSharp.Plugin.Dashboard/BotSharp.Plugin.Dashboard.csproj new file mode 100644 index 00000000..5736c64f --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.Dashboard/BotSharp.Plugin.Dashboard.csproj @@ -0,0 +1,12 @@ + + + + netstandard2.1 + enable + + + + + + + diff --git a/src/Plugins/BotSharp.Plugin.Dashboard/DashboardPlugin.cs b/src/Plugins/BotSharp.Plugin.Dashboard/DashboardPlugin.cs new file mode 100644 index 00000000..3183d7d9 --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.Dashboard/DashboardPlugin.cs @@ -0,0 +1,32 @@ +using BotSharp.Abstraction.Conversations; +using BotSharp.Abstraction.Plugins; +using BotSharp.Abstraction.Plugins.Models; +using BotSharp.Abstraction.Settings; +using BotSharp.Abstraction.Statistics.Settings; +using BotSharp.Plugin.Dashboard.Hooks; + +namespace BotSharp.Plugin.Dashboard; + +public class DashboardPlugin : IBotSharpPlugin +{ + public string Id => "d42a0c21-b461-44f6-ada2-499510d260af"; + public string Name => "Dashboard"; + public string Description => "Dashboard that offering real-time statistics on model performance, usage trends, and user feedback"; + + public void RegisterDI(IServiceCollection services, IConfiguration config) + { + services.AddScoped(); + services.AddScoped(provider => + { + var settingService = provider.GetRequiredService(); + return settingService.Bind("Statistics"); + }); + } + + public bool AttachMenu(List menu) + { + var section = menu.First(x => x.Label == "Apps"); + menu.Add(new PluginMenuDef("Dashboard", link: "/page/dashboard", icon: "bx bx-home-circle", weight: section.Weight - 1)); + return true; + } +} diff --git a/src/Plugins/BotSharp.Plugin.Dashboard/Hooks/StatsConversationHook.cs b/src/Plugins/BotSharp.Plugin.Dashboard/Hooks/StatsConversationHook.cs new file mode 100644 index 00000000..5c16a173 --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.Dashboard/Hooks/StatsConversationHook.cs @@ -0,0 +1,20 @@ +using BotSharp.Abstraction.Conversations; +using BotSharp.Abstraction.Plugins.Models; +using BotSharp.Abstraction.Repositories; + +namespace BotSharp.Plugin.Dashboard.Hooks; + +public class StatsConversationHook : ConversationHookBase +{ + private readonly IServiceProvider _services; + public StatsConversationHook(IServiceProvider services) + { + _services = services; + } + + public override async Task OnConversationInitialized(Conversation conversation) + { + var db = _services.GetRequiredService(); + db.IncrementConversationCount(); + } +} diff --git a/src/Plugins/BotSharp.Plugin.Dashboard/Using.cs b/src/Plugins/BotSharp.Plugin.Dashboard/Using.cs new file mode 100644 index 00000000..8cb9a723 --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.Dashboard/Using.cs @@ -0,0 +1,13 @@ +global using System; +global using System.Collections.Generic; +global using System.Text; +global using System.Threading.Tasks; +global using System.Linq; +global using System.Text.Json; +global using BotSharp.Abstraction.Conversations.Models; +global using BotSharp.Abstraction.Agents.Models; +global using BotSharp.Abstraction.MLTasks; +global using Microsoft.Extensions.Configuration; +global using Microsoft.Extensions.DependencyInjection; +global using System.Text.Json.Serialization; +global using BotSharp.Abstraction.Utilities; \ No newline at end of file diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Stats.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Stats.cs new file mode 100644 index 00000000..11f74e69 --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Stats.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace BotSharp.Plugin.MongoStorage.Repository +{ + public partial class MongoRepository + { + #region Statistics + public void IncrementConversationCount() + { + throw new NotImplementedException(); + } + #endregion + } +} diff --git a/src/WebStarter/WebStarter.csproj b/src/WebStarter/WebStarter.csproj index d4e6e764..8a612ae4 100644 --- a/src/WebStarter/WebStarter.csproj +++ b/src/WebStarter/WebStarter.csproj @@ -1,4 +1,4 @@ - + net6.0 @@ -27,6 +27,7 @@ + diff --git a/src/WebStarter/appsettings.json b/src/WebStarter/appsettings.json index 67952c9a..9c59875f 100644 --- a/src/WebStarter/appsettings.json +++ b/src/WebStarter/appsettings.json @@ -82,7 +82,9 @@ "EnableLlmCompletionLog": false, "EnableExecutionLog": true }, - + "Stats": { + "DataDir": "stats" + }, "LlamaSharp": { "Interactive": true, "ModelDir": "C:/Users/haipi/Downloads", @@ -163,6 +165,7 @@ "Assemblies": [ "BotSharp.Plugin.MongoStorage", "BotSharp.Core", + "BotSharp.Plugin.Dashboard", "BotSharp.Plugin.AzureOpenAI", "BotSharp.Plugin.GoogleAI", "BotSharp.Plugin.MetaAI", From c0b2320010596b206405895917af1c9441caeca4 Mon Sep 17 00:00:00 2001 From: Visagan Guruparan <103048@smsassist.com> Date: Sun, 28 Jan 2024 22:20:37 -0600 Subject: [PATCH 06/13] Update plugin description --- src/Plugins/BotSharp.Plugin.Dashboard/DashboardPlugin.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Plugins/BotSharp.Plugin.Dashboard/DashboardPlugin.cs b/src/Plugins/BotSharp.Plugin.Dashboard/DashboardPlugin.cs index 3183d7d9..572bff90 100644 --- a/src/Plugins/BotSharp.Plugin.Dashboard/DashboardPlugin.cs +++ b/src/Plugins/BotSharp.Plugin.Dashboard/DashboardPlugin.cs @@ -11,7 +11,7 @@ public class DashboardPlugin : IBotSharpPlugin { public string Id => "d42a0c21-b461-44f6-ada2-499510d260af"; public string Name => "Dashboard"; - public string Description => "Dashboard that offering real-time statistics on model performance, usage trends, and user feedback"; + public string Description => "Dashboard that offers real-time statistics on model performance, usage trends, and user feedback"; public void RegisterDI(IServiceCollection services, IConfiguration config) { From dc5988a67564806f2470ff9b8da0ef40f18b5fa1 Mon Sep 17 00:00:00 2001 From: Visagan Guruparan <103048@smsassist.com> Date: Sun, 28 Jan 2024 22:24:01 -0600 Subject: [PATCH 07/13] Update stats directory naming --- .../Repository/FileRepository/FileRepository.Stats.cs | 2 +- .../Repository/FileRepository/FileRepository.cs | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Stats.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Stats.cs index f67da60e..b9c3b664 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Stats.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Stats.cs @@ -46,7 +46,7 @@ namespace BotSharp.Core.Repository } private string GenerateStatsDirectoryName() { - return Path.Combine(_dbSettings.FileRepository, "stats", DateTime.UtcNow.Year.ToString(), DateTime.UtcNow.ToString("MM")); + return Path.Combine(_dbSettings.FileRepository, _statisticsSetting.DataDir, DateTime.UtcNow.Year.ToString(), DateTime.UtcNow.ToString("MM")); } private string GenerateStatsFileName() { diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.cs index 1cd0ae4d..8c904109 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.cs @@ -11,6 +11,7 @@ using BotSharp.Abstraction.Routing.Settings; using BotSharp.Abstraction.Evaluations.Settings; using System.Text.Encodings.Web; using BotSharp.Abstraction.Plugins.Models; +using BotSharp.Abstraction.Statistics.Settings; namespace BotSharp.Core.Repository; @@ -20,6 +21,7 @@ public partial class FileRepository : IBotSharpRepository private readonly BotSharpDatabaseSettings _dbSettings; private readonly AgentSettings _agentSettings; private readonly ConversationSetting _conversationSettings; + private readonly StatisticsSettings _statisticsSetting; private JsonSerializerOptions _options; private const string AGENT_FILE = "agent.json"; @@ -39,12 +41,14 @@ public partial class FileRepository : IBotSharpRepository IServiceProvider services, BotSharpDatabaseSettings dbSettings, AgentSettings agentSettings, - ConversationSetting conversationSettings) + ConversationSetting conversationSettings, + StatisticsSettings statisticsSettings) { _services = services; _dbSettings = dbSettings; _agentSettings = agentSettings; _conversationSettings = conversationSettings; + _statisticsSetting = statisticsSettings; _options = new JsonSerializerOptions { From 67fd6f79fd1079b32073b8aa528406dc83fde859 Mon Sep 17 00:00:00 2001 From: Haiping Chen <101423@smsassist.com> Date: Mon, 29 Jan 2024 12:08:49 -0600 Subject: [PATCH 08/13] Allow agent to inherit from other agent. --- .../Agents/Models/Agent.cs | 11 ++- .../Plugins/PluginDependencyAttribute.cs | 11 +++ .../Routing/Models/RoutingRule.cs | 2 +- .../{ => Routing}/Planning/IExecutor.cs | 5 +- .../{ => Routing}/Planning/IPlaner.cs | 2 +- .../Agents/Services/AgentService.LoadAgent.cs | 21 +++++ .../BotSharp.Core/BotSharp.Core.csproj | 4 +- .../Conversations/ConversationPlugin.cs | 4 +- .../Infrastructures/LlmProviderPlugin.cs | 3 +- .../Instructs/InstructService.cs | 8 ++ .../BotSharp.Core/Plugins/PluginLoader.cs | 82 ++++++++++++++----- .../FileRepository/FileRepository.cs | 4 +- .../ContinueExecuteTaskRoutingHandler.cs | 2 +- .../InterruptTaskExecutionRoutingHandler.cs | 2 +- .../RetrieveDataFromAgentRoutingHandler.cs | 2 +- .../Routing/Handlers/TaskEndRoutingHandler.cs | 2 +- .../{ => Routing}/Planning/HFPlanner.cs | 4 +- .../Planning/InstructExecutor.cs | 4 +- .../{ => Routing}/Planning/NaivePlanner.cs | 14 ++-- .../Planning/SequentialPlanner.cs | 6 +- .../BotSharp.Core/Routing/RoutingPlugin.cs | 3 +- .../Routing/RoutingService.GetPlanner.cs | 4 +- .../BotSharp.Core/Routing/RoutingService.cs | 2 +- .../agent.json | 2 +- .../{welcome.liquid => .welcome.liquid} | 0 .../planner_prompt.sequential.liquid | 2 +- .../Controllers/PluginController.cs | 8 +- .../Providers/ChatCompletionProvider.cs | 4 +- .../Hooks/ChatHubConversationHook.cs | 2 +- .../agent.json | 14 +--- src/WebStarter/appsettings.json | 3 +- 31 files changed, 160 insertions(+), 77 deletions(-) create mode 100644 src/Infrastructure/BotSharp.Abstraction/Plugins/PluginDependencyAttribute.cs rename src/Infrastructure/BotSharp.Abstraction/{ => Routing}/Planning/IExecutor.cs (57%) rename src/Infrastructure/BotSharp.Abstraction/{ => Routing}/Planning/IPlaner.cs (90%) rename src/Infrastructure/BotSharp.Core/{ => Routing}/Planning/HFPlanner.cs (97%) rename src/Infrastructure/BotSharp.Core/{ => Routing}/Planning/InstructExecutor.cs (92%) rename src/Infrastructure/BotSharp.Core/{ => Routing}/Planning/NaivePlanner.cs (96%) rename src/Infrastructure/BotSharp.Core/{ => Routing}/Planning/SequentialPlanner.cs (97%) rename src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/{welcome.liquid => .welcome.liquid} (100%) diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs index 6b18b652..68e636b8 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs @@ -33,7 +33,8 @@ public class Agent /// Templates /// [JsonIgnore] - public List? Templates { get; set; } + public List Templates { get; set; } + = new List(); /// /// Samples @@ -46,7 +47,8 @@ public class Agent /// Functions /// [JsonIgnore] - public List Functions { get; set; } = new List(); + public List Functions { get; set; } + = new List(); /// /// Responses @@ -80,6 +82,11 @@ public class Agent public List Profiles { get; set; } = new List(); + /// + /// Inherit from agent + /// + public string? InheritAgentId { get; set; } + public List RoutingRules { get; set; } = new List(); diff --git a/src/Infrastructure/BotSharp.Abstraction/Plugins/PluginDependencyAttribute.cs b/src/Infrastructure/BotSharp.Abstraction/Plugins/PluginDependencyAttribute.cs new file mode 100644 index 00000000..7b5e93cb --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Plugins/PluginDependencyAttribute.cs @@ -0,0 +1,11 @@ +namespace BotSharp.Abstraction.Plugins; + +public class PluginDependencyAttribute : Attribute +{ + public string[] PluginNames { get; set; } + + public PluginDependencyAttribute(params string[] pluginNames) + { + PluginNames = pluginNames; + } +} diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingRule.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingRule.cs index b652ced1..b0353ce6 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingRule.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingRule.cs @@ -26,7 +26,7 @@ public class RoutingRule public override string ToString() { - return $"{AgentName} {Field}"; + return $"{Type} {AgentName} {Field}"; } public RoutingRule() diff --git a/src/Infrastructure/BotSharp.Abstraction/Planning/IExecutor.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/Planning/IExecutor.cs similarity index 57% rename from src/Infrastructure/BotSharp.Abstraction/Planning/IExecutor.cs rename to src/Infrastructure/BotSharp.Abstraction/Routing/Planning/IExecutor.cs index 187fcfcc..c8bffe6c 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Planning/IExecutor.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Routing/Planning/IExecutor.cs @@ -1,11 +1,10 @@ using BotSharp.Abstraction.Functions.Models; -using BotSharp.Abstraction.Routing; -namespace BotSharp.Abstraction.Planning; +namespace BotSharp.Abstraction.Routing.Planning; public interface IExecutor { - Task Execute(IRoutingService routing, + Task Execute(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message, List dialogs); diff --git a/src/Infrastructure/BotSharp.Abstraction/Planning/IPlaner.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/Planning/IPlaner.cs similarity index 90% rename from src/Infrastructure/BotSharp.Abstraction/Planning/IPlaner.cs rename to src/Infrastructure/BotSharp.Abstraction/Routing/Planning/IPlaner.cs index a6136ea8..4053f81c 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Planning/IPlaner.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Routing/Planning/IPlaner.cs @@ -1,6 +1,6 @@ using BotSharp.Abstraction.Functions.Models; -namespace BotSharp.Abstraction.Planning; +namespace BotSharp.Abstraction.Routing.Planning; /// /// Task breakdown and execution plan diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs index ab40b134..a6910603 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs @@ -32,6 +32,27 @@ public partial class AgentService throw new Exception($"Can't load agent by id: {id}"); } + if (agent.InheritAgentId != null) + { + var inheritedAgent = await GetAgent(agent.InheritAgentId); + agent.Templates.AddRange(inheritedAgent.Templates + // exclude private template + .Where(x => !x.Name.StartsWith(".")) + // exclude duplicate name + .Where(x => !agent.Templates.Exists(t => t.Name == x.Name))); + + agent.Functions.AddRange(inheritedAgent.Functions + // exclude private template + .Where(x => !x.Name.StartsWith(".")) + // exclude duplicate name + .Where(x => !agent.Functions.Exists(t => t.Name == x.Name))); + + if (agent.Instruction == null) + { + agent.Instruction = inheritedAgent.Instruction; + } + } + agent.TemplateDict = new Dictionary(); // Populate state into dictionary diff --git a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj index 8f706a7b..8e79687f 100644 --- a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj +++ b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj @@ -50,11 +50,11 @@ + - @@ -87,7 +87,7 @@ PreserveNewest - + PreserveNewest diff --git a/src/Infrastructure/BotSharp.Core/Conversations/ConversationPlugin.cs b/src/Infrastructure/BotSharp.Core/Conversations/ConversationPlugin.cs index 00d55555..13885fec 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/ConversationPlugin.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/ConversationPlugin.cs @@ -1,12 +1,12 @@ using BotSharp.Abstraction.Instructs; using BotSharp.Abstraction.Messaging; -using BotSharp.Abstraction.Planning; using BotSharp.Abstraction.Plugins.Models; +using BotSharp.Abstraction.Routing.Planning; using BotSharp.Abstraction.Settings; using BotSharp.Abstraction.Templating; using BotSharp.Core.Instructs; using BotSharp.Core.Messaging; -using BotSharp.Core.Planning; +using BotSharp.Core.Routing.Planning; using BotSharp.Core.Templating; using Microsoft.Extensions.Configuration; diff --git a/src/Infrastructure/BotSharp.Core/Infrastructures/LlmProviderPlugin.cs b/src/Infrastructure/BotSharp.Core/Infrastructures/LlmProviderPlugin.cs index 469447a2..74f1aa83 100644 --- a/src/Infrastructure/BotSharp.Core/Infrastructures/LlmProviderPlugin.cs +++ b/src/Infrastructure/BotSharp.Core/Infrastructures/LlmProviderPlugin.cs @@ -21,10 +21,11 @@ public class LlmProviderPlugin : IBotSharpPlugin services.AddScoped(provider => { var settingService = provider.GetRequiredService(); + var loger = provider.GetRequiredService>(); var llmProviders = settingService.Bind>("LlmProviders"); foreach (var llmProvider in llmProviders) { - Console.WriteLine($"Loaded LlmProvider {llmProvider.Provider} settings with {llmProvider.Models.Count} models."); + loger.LogInformation($"Loaded LlmProvider {llmProvider.Provider} settings with {llmProvider.Models.Count} models."); } return llmProviders; }); diff --git a/src/Infrastructure/BotSharp.Core/Instructs/InstructService.cs b/src/Infrastructure/BotSharp.Core/Instructs/InstructService.cs index ccab8874..d8a9a1bb 100644 --- a/src/Infrastructure/BotSharp.Core/Instructs/InstructService.cs +++ b/src/Infrastructure/BotSharp.Core/Instructs/InstructService.cs @@ -16,6 +16,14 @@ public partial class InstructService : IInstructService _logger = logger; } + /// + /// Execute completion by using specified instruction or template + /// + /// Agent (static agent) + /// Additional message provided by user + /// Template name + /// System prompt + /// public async Task Execute(string agentId, RoleDialogModel message, string? templateName = null, string? instruction = null) { var agentService = _services.GetRequiredService(); diff --git a/src/Infrastructure/BotSharp.Core/Plugins/PluginLoader.cs b/src/Infrastructure/BotSharp.Core/Plugins/PluginLoader.cs index 0d54f4af..0932041d 100644 --- a/src/Infrastructure/BotSharp.Core/Plugins/PluginLoader.cs +++ b/src/Infrastructure/BotSharp.Core/Plugins/PluginLoader.cs @@ -27,12 +27,17 @@ public class PluginLoader _settings = settings; } - public void Load(Action loaded) + public void Load(Action loaded, string? plugin = null) { _executingDir = Directory.GetParent(Assembly.GetEntryAssembly().Location).FullName; _settings.Assemblies.ToList().ForEach(assemblyName => { + if (plugin != null && plugin != assemblyName) + { + return; + } + var assemblyPath = Path.Combine(_executingDir, assemblyName + ".dll"); if (File.Exists(assemblyPath)) { @@ -45,38 +50,66 @@ public class PluginLoader foreach (var module in modules) { - module.RegisterDI(_services, _config); - // string classSummary = GetSummaryComment(module.GetType()); - var name = string.IsNullOrEmpty(module.Name) ? module.GetType().Name : module.Name; - _modules.Add(module); - _plugins.Add(new PluginDef + if (_plugins.Exists(x => x.Id == module.Id)) { - Id = module.Id, - Name = name, - Module = module, - Description = module.Description, - Assembly = assemblyName, - IconUrl = module.IconUrl, - AgentIds = module.AgentIds - }); - Console.Write($"Loaded plugin "); - Console.Write(name, Color.Green); - Console.WriteLine($" from {assemblyName}."); - if (!string.IsNullOrEmpty(module.Description)) - { - Console.WriteLine(module.Description); + continue; } + + // Solve plugin dependency + var attr = module.GetType().GetCustomAttribute(); + if (attr != null) + { + foreach (var plugin in attr.PluginNames) + { + if (!_plugins.Any(x => x.Assembly == plugin)) + { + Load(loaded, plugin); + } + + if (!_plugins.Any(x => x.Assembly == plugin)) + { + Console.WriteLine($"Load dependent plugin {plugin} failed by {module.Name}.", Color.Red); + } + } + } + + InitModule(assemblyName, module); } loaded(assembly); } else { - Console.WriteLine($"Can't find assemble {assemblyPath}."); + Console.WriteLine($"Can't find assemble {assemblyPath}.", Color.Red); } }); } + private void InitModule(string assembly, IBotSharpPlugin module) + { + module.RegisterDI(_services, _config); + // string classSummary = GetSummaryComment(module.GetType()); + var name = string.IsNullOrEmpty(module.Name) ? module.GetType().Name : module.Name; + _modules.Add(module); + _plugins.Add(new PluginDef + { + Id = module.Id, + Name = name, + Module = module, + Description = module.Description, + Assembly = assembly, + IconUrl = module.IconUrl, + AgentIds = module.AgentIds + }); + Console.Write($"Loaded plugin "); + Console.Write(name, Color.Green); + Console.WriteLine($" from {assembly}."); + if (!string.IsNullOrEmpty(module.Description)) + { + Console.WriteLine(module.Description); + } + } + public List GetPlugins(IServiceProvider services) { // Apply user configurations @@ -124,6 +157,13 @@ public class PluginLoader var agent = agentService.LoadAgent(agentId).Result; agent.Disabled = false; agentService.UpdateAgent(agent, AgentField.Disabled); + + if (agent.InheritAgentId != null) + { + agent = agentService.LoadAgent(agent.InheritAgentId).Result; + agent.Disabled = false; + agentService.UpdateAgent(agent, AgentField.Disabled); + } } } else diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.cs index 6874ed02..2fca2321 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.cs @@ -176,10 +176,10 @@ public partial class FileRepository : IBotSharpRepository return (agent, agentFile); } - private string FetchInstruction(string fileDir) + private string? FetchInstruction(string fileDir) { var file = Path.Combine(fileDir, $"{AGENT_INSTRUCTION_FILE}.{_agentSettings.TemplateFormat}"); - if (!File.Exists(file)) return string.Empty; + if (!File.Exists(file)) return null; var instruction = File.ReadAllText(file); return instruction; diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/ContinueExecuteTaskRoutingHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/ContinueExecuteTaskRoutingHandler.cs index 66fe6759..646dd481 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/ContinueExecuteTaskRoutingHandler.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Handlers/ContinueExecuteTaskRoutingHandler.cs @@ -4,7 +4,7 @@ using BotSharp.Abstraction.Repositories; using BotSharp.Abstraction.Repositories.Filters; using BotSharp.Abstraction.Routing; using BotSharp.Abstraction.Routing.Settings; -using BotSharp.Core.Planning; +using BotSharp.Core.Routing.Planning; namespace BotSharp.Core.Routing.Handlers; diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/InterruptTaskExecutionRoutingHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/InterruptTaskExecutionRoutingHandler.cs index 00068306..da58b98b 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/InterruptTaskExecutionRoutingHandler.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Handlers/InterruptTaskExecutionRoutingHandler.cs @@ -1,7 +1,7 @@ using BotSharp.Abstraction.Functions.Models; using BotSharp.Abstraction.Routing; using BotSharp.Abstraction.Routing.Settings; -using BotSharp.Core.Planning; +using BotSharp.Core.Routing.Planning; namespace BotSharp.Core.Routing.Handlers; diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/RetrieveDataFromAgentRoutingHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/RetrieveDataFromAgentRoutingHandler.cs index 3e397089..54f3e66c 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/RetrieveDataFromAgentRoutingHandler.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Handlers/RetrieveDataFromAgentRoutingHandler.cs @@ -2,7 +2,7 @@ using BotSharp.Abstraction.Functions.Models; using BotSharp.Abstraction.Routing; using BotSharp.Abstraction.Routing.Models; using BotSharp.Abstraction.Routing.Settings; -using BotSharp.Core.Planning; +using BotSharp.Core.Routing.Planning; namespace BotSharp.Core.Routing.Handlers; diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/TaskEndRoutingHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/TaskEndRoutingHandler.cs index 0b299f25..5e431f84 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/TaskEndRoutingHandler.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Handlers/TaskEndRoutingHandler.cs @@ -1,7 +1,7 @@ using BotSharp.Abstraction.Functions.Models; using BotSharp.Abstraction.Routing; using BotSharp.Abstraction.Routing.Settings; -using BotSharp.Core.Planning; +using BotSharp.Core.Routing.Planning; namespace BotSharp.Core.Routing.Handlers; diff --git a/src/Infrastructure/BotSharp.Core/Planning/HFPlanner.cs b/src/Infrastructure/BotSharp.Core/Routing/Planning/HFPlanner.cs similarity index 97% rename from src/Infrastructure/BotSharp.Core/Planning/HFPlanner.cs rename to src/Infrastructure/BotSharp.Core/Routing/Planning/HFPlanner.cs index 8f4e0033..9cff003a 100644 --- a/src/Infrastructure/BotSharp.Core/Planning/HFPlanner.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Planning/HFPlanner.cs @@ -1,12 +1,12 @@ using BotSharp.Abstraction.Agents.Models; using BotSharp.Abstraction.Functions.Models; -using BotSharp.Abstraction.Planning; using BotSharp.Abstraction.Repositories; using BotSharp.Abstraction.Repositories.Filters; using BotSharp.Abstraction.Routing.Models; +using BotSharp.Abstraction.Routing.Planning; using BotSharp.Abstraction.Templating; -namespace BotSharp.Core.Planning; +namespace BotSharp.Core.Routing.Planning; /// /// Human feedback based planner diff --git a/src/Infrastructure/BotSharp.Core/Planning/InstructExecutor.cs b/src/Infrastructure/BotSharp.Core/Routing/Planning/InstructExecutor.cs similarity index 92% rename from src/Infrastructure/BotSharp.Core/Planning/InstructExecutor.cs rename to src/Infrastructure/BotSharp.Core/Routing/Planning/InstructExecutor.cs index 0d02cd95..0f436edd 100644 --- a/src/Infrastructure/BotSharp.Core/Planning/InstructExecutor.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Planning/InstructExecutor.cs @@ -1,8 +1,8 @@ using BotSharp.Abstraction.Functions.Models; -using BotSharp.Abstraction.Planning; using BotSharp.Abstraction.Routing; +using BotSharp.Abstraction.Routing.Planning; -namespace BotSharp.Core.Planning; +namespace BotSharp.Core.Routing.Planning; public class InstructExecutor : IExecutor { diff --git a/src/Infrastructure/BotSharp.Core/Planning/NaivePlanner.cs b/src/Infrastructure/BotSharp.Core/Routing/Planning/NaivePlanner.cs similarity index 96% rename from src/Infrastructure/BotSharp.Core/Planning/NaivePlanner.cs rename to src/Infrastructure/BotSharp.Core/Routing/Planning/NaivePlanner.cs index 78112559..fa4b20a0 100644 --- a/src/Infrastructure/BotSharp.Core/Planning/NaivePlanner.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Planning/NaivePlanner.cs @@ -1,11 +1,11 @@ using BotSharp.Abstraction.Agents.Models; using BotSharp.Abstraction.Functions.Models; -using BotSharp.Abstraction.Planning; using BotSharp.Abstraction.Repositories.Filters; using BotSharp.Abstraction.Routing.Models; +using BotSharp.Abstraction.Routing.Planning; using BotSharp.Abstraction.Templating; -namespace BotSharp.Core.Planning; +namespace BotSharp.Core.Routing.Planning; public class NaivePlanner : IPlaner { @@ -32,7 +32,7 @@ public class NaivePlanner : IPlaner var completion = CompletionProvider.GetTextCompletion(_services);*/ // chat completion - var completion = CompletionProvider.GetChatCompletion(_services, + var completion = CompletionProvider.GetChatCompletion(_services, provider: router?.LlmConfig?.Provider, model: router?.LlmConfig?.Model); @@ -44,7 +44,7 @@ public class NaivePlanner : IPlaner { // text completion // text = await completion.GetCompletion(content, router.Id, messageId); - var dialogs = new List + var dialogs = new List { new RoleDialogModel(AgentRole.User, next) { @@ -91,7 +91,7 @@ public class NaivePlanner : IPlaner if (inst.UnmatchedAgent) { var unmatchedAgentId = context.GetCurrentAgentId(); - + // Exclude the wrong routed agent var agents = router.TemplateDict["routing_agents"] as RoutableAgent[]; router.TemplateDict["routing_agents"] = agents.Where(x => x.AgentId != unmatchedAgentId).ToArray(); @@ -123,8 +123,8 @@ public class NaivePlanner : IPlaner private void FixMalformedResponse(FunctionCallFromLlm args) { var agentService = _services.GetRequiredService(); - var agents = agentService.GetAgents(new AgentFilter - { + var agents = agentService.GetAgents(new AgentFilter + { Type = AgentType.Task }).Result.Items.ToList(); var malformed = false; diff --git a/src/Infrastructure/BotSharp.Core/Planning/SequentialPlanner.cs b/src/Infrastructure/BotSharp.Core/Routing/Planning/SequentialPlanner.cs similarity index 97% rename from src/Infrastructure/BotSharp.Core/Planning/SequentialPlanner.cs rename to src/Infrastructure/BotSharp.Core/Routing/Planning/SequentialPlanner.cs index 8f571266..1b24152a 100644 --- a/src/Infrastructure/BotSharp.Core/Planning/SequentialPlanner.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Planning/SequentialPlanner.cs @@ -1,11 +1,11 @@ using BotSharp.Abstraction.Agents.Models; using BotSharp.Abstraction.Functions.Models; -using BotSharp.Abstraction.Planning; using BotSharp.Abstraction.Routing; using BotSharp.Abstraction.Routing.Models; +using BotSharp.Abstraction.Routing.Planning; using BotSharp.Abstraction.Templating; -namespace BotSharp.Core.Planning; +namespace BotSharp.Core.Routing.Planning; public class SequentialPlanner : IPlaner { @@ -91,7 +91,7 @@ public class SequentialPlanner : IPlaner context.Empty(); return false; } - + // Handover to Router; context.Pop(); diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingPlugin.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingPlugin.cs index 946e6057..677157d6 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingPlugin.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingPlugin.cs @@ -1,10 +1,9 @@ -using BotSharp.Abstraction.Planning; using BotSharp.Abstraction.Routing; using BotSharp.Abstraction.Routing.Models; using BotSharp.Abstraction.Routing.Settings; using BotSharp.Abstraction.Settings; -using BotSharp.Core.Planning; using BotSharp.Core.Routing.Hooks; +using BotSharp.Core.Routing.Planning; using Microsoft.Extensions.Configuration; namespace BotSharp.Core.Routing; diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.GetPlanner.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.GetPlanner.cs index 01de9a29..2d47f1ab 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.GetPlanner.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.GetPlanner.cs @@ -1,7 +1,7 @@ using BotSharp.Abstraction.Agents.Models; -using BotSharp.Abstraction.Planning; using BotSharp.Abstraction.Routing.Enums; -using BotSharp.Core.Planning; +using BotSharp.Abstraction.Routing.Planning; +using BotSharp.Core.Routing.Planning; namespace BotSharp.Core.Routing; diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs index b94903af..8a34d684 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs @@ -1,10 +1,10 @@ using BotSharp.Abstraction.Agents.Models; using BotSharp.Abstraction.Functions.Models; -using BotSharp.Abstraction.Planning; using BotSharp.Abstraction.Repositories; using BotSharp.Abstraction.Repositories.Filters; using BotSharp.Abstraction.Routing; using BotSharp.Abstraction.Routing.Models; +using BotSharp.Abstraction.Routing.Planning; using BotSharp.Abstraction.Routing.Settings; using System.Drawing; diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01e2fc5c-2c89-4ec7-8470-7688608b496c/agent.json b/src/Infrastructure/BotSharp.Core/data/agents/01e2fc5c-2c89-4ec7-8470-7688608b496c/agent.json index d75a4483..536ca340 100644 --- a/src/Infrastructure/BotSharp.Core/data/agents/01e2fc5c-2c89-4ec7-8470-7688608b496c/agent.json +++ b/src/Infrastructure/BotSharp.Core/data/agents/01e2fc5c-2c89-4ec7-8470-7688608b496c/agent.json @@ -1,7 +1,7 @@ { "id": "01e2fc5c-2c89-4ec7-8470-7688608b496c", "name": "Chatbot", - "description": "AI chatbot that can do variaty of tasks", + "description": "Chatbot is used to test the performance of different large models and does not interact with external APIs.", "type": "task", "createdDateTime": "2024-01-15T10:39:32Z", "updatedDateTime": "2024-01-15T14:39:32Z", diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/welcome.liquid b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/.welcome.liquid similarity index 100% rename from src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/welcome.liquid rename to src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/.welcome.liquid diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.sequential.liquid b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.sequential.liquid index a1025e50..32de085b 100644 --- a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.sequential.liquid +++ b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.sequential.liquid @@ -1,2 +1,2 @@ -In order to execute the instructions listed by the user in the order specified by the user. +In order to execute the listed instructions in the order specified by the user. What is the next step based on the CONVERSATION? \ No newline at end of file diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/PluginController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/PluginController.cs index 54cdae14..7feceadf 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/PluginController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/PluginController.cs @@ -54,15 +54,15 @@ public class PluginController : ControllerBase return menu; } - [HttpPost("/plugin/{id}/enable")] - public PluginDef EnablePlugin([FromRoute] string id) + [HttpPost("/plugin/{id}/install")] + public PluginDef InstallPlugin([FromRoute] string id) { var loader = _services.GetRequiredService(); return loader.UpdatePluginStatus(_services, id, true); } - [HttpPost("/plugin/{id}/disable")] - public PluginDef DisablePluginStats([FromRoute] string id) + [HttpPost("/plugin/{id}/remove")] + public PluginDef RemovePluginStats([FromRoute] string id) { var loader = _services.GetRequiredService(); return loader.UpdatePluginStatus(_services, id, false); diff --git a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs index bf563670..ca8d7e01 100644 --- a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs +++ b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs @@ -292,7 +292,9 @@ public class ChatCompletionProvider : IChatCompletion else if (x.Role == ChatRole.User) { var m = x as ChatRequestUserMessage; - return $"{m.Role}: {m.Content}"; + return !string.IsNullOrEmpty(m.Name) ? + $"{m.Name}: {m.Content}" : + $"{m.Role}: {m.Content}"; } else if (x.Role == ChatRole.Assistant) { diff --git a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs index bad8cf2b..8275daa7 100644 --- a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs +++ b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs @@ -36,7 +36,7 @@ public class ChatHubConversationHook : ConversationHookBase var agent = await agentService.LoadAgent(conversation.AgentId); // Check if the Welcome template exists. - var welcomeTemplate = agent.Templates?.FirstOrDefault(x => x.Name == "welcome"); + var welcomeTemplate = agent.Templates?.FirstOrDefault(x => x.Name == ".welcome"); if (welcomeTemplate != null) { var richContentService = _services.GetRequiredService(); diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/agent.json b/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/agent.json index 290a88d0..2d928f12 100644 --- a/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/agent.json +++ b/src/Plugins/BotSharp.Plugin.WebDriver/data/agents/f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b/agent.json @@ -1,19 +1,13 @@ { "id": "f3ae2a0f-e6ba-4ee1-a0b9-75d7431ff32b", "name": "Web Driver", - "description": "Perform a specific action on a web browser", + "description": "Perform the web page related task in browser by using automation tools.", "type": "task", "createdDateTime": "2024-01-02T00:00:00Z", "updatedDateTime": "2024-01-02T00:00:00Z", "isPublic": true, - "profiles": [ "default" ], + "profiles": [ "web-driver" ], "llmConfig": { - "max_recursion_depth": 10 - }, - "routingRules": [ - { - "type": "fallback", - "redirectTo": "01e2fc5c-2c89-4ec7-8470-7688608b496c" - } - ] + "max_recursion_depth": 5 + } } \ No newline at end of file diff --git a/src/WebStarter/appsettings.json b/src/WebStarter/appsettings.json index 67952c9a..91bf2de7 100644 --- a/src/WebStarter/appsettings.json +++ b/src/WebStarter/appsettings.json @@ -161,8 +161,9 @@ "PluginLoader": { "Assemblies": [ - "BotSharp.Plugin.MongoStorage", "BotSharp.Core", + "BotSharp.Logger", + "BotSharp.Plugin.MongoStorage", "BotSharp.Plugin.AzureOpenAI", "BotSharp.Plugin.GoogleAI", "BotSharp.Plugin.MetaAI", From d088ca13e85dff3e66fe55bff553aae8a27c1c2c Mon Sep 17 00:00:00 2001 From: Haiping Date: Mon, 29 Jan 2024 13:02:02 -0600 Subject: [PATCH 09/13] Update MongoRepository.Stats.cs --- .../Repository/MongoRepository.Stats.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Stats.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Stats.cs index 11f74e69..eea27ee9 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Stats.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Stats.cs @@ -9,7 +9,7 @@ namespace BotSharp.Plugin.MongoStorage.Repository #region Statistics public void IncrementConversationCount() { - throw new NotImplementedException(); + } #endregion } From 390399dd7e70cd4052a70a0b0ee09c2a7ad42598 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Mon, 29 Jan 2024 13:22:37 -0600 Subject: [PATCH 10/13] add inherit agent id in mongo --- .../Agents/Enums/AgentField.cs | 1 + .../FileRepository/FileRepository.Agent.cs | 14 ++++++++++++++ .../Collections/AgentDocument.cs | 1 + .../Repository/MongoRepository.Agent.cs | 16 ++++++++++++++++ .../Repository/MongoRepository.Transaction.cs | 2 ++ 5 files changed, 34 insertions(+) diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentField.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentField.cs index 0fdeffe3..81aacb85 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentField.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentField.cs @@ -8,6 +8,7 @@ public enum AgentField IsPublic, Disabled, Type, + InheritAgentId, Profiles, RoutingRule, Instruction, diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs index b2476921..01a75d40 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs @@ -31,6 +31,9 @@ namespace BotSharp.Core.Repository case AgentField.Type: UpdateAgentType(agent.Id, agent.Type); break; + case AgentField.InheritAgentId: + UpdateAgentInheritAgentId(agent.Id, agent.InheritAgentId); + break; case AgentField.Profiles: UpdateAgentProfiles(agent.Id, agent.Profiles); break; @@ -123,6 +126,17 @@ namespace BotSharp.Core.Repository File.WriteAllText(agentFile, json); } + private void UpdateAgentInheritAgentId(string agentId, string? inheritAgentId) + { + var (agent, agentFile) = GetAgentFromFile(agentId); + if (agent == null) return; + + agent.InheritAgentId = inheritAgentId; + agent.UpdatedDateTime = DateTime.UtcNow; + var json = JsonSerializer.Serialize(agent, _options); + File.WriteAllText(agentFile, json); + } + private void UpdateAgentProfiles(string agentId, List profiles) { if (profiles.IsNullOrEmpty()) return; diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentDocument.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentDocument.cs index 603f312e..8e2f4dd4 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentDocument.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentDocument.cs @@ -7,6 +7,7 @@ public class AgentDocument : MongoBase public string Name { get; set; } public string Description { get; set; } public string Type { get; set; } + public string? InheritAgentId { get; set; } public string? IconUrl { get; set; } public string Instruction { get; set; } public List Templates { get; set; } diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs index 9a0f0cee..58fe44ff 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs @@ -32,6 +32,9 @@ public partial class MongoRepository case AgentField.Type: UpdateAgentType(agent.Id, agent.Type); break; + case AgentField.InheritAgentId: + UpdateAgentInheritAgentId(agent.Id, agent.InheritAgentId); + break; case AgentField.Profiles: UpdateAgentProfiles(agent.Id, agent.Profiles); break; @@ -119,6 +122,16 @@ public partial class MongoRepository _dc.Agents.UpdateOne(filter, update); } + private void UpdateAgentInheritAgentId(string agentId, string? inheritAgentId) + { + var filter = Builders.Filter.Eq(x => x.Id, agentId); + var update = Builders.Update + .Set(x => x.InheritAgentId, inheritAgentId) + .Set(x => x.UpdatedTime, DateTime.UtcNow); + + _dc.Agents.UpdateOne(filter, update); + } + private void UpdateAgentProfiles(string agentId, List profiles) { if (profiles.IsNullOrEmpty()) return; @@ -268,6 +281,7 @@ public partial class MongoRepository IsPublic = agent.IsPublic, Disabled = agent.Disabled, Type = agent.Type, + InheritAgentId = agent.InheritAgentId, Profiles = agent.Profiles, RoutingRules = !agent.RoutingRules.IsNullOrEmpty() ? agent.RoutingRules .Select(r => RoutingRuleMongoElement.ToDomainElement(agent.Id, agent.Name, r)) @@ -329,6 +343,7 @@ public partial class MongoRepository IsPublic = x.IsPublic, Disabled = x.Disabled, Type = x.Type, + InheritAgentId = x.InheritAgentId, Profiles = x.Profiles, RoutingRules = !x.RoutingRules.IsNullOrEmpty() ? x.RoutingRules .Select(r => RoutingRuleMongoElement.ToDomainElement(x.Id, x.Name, r)) @@ -393,6 +408,7 @@ public partial class MongoRepository Samples = x.Samples ?? new List(), IsPublic = x.IsPublic, Type = x.Type, + InheritAgentId = x.InheritAgentId, Disabled = x.Disabled, Profiles = x.Profiles, RoutingRules = x.RoutingRules? diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Transaction.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Transaction.cs index 17e59c2e..470b1fb1 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Transaction.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Transaction.cs @@ -55,6 +55,7 @@ public partial class MongoRepository Samples = x.Samples ?? new List(), IsPublic = x.IsPublic, Type = x.Type, + InheritAgentId = x.InheritAgentId, Disabled = x.Disabled, Profiles = x.Profiles, RoutingRules = x.RoutingRules? @@ -78,6 +79,7 @@ public partial class MongoRepository .Set(x => x.Samples, agent.Samples) .Set(x => x.IsPublic, agent.IsPublic) .Set(x => x.Type, agent.Type) + .Set(x => x.InheritAgentId, agent.InheritAgentId) .Set(x => x.Disabled, agent.Disabled) .Set(x => x.Profiles, agent.Profiles) .Set(x => x.RoutingRules, agent.RoutingRules) From 972de3d2639829b55e180e8d0adde71317aac60b Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Mon, 29 Jan 2024 15:02:27 -0600 Subject: [PATCH 11/13] fix agent template migrate --- .../Agents/Services/AgentService.CreateAgent.cs | 6 +++--- .../Repository/FileRepository/FileRepository.Agent.cs | 6 +++--- .../Repository/FileRepository/FileRepository.cs | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs index ce74d7c4..01ca0c03 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs @@ -107,9 +107,9 @@ public partial class AgentService foreach (var file in Directory.GetFiles(templateDir)) { var fileName = file.Split(Path.DirectorySeparatorChar).Last(); - var splits = fileName.ToLower().Split('.'); - var name = splits[0]; - var extension = splits[1]; + var splitIdx = fileName.LastIndexOf("."); + var name = fileName.Substring(0, splitIdx); + var extension = fileName.Substring(splitIdx + 1); if (extension.IsEqualTo(_agentSettings.TemplateFormat)) { var content = File.ReadAllText(file); diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs index 01a75d40..c9aebd1e 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs @@ -393,9 +393,9 @@ namespace BotSharp.Core.Repository foreach (var file in Directory.GetFiles(dir)) { var fileName = file.Split(Path.DirectorySeparatorChar).Last(); - var splits = ParseFileNameByPath(fileName.ToLower()); - var name = splits[0]; - var extension = splits[1]; + var splitIdx = fileName.LastIndexOf("."); + var name = fileName.Substring(0, splitIdx); + var extension = fileName.Substring(splitIdx + 1); if (name.IsEqualTo(templateName) && extension.IsEqualTo(_agentSettings.TemplateFormat)) { return File.ReadAllText(file); diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.cs index 94954bf4..cca7d2e7 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.cs @@ -217,9 +217,9 @@ public partial class FileRepository : IBotSharpRepository foreach (var file in Directory.GetFiles(templateDir)) { var fileName = file.Split(Path.DirectorySeparatorChar).Last(); - var splits = fileName.ToLower().Split('.'); - var name = string.Join('.', splits.Take(splits.Length - 1)); - var extension = splits.Last(); + var splitIdx = fileName.LastIndexOf("."); + var name = fileName.Substring(0, splitIdx); + var extension = fileName.Substring(splitIdx + 1); if (extension.Equals(_agentSettings.TemplateFormat, StringComparison.OrdinalIgnoreCase)) { var content = File.ReadAllText(file); From 0b14978af70cf3236d84968fec6b45b9c682ce49 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Mon, 29 Jan 2024 16:14:17 -0600 Subject: [PATCH 12/13] add type in routing rules --- .../Models/RoutingRuleMongoElement.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Models/RoutingRuleMongoElement.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/RoutingRuleMongoElement.cs index 1a40b0f7..571c6d09 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Models/RoutingRuleMongoElement.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/RoutingRuleMongoElement.cs @@ -9,6 +9,7 @@ public class RoutingRuleMongoElement public string Description { get; set; } public bool Required { get; set; } public string? RedirectTo { get; set; } + public string Type { get; set; } public RoutingRuleMongoElement() { @@ -22,7 +23,8 @@ public class RoutingRuleMongoElement Field = routingRule.Field, Description = routingRule.Description, Required = routingRule.Required, - RedirectTo = routingRule.RedirectTo + RedirectTo = routingRule.RedirectTo, + Type = routingRule.Type, }; } @@ -35,7 +37,8 @@ public class RoutingRuleMongoElement Field = rule.Field, Description = rule.Description, Required = rule.Required, - RedirectTo = rule.RedirectTo + RedirectTo = rule.RedirectTo, + Type = rule.Type, }; } } From 3f2d63c10175216e582daf12beaf7dff3482f2b6 Mon Sep 17 00:00:00 2001 From: geffzhang Date: Tue, 30 Jan 2024 19:04:22 +0800 Subject: [PATCH 13/13] feat: upgrade semantic kernel to 1.2 --- .../BotSharp.Plugin.SemanticKernel.csproj | 10 +++- .../SemanticKernelChatCompletionProvider.cs | 19 +++--- .../SemanticKernelMemoryStoreProvider.cs | 6 ++ .../SemanticKernelTextCompletionProvider.cs | 11 ++-- .../SemanticKernelTextEmbeddingProvider.cs | 12 +++- ...arp.Plugin.SemanticKernel.UnitTests.csproj | 4 +- .../Helpers/ResultHelper.cs | 59 +++++++++---------- .../Helpers/SemanticKernelHelper.cs | 34 +++++------ ...manticKernelChatCompletionProviderTests.cs | 29 +++++---- .../SemanticKernelPluginTests.cs | 10 +++- ...manticKernelTextCompletionProviderTests.cs | 17 +----- 11 files changed, 104 insertions(+), 107 deletions(-) diff --git a/src/Plugins/BotSharp.Plugin.SemanticKernel/BotSharp.Plugin.SemanticKernel.csproj b/src/Plugins/BotSharp.Plugin.SemanticKernel/BotSharp.Plugin.SemanticKernel.csproj index fe605288..bc0c0c2d 100644 --- a/src/Plugins/BotSharp.Plugin.SemanticKernel/BotSharp.Plugin.SemanticKernel.csproj +++ b/src/Plugins/BotSharp.Plugin.SemanticKernel/BotSharp.Plugin.SemanticKernel.csproj @@ -1,4 +1,4 @@ - + netstandard2.1 @@ -11,8 +11,8 @@ - - + + @@ -24,4 +24,8 @@ + + + + diff --git a/src/Plugins/BotSharp.Plugin.SemanticKernel/SemanticKernelChatCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.SemanticKernel/SemanticKernelChatCompletionProvider.cs index bf7fbc42..22c7fc68 100644 --- a/src/Plugins/BotSharp.Plugin.SemanticKernel/SemanticKernelChatCompletionProvider.cs +++ b/src/Plugins/BotSharp.Plugin.SemanticKernel/SemanticKernelChatCompletionProvider.cs @@ -6,7 +6,7 @@ using BotSharp.Abstraction.Conversations.Models; using BotSharp.Abstraction.Loggers; using BotSharp.Abstraction.MLTasks; using Microsoft.Extensions.DependencyInjection; -using Microsoft.SemanticKernel; +using Microsoft.SemanticKernel.ChatCompletion; using System; using System.Collections.Generic; using System.Linq; @@ -19,7 +19,7 @@ namespace BotSharp.Plugin.SemanticKernel /// public class SemanticKernelChatCompletionProvider : IChatCompletion { - private Microsoft.SemanticKernel.AI.ChatCompletion.IChatCompletion _kernelChatCompletion; + private Microsoft.SemanticKernel.ChatCompletion.IChatCompletionService _kernelChatCompletion; private IServiceProvider _services; private ITokenStatistics _tokenStatistics; private string? _model = null; @@ -33,7 +33,7 @@ namespace BotSharp.Plugin.SemanticKernel /// /// /// - public SemanticKernelChatCompletionProvider(Microsoft.SemanticKernel.AI.ChatCompletion.IChatCompletion chatCompletion, + public SemanticKernelChatCompletionProvider(IChatCompletionService chatCompletion, IServiceProvider services, ITokenStatistics tokenStatistics) { @@ -55,7 +55,7 @@ namespace BotSharp.Plugin.SemanticKernel var agentService = _services.GetRequiredService(); var instruction = agentService.RenderedInstruction(agent); - var chatHistory = completion.CreateNewChat(instruction); + ChatHistory chatHistory = new ChatHistory(instruction); foreach (var message in conversations) { @@ -69,14 +69,9 @@ namespace BotSharp.Plugin.SemanticKernel } } - var response = await completion.GetChatCompletionsAsync(chatHistory) - .ContinueWith(async t => - { - var result = await t; - var message = await result.First().GetChatMessageAsync(); - return message.Content; - }).ConfigureAwait(false).GetAwaiter().GetResult(); - + var ChatMessage = await completion.GetChatMessageContentsAsync(chatHistory); + var chatMessageContent = ChatMessage?.FirstOrDefault(); + var response = chatMessageContent != null ? chatMessageContent.Content :string.Empty; var msg = new RoleDialogModel(AgentRole.Assistant, response) { CurrentAgentId = agent.Id diff --git a/src/Plugins/BotSharp.Plugin.SemanticKernel/SemanticKernelMemoryStoreProvider.cs b/src/Plugins/BotSharp.Plugin.SemanticKernel/SemanticKernelMemoryStoreProvider.cs index 3f34e76b..444cab1e 100644 --- a/src/Plugins/BotSharp.Plugin.SemanticKernel/SemanticKernelMemoryStoreProvider.cs +++ b/src/Plugins/BotSharp.Plugin.SemanticKernel/SemanticKernelMemoryStoreProvider.cs @@ -9,9 +9,13 @@ namespace BotSharp.Plugin.SemanticKernel { internal class SemanticKernelMemoryStoreProvider : IVectorDb { +#pragma warning disable SKEXP0003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. private readonly IMemoryStore _memoryStore; +#pragma warning restore SKEXP0003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. +#pragma warning disable SKEXP0003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. public SemanticKernelMemoryStoreProvider(IMemoryStore memoryStore) +#pragma warning restore SKEXP0003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. { this._memoryStore = memoryStore; } @@ -46,7 +50,9 @@ namespace BotSharp.Plugin.SemanticKernel public async Task Upsert(string collectionName, int id, float[] vector, string text) { +#pragma warning disable SKEXP0003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. await _memoryStore.UpsertAsync(collectionName, MemoryRecord.LocalRecord(id.ToString(), text, null, vector)); +#pragma warning restore SKEXP0003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. } } } diff --git a/src/Plugins/BotSharp.Plugin.SemanticKernel/SemanticKernelTextCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.SemanticKernel/SemanticKernelTextCompletionProvider.cs index 15791931..91dec640 100644 --- a/src/Plugins/BotSharp.Plugin.SemanticKernel/SemanticKernelTextCompletionProvider.cs +++ b/src/Plugins/BotSharp.Plugin.SemanticKernel/SemanticKernelTextCompletionProvider.cs @@ -3,10 +3,7 @@ using BotSharp.Abstraction.Agents.Models; using BotSharp.Abstraction.Conversations; using BotSharp.Abstraction.Conversations.Models; using BotSharp.Abstraction.Loggers; -using Microsoft; using Microsoft.Extensions.DependencyInjection; -using Microsoft.SemanticKernel; -using Microsoft.SemanticKernel.AI.TextCompletion; using System; using System.Collections.Generic; using System.Linq; @@ -19,7 +16,7 @@ namespace BotSharp.Plugin.SemanticKernel /// public class SemanticKernelTextCompletionProvider : Abstraction.MLTasks.ITextCompletion { - private readonly Microsoft.SemanticKernel.AI.TextCompletion.ITextCompletion _kernelTextCompletion; + private readonly Microsoft.SemanticKernel.TextGeneration.ITextGenerationService _kernelTextCompletion; private readonly IServiceProvider _services; private readonly ITokenStatistics _tokenStatistics; private string? _model = null; @@ -33,7 +30,7 @@ namespace BotSharp.Plugin.SemanticKernel /// /// /// - public SemanticKernelTextCompletionProvider(Microsoft.SemanticKernel.AI.TextCompletion.ITextCompletion textCompletion, + public SemanticKernelTextCompletionProvider(Microsoft.SemanticKernel.TextGeneration.ITextGenerationService textCompletion, IServiceProvider services, ITokenStatistics tokenStatistics) { @@ -61,9 +58,11 @@ namespace BotSharp.Plugin.SemanticKernel var completion = this._kernelTextCompletion; _tokenStatistics.StartTimer(); - var result = await completion.CompleteAsync(text); + var textContent = await completion.GetTextContentsAsync(text); + var result = textContent.FirstOrDefault().Text; _tokenStatistics.StopTimer(); + // After chat completion hook Task.WaitAll(hooks.Select(hook => hook.AfterGenerated(new RoleDialogModel(AgentRole.Assistant, result), new TokenStatsModel diff --git a/src/Plugins/BotSharp.Plugin.SemanticKernel/SemanticKernelTextEmbeddingProvider.cs b/src/Plugins/BotSharp.Plugin.SemanticKernel/SemanticKernelTextEmbeddingProvider.cs index ef6efd49..66884ee8 100644 --- a/src/Plugins/BotSharp.Plugin.SemanticKernel/SemanticKernelTextEmbeddingProvider.cs +++ b/src/Plugins/BotSharp.Plugin.SemanticKernel/SemanticKernelTextEmbeddingProvider.cs @@ -1,6 +1,6 @@ using BotSharp.Abstraction.MLTasks; using Microsoft.Extensions.Configuration; -using Microsoft.SemanticKernel.AI.Embeddings; +using Microsoft.SemanticKernel.Embeddings; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -12,13 +12,17 @@ namespace BotSharp.Plugin.SemanticKernel /// public class SemanticKernelTextEmbeddingProvider : ITextEmbedding { - private readonly ITextEmbeddingGeneration _embedding; +#pragma warning disable SKEXP0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + private readonly ITextEmbeddingGenerationService _embedding; +#pragma warning restore SKEXP0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. private readonly IConfiguration _configuration; /// /// Constructor of /// - public SemanticKernelTextEmbeddingProvider(ITextEmbeddingGeneration embedding, IConfiguration configuration) +#pragma warning disable SKEXP0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + public SemanticKernelTextEmbeddingProvider(ITextEmbeddingGenerationService embedding, IConfiguration configuration) +#pragma warning restore SKEXP0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. { this._embedding = embedding; this._configuration = configuration; @@ -33,7 +37,9 @@ namespace BotSharp.Plugin.SemanticKernel /// public async Task GetVectorAsync(string text) { +#pragma warning disable SKEXP0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. return (await this._embedding.GenerateEmbeddingAsync(text)).ToArray(); +#pragma warning restore SKEXP0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. } /// diff --git a/tests/BotSharp.Plugin.SemanticKernel.UnitTests/BotSharp.Plugin.SemanticKernel.UnitTests.csproj b/tests/BotSharp.Plugin.SemanticKernel.UnitTests/BotSharp.Plugin.SemanticKernel.UnitTests.csproj index 81e6d3b6..0b6a9880 100644 --- a/tests/BotSharp.Plugin.SemanticKernel.UnitTests/BotSharp.Plugin.SemanticKernel.UnitTests.csproj +++ b/tests/BotSharp.Plugin.SemanticKernel.UnitTests/BotSharp.Plugin.SemanticKernel.UnitTests.csproj @@ -12,9 +12,9 @@ - + - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/tests/BotSharp.Plugin.SemanticKernel.UnitTests/Helpers/ResultHelper.cs b/tests/BotSharp.Plugin.SemanticKernel.UnitTests/Helpers/ResultHelper.cs index 4a818310..8acc4202 100644 --- a/tests/BotSharp.Plugin.SemanticKernel.UnitTests/Helpers/ResultHelper.cs +++ b/tests/BotSharp.Plugin.SemanticKernel.UnitTests/Helpers/ResultHelper.cs @@ -1,35 +1,34 @@ -using Microsoft.SemanticKernel.AI.ChatCompletion; -using Microsoft.SemanticKernel.AI.TextCompletion; -using Microsoft.SemanticKernel.Orchestration; +using Microsoft.SemanticKernel; +using Microsoft.SemanticKernel.ChatCompletion; -namespace BotSharp.Plugin.SemanticKernel.UnitTests.Helpers -{ - public class ResultHelper : IChatResult, ITextResult - { - public ModelResult ModelResult { get; set; } - private string _response; +//namespace BotSharp.Plugin.SemanticKernel.UnitTests.Helpers +//{ +// public class ResultHelper : KernelContent +// { +// public TextContent ModelResult { get; set; } +// private string _response; - public ResultHelper(string response) - { - ModelResult = new ModelResult(response); - _response = response; - } +// public ResultHelper(string response) +// { +// ModelResult = new TextContent(response); +// _response = response; +// } - public async Task GetChatMessageAsync(CancellationToken cancellationToken = default) - { - return await Task.FromResult(new MockModelResult(_response)); - } +// public async Task GetChatMessageAsync(CancellationToken cancellationToken = default) +// { +// return await Task.FromResult(new MockModelResult(_response)); +// } - public Task GetCompletionAsync(CancellationToken cancellationToken = default) - { - return Task.FromResult(_response); - } +// public Task GetCompletionAsync(CancellationToken cancellationToken = default) +// { +// return Task.FromResult(_response); +// } - public class MockModelResult : ChatMessage - { - public MockModelResult(string content) : base(AuthorRole.Assistant, content, null) - { - } - } - } -} \ No newline at end of file +// public class MockModelResult : ChatMessageContent +// { +// public MockModelResult(string content) : base(AuthorRole.Assistant, content, null) +// { +// } +// } +// } +//} \ No newline at end of file diff --git a/tests/BotSharp.Plugin.SemanticKernel.UnitTests/Helpers/SemanticKernelHelper.cs b/tests/BotSharp.Plugin.SemanticKernel.UnitTests/Helpers/SemanticKernelHelper.cs index 1245a4d2..4920460b 100644 --- a/tests/BotSharp.Plugin.SemanticKernel.UnitTests/Helpers/SemanticKernelHelper.cs +++ b/tests/BotSharp.Plugin.SemanticKernel.UnitTests/Helpers/SemanticKernelHelper.cs @@ -1,16 +1,11 @@ -using Microsoft.SemanticKernel.AI; -using Microsoft.SemanticKernel.AI.ChatCompletion; -using Microsoft.SemanticKernel.AI.TextCompletion; +using Microsoft.SemanticKernel; +using Microsoft.SemanticKernel.ChatCompletion; using Microsoft.SemanticKernel.Services; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using Microsoft.SemanticKernel.TextGeneration; namespace BotSharp.Plugin.SemanticKernel.UnitTests.Helpers { - internal class SemanticKernelHelper : IChatCompletion, ITextCompletion, IAIService + internal class SemanticKernelHelper : IChatCompletionService, ITextGenerationService, IAIService { private Dictionary _attributes = new(); private readonly string _excepted; @@ -22,27 +17,30 @@ namespace BotSharp.Plugin.SemanticKernel.UnitTests.Helpers public IReadOnlyDictionary Attributes => _attributes; + IReadOnlyDictionary IAIService.Attributes => throw new NotImplementedException(); + public ChatHistory CreateNewChat(string? instructions = null) { return new ChatHistory(); } - public Task> GetChatCompletionsAsync(ChatHistory chat, AIRequestSettings? requestSettings = null, CancellationToken cancellationToken = default) + public Task> GetChatMessageContentsAsync(ChatHistory chatHistory, PromptExecutionSettings? executionSettings = null, Kernel? kernel = null, CancellationToken cancellationToken = default) { - return Task.FromResult>(new List { new ResultHelper(_excepted) }); + return Task.FromResult>(new List { new ChatMessageContent(AuthorRole.Assistant, _excepted) }); + } - public Task> GetCompletionsAsync(string text, AIRequestSettings? requestSettings = null, CancellationToken cancellationToken = default) - { - return Task.FromResult>(new List { new ResultHelper(_excepted) }); - } - - public IAsyncEnumerable GetStreamingChatCompletionsAsync(ChatHistory chat, AIRequestSettings? requestSettings = null, CancellationToken cancellationToken = default) + public IAsyncEnumerable GetStreamingChatMessageContentsAsync(ChatHistory chatHistory, PromptExecutionSettings? executionSettings = null, Kernel? kernel = null, CancellationToken cancellationToken = default) { throw new NotImplementedException(); } - public IAsyncEnumerable GetStreamingCompletionsAsync(string text, AIRequestSettings? requestSettings = null, CancellationToken cancellationToken = default) + public Task> GetTextContentsAsync(string prompt, PromptExecutionSettings? executionSettings = null, Kernel? kernel = null, CancellationToken cancellationToken = default) + { + return Task.FromResult>(new List { new TextContent(_excepted) }); + } + + public IAsyncEnumerable GetStreamingTextContentsAsync(string prompt, PromptExecutionSettings? executionSettings = null, Kernel? kernel = null, CancellationToken cancellationToken = default) { throw new NotImplementedException(); } diff --git a/tests/BotSharp.Plugin.SemanticKernel.UnitTests/SemanticKernelChatCompletionProviderTests.cs b/tests/BotSharp.Plugin.SemanticKernel.UnitTests/SemanticKernelChatCompletionProviderTests.cs index 8c564a1a..caf4746e 100644 --- a/tests/BotSharp.Plugin.SemanticKernel.UnitTests/SemanticKernelChatCompletionProviderTests.cs +++ b/tests/BotSharp.Plugin.SemanticKernel.UnitTests/SemanticKernelChatCompletionProviderTests.cs @@ -1,26 +1,25 @@ using BotSharp.Abstraction.Agents; -using BotSharp.Abstraction.Conversations.Models; -using Moq; using BotSharp.Abstraction.Agents.Enums; using BotSharp.Abstraction.Agents.Models; using BotSharp.Abstraction.Conversations; -using Microsoft.SemanticKernel.AI.ChatCompletion; -using Microsoft.SemanticKernel.AI; -using BotSharp.Plugin.SemanticKernel.UnitTests.Helpers; +using BotSharp.Abstraction.Conversations.Models; using BotSharp.Abstraction.Loggers; +using Microsoft.SemanticKernel; +using Microsoft.SemanticKernel.ChatCompletion; +using Moq; namespace BotSharp.Plugin.SemanticKernel.Tests { public class SemanticKernelChatCompletionProviderTests { - private readonly Mock _chatCompletionMock; + private readonly Mock _chatCompletionMock; private readonly Mock _servicesMock; private readonly Mock _tokenStatisticsMock; private readonly SemanticKernelChatCompletionProvider _provider; public SemanticKernelChatCompletionProviderTests() { - _chatCompletionMock = new Mock(); + _chatCompletionMock = new Mock(); _servicesMock = new Mock(); _tokenStatisticsMock = new Mock(); _provider = new SemanticKernelChatCompletionProvider(_chatCompletionMock.Object, _servicesMock.Object, _tokenStatisticsMock.Object); @@ -39,18 +38,18 @@ namespace BotSharp.Plugin.SemanticKernel.Tests _servicesMock.Setup(x => x.GetService(typeof(IEnumerable))) .Returns(new List()); var agentService = new Mock(); - agentService.Setup(x => x.RenderedInstruction(agent)).Returns(""); + agentService.Setup(x => x.RenderedInstruction(agent)).Returns("How can I help you?"); _servicesMock.Setup(x => x.GetService(typeof(IAgentService))) .Returns(agentService.Object); var chatHistoryMock = new Mock(); - _chatCompletionMock.Setup(x => x.CreateNewChat(It.IsAny())).Returns(chatHistoryMock.Object); - _chatCompletionMock.Setup(x => x.GetChatCompletionsAsync(chatHistoryMock.Object, It.IsAny(), It.IsAny())) - .ReturnsAsync(new List - { - new ResultHelper("How can I help you?") - }); - + //_chatCompletionMock.Setup(x => new ChatHistory(It.IsAny())).Returns(chatHistoryMock.Object); + + _chatCompletionMock.Setup(x => x.GetChatMessageContentsAsync(chatHistoryMock.Object, It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(new List + { + new ChatMessageContent(AuthorRole.Assistant,"How can I help you?") + }); // Act var result = await _provider.GetChatCompletions(agent, conversations); diff --git a/tests/BotSharp.Plugin.SemanticKernel.UnitTests/SemanticKernelPluginTests.cs b/tests/BotSharp.Plugin.SemanticKernel.UnitTests/SemanticKernelPluginTests.cs index a1ac3963..99d41024 100644 --- a/tests/BotSharp.Plugin.SemanticKernel.UnitTests/SemanticKernelPluginTests.cs +++ b/tests/BotSharp.Plugin.SemanticKernel.UnitTests/SemanticKernelPluginTests.cs @@ -20,10 +20,14 @@ namespace BotSharp.Plugin.SemanticKernel.Tests services.AddSingleton(config); var plugin = new SemanticKernelPlugin(); - services.AddScoped(x => Mock.Of()); - services.AddScoped(x => Mock.Of()); + services.AddScoped(x => Mock.Of()); + services.AddScoped(x => Mock.Of()); +#pragma warning disable SKEXP0003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. services.AddScoped(x => Mock.Of()); - services.AddScoped(x => Mock.Of()); +#pragma warning restore SKEXP0003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. +#pragma warning disable SKEXP0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + services.AddScoped(x => Mock.Of()); +#pragma warning restore SKEXP0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. services.AddScoped(x => Mock.Of()); diff --git a/tests/BotSharp.Plugin.SemanticKernel.UnitTests/SemanticKernelTextCompletionProviderTests.cs b/tests/BotSharp.Plugin.SemanticKernel.UnitTests/SemanticKernelTextCompletionProviderTests.cs index 89188973..3eb8f8b5 100644 --- a/tests/BotSharp.Plugin.SemanticKernel.UnitTests/SemanticKernelTextCompletionProviderTests.cs +++ b/tests/BotSharp.Plugin.SemanticKernel.UnitTests/SemanticKernelTextCompletionProviderTests.cs @@ -1,20 +1,7 @@ -using BotSharp.Abstraction.Conversations.Models; -using BotSharp.Plugin.SemanticKernel; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.SemanticKernel; -using Microsoft.SemanticKernel.AI.TextCompletion; -using Moq; -using System.Collections.Generic; -using System.Threading.Tasks; -using Xunit; -using BotSharp.Abstraction.Agents.Enums; -using BotSharp.Abstraction.Agents.Models; using BotSharp.Abstraction.Conversations; -using System; -using System.Linq; -using Microsoft; -using Microsoft.SemanticKernel.AI; using BotSharp.Plugin.SemanticKernel.UnitTests.Helpers; +using Microsoft.Extensions.DependencyInjection; +using Moq; namespace BotSharp.Plugin.SemanticKernel.Tests {