diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs index b86e5916..87d8f415 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs @@ -10,7 +10,7 @@ namespace BotSharp.Abstraction.Agents; public interface IAgentService { Task CreateAgent(Agent agent); - Task RefreshAgents(); + Task RefreshAgents(IEnumerable? agentIds = null); Task> GetAgents(AgentFilter filter); Task> GetAgentOptions(List? agentIds = null, bool byName = false); Task> GetAgentUtilityOptions(); diff --git a/src/Infrastructure/BotSharp.Abstraction/Utilities/StringExtensions.cs b/src/Infrastructure/BotSharp.Abstraction/Utilities/StringExtensions.cs index ea6bb8ec..0270133c 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Utilities/StringExtensions.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Utilities/StringExtensions.cs @@ -122,6 +122,11 @@ public static class StringExtensions return s; } + if (value is DateTime d) + { + return d.ToString("o"); + } + if (value is JsonElement elem && elem.ValueKind == JsonValueKind.String) { diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.RefreshAgents.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.RefreshAgents.cs index 9603d1e5..506e00bb 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.RefreshAgents.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.RefreshAgents.cs @@ -6,7 +6,7 @@ namespace BotSharp.Core.Agents.Services; public partial class AgentService { - public async Task RefreshAgents() + public async Task RefreshAgents(IEnumerable? agentIds = null) { string refreshResult; var dbSettings = _services.GetRequiredService(); @@ -28,7 +28,13 @@ public partial class AgentService } var refreshedAgents = new List(); - foreach (var dir in Directory.GetDirectories(agentDir)) + var dirs = Directory.GetDirectories(agentDir); + if (!agentIds.IsNullOrEmpty()) + { + dirs = dirs.Where(x => agentIds.Contains(x.Split(Path.DirectorySeparatorChar).Last())).ToArray(); + } + + foreach (var dir in dirs) { try { @@ -78,7 +84,7 @@ public partial class AgentService } else { - refreshResult = "No agent gets refreshed!"; + refreshResult = "No agent gets migrated!"; } _logger.LogInformation(refreshResult); diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.Rendering.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.Rendering.cs index ffaffb47..9059dbf2 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.Rendering.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.Rendering.cs @@ -17,13 +17,14 @@ public partial class AgentService instructions.AddRange(secondaryInstructions); // update states + var renderDict = new Dictionary(agent.TemplateDict); foreach (var t in conv.States.GetStates()) { - agent.TemplateDict[t.Key] = t.Value; + renderDict[t.Key] = t.Value; } - agent.TemplateDict[TemplateRenderConstant.RENDER_AGENT] = agent; - var res = render.Render(string.Join("\r\n", instructions), agent.TemplateDict); + renderDict[TemplateRenderConstant.RENDER_AGENT] = agent; + var res = render.Render(string.Join("\r\n", instructions), renderDict); return res; } @@ -143,4 +144,4 @@ public partial class AgentService return result.IsEqualTo("visible"); } -} \ No newline at end of file +} diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeFunction.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeFunction.cs index 1001dede..20c691f8 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeFunction.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeFunction.cs @@ -64,7 +64,7 @@ public partial class RoutingService } catch (JsonException ex) { - _logger.LogError($"The input does not contain any JSON tokens:\r\n{message.Content}"); + _logger.LogError($"The input does not contain any JSON tokens:\r\n{message.Content}\r\n{ex.Message}"); message.StopCompletion = true; message.Content = ex.Message; } diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs index 2b2a72f6..4543fe19 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs @@ -111,9 +111,9 @@ public class AgentController : ControllerBase [BotSharpAuth] [HttpPost("/refresh-agents")] - public async Task RefreshAgents() + public async Task RefreshAgents([FromBody] AgentMigrationModel request) { - return await _agentService.RefreshAgents(); + return await _agentService.RefreshAgents(request?.AgentIds); } [HttpPut("/agent/file/{agentId}")] diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/Request/AgentMigrationModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/Request/AgentMigrationModel.cs new file mode 100644 index 00000000..19053c65 --- /dev/null +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/Request/AgentMigrationModel.cs @@ -0,0 +1,10 @@ +using System.Text.Json.Serialization; + +namespace BotSharp.OpenAPI.ViewModels.Agents; + +public class AgentMigrationModel +{ + [JsonPropertyName("agent_ids")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IEnumerable? AgentIds { get; set; } +} diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.DoAction.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.DoAction.cs index 45c42089..201fe7c3 100644 --- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.DoAction.cs +++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.DoAction.cs @@ -55,15 +55,23 @@ public partial class PlaywrightWebDriver } else if (action.Action == BroswerActionEnum.DropDown) { - await locator.ClickAsync(); - var optionLocator = page.Locator($"//div[text()='{action.Content}']"); - var optionCount = await optionLocator.CountAsync(); ; - if (optionCount == 0) + var tagName = await locator.EvaluateAsync("el => el.tagName.toLowerCase()"); + if (tagName == "select") { - Serilog.Log.Error($"Dropdown option not found: {action.Content}"); - return; + await HandleSelectDropDownAsync(page, locator, action); + } + else + { + await locator.ClickAsync(); + var optionLocator = page.Locator($"//div[text()='{action.Content}']"); + var optionCount = await optionLocator.CountAsync(); + if (optionCount == 0) + { + Serilog.Log.Error($"Dropdown option not found: {action.Content}"); + return; + } + await optionLocator.First.ClickAsync(); } - await optionLocator.First.ClickAsync(); } else if (action.Action == BroswerActionEnum.InputText) { @@ -247,4 +255,29 @@ public partial class PlaywrightWebDriver return track; } + + private async Task HandleSelectDropDownAsync(IPage page, ILocator locator, ElementActionArgs action) + { + if (string.IsNullOrWhiteSpace(action.Content)) + { + throw new InvalidOperationException("Dropdown target option (action.Content) cannot be null or empty when using a