diff --git a/Directory.Build.props b/Directory.Build.props
index 4233fb32..6716a3c7 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -2,7 +2,7 @@
net8.0
12.0
- 3.0.0
+ 4.0.0
true
false
diff --git a/README.md b/README.md
index e5c3684a..f8f76eb4 100644
--- a/README.md
+++ b/README.md
@@ -23,7 +23,7 @@ It's written in C# running on .Net Core that is full cross-platform framework, t
* Built-in multi-agents and conversation with state management.
* Support multiple LLM Planning approaches to handle different tasks from simple to complex.
* Built-in RAG related interfaces, Memory based vector searching.
-* Support multiple AI platforms (ChatGPT 3.5 / 4.0, PaLM 2, LLaMA 3, Claude Sonnet 3.5, HuggingFace).
+* Support multiple AI platforms (ChatGPT 3.5/ 4o/ o1, Gemini 2, LLaMA 3, Claude Sonnet 3.5, HuggingFace).
* Allow multiple agents with different responsibilities cooperate to complete complex tasks.
* Build, test, evaluate and audit your LLM agent in one place.
* Build-in `BotSharp UI` written in [SvelteKit](https://kit.svelte.dev/).
@@ -79,6 +79,7 @@ BotSharp uses component design, the kernel is kept to a minimum, and business fu
#### Data Storages
- BotSharp.Core.Repository
- BotSharp.Plugin.MongoStorage
+- [BotSharp.Plugin.LiteDBStorage](https://github.com/GreenShadeZhang/BotSharp/tree/dev_litedb/src/Plugins/BotSharp.Plugin.LiteDBStorage)
- BotSharp.Plugin.TencentCos
#### LLMs
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentField.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentField.cs
index 346bcf31..2a9508d7 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentField.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentField.cs
@@ -19,6 +19,7 @@ public enum AgentField
LlmConfig,
Utility,
KnowledgeBase,
+ Rule,
MaxMessageCount
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentRuleHook.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentRuleHook.cs
new file mode 100644
index 00000000..8a19a561
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentRuleHook.cs
@@ -0,0 +1,6 @@
+namespace BotSharp.Abstraction.Agents;
+
+public interface IAgentRuleHook
+{
+ void AddRules(List rules);
+}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs
index 91beea8b..2ec4ff92 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs
@@ -58,6 +58,4 @@ public interface IAgentService
Task> GetUserAgents(string userId);
PluginDef GetPlugin(string agentId);
-
- IEnumerable GetAgentUtilityOptions();
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs
index 566df050..96aa070c 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs
@@ -99,6 +99,11 @@ public class Agent
///
public List Utilities { get; set; } = new();
+ ///
+ /// Agent rules
+ ///
+ public List Rules { get; set; } = new();
+
///
/// Agent knowledge bases
///
@@ -154,6 +159,7 @@ public class Agent
MaxMessageCount = agent.MaxMessageCount,
Profiles = agent.Profiles,
RoutingRules = agent.RoutingRules,
+ Rules = agent.Rules,
LlmConfig = agent.LlmConfig,
KnowledgeBases = agent.KnowledgeBases,
CreatedDateTime = agent.CreatedDateTime,
@@ -269,6 +275,12 @@ public class Agent
return this;
}
+ public Agent SetRules(List rules)
+ {
+ Rules = rules ?? [];
+ return this;
+ }
+
public Agent SetLlmConfig(AgentLlmConfig? llmConfig)
{
LlmConfig = llmConfig;
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentRule.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentRule.cs
new file mode 100644
index 00000000..5c3a276e
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentRule.cs
@@ -0,0 +1,13 @@
+namespace BotSharp.Abstraction.Agents.Models;
+
+public class AgentRule
+{
+ public string Name { get; set; }
+ public bool Disabled { get; set; }
+
+ [JsonPropertyName("event_name")]
+ public string EventName { get; set; }
+
+ [JsonPropertyName("entity_type")]
+ public string EntityType { get; set; }
+}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Browsing/IWebBrowser.cs b/src/Infrastructure/BotSharp.Abstraction/Browsing/IWebBrowser.cs
index ff2c4a7d..9386dd8a 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Browsing/IWebBrowser.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Browsing/IWebBrowser.cs
@@ -28,4 +28,5 @@ public interface IWebBrowser
Task CloseCurrentPage(MessageInfo message);
Task SendHttpRequest(MessageInfo message, HttpRequestParams actionParams);
Task GetAttributeValue(MessageInfo message, ElementLocatingArgs location);
+ Task SetAttributeValue(MessageInfo message, ElementLocatingArgs location);
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/BrowserActionArgs.cs b/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/BrowserActionArgs.cs
index 21bdf6ab..7987b3a5 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/BrowserActionArgs.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/BrowserActionArgs.cs
@@ -3,4 +3,6 @@ namespace BotSharp.Abstraction.Browsing.Models;
public class BrowserActionArgs
{
public bool Headless { get; set; }
+ public string? UserDataDir { get; set; }
+ public string? RemoteHostUrl { get; set; }
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/BrowserActionResult.cs b/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/BrowserActionResult.cs
index 1867a687..e2f11972 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/BrowserActionResult.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/BrowserActionResult.cs
@@ -8,6 +8,10 @@ public class BrowserActionResult
public string? StackTrace { get; set; }
public string? Selector { get; set; }
public string? Body { get; set; }
+ ///
+ /// Page open in new tab after button click
+ ///
+ public string? UrlAfterAction { get; set; }
public bool IsHighlighted { get; set; }
public override string ToString()
diff --git a/src/Infrastructure/BotSharp.Abstraction/Http/IHttpRequestHook.cs b/src/Infrastructure/BotSharp.Abstraction/Http/IHttpRequestHook.cs
new file mode 100644
index 00000000..18b96e77
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/Http/IHttpRequestHook.cs
@@ -0,0 +1,8 @@
+using System.Net.Http.Headers;
+
+namespace BotSharp.Abstraction.Http;
+
+public interface IHttpRequestHook
+{
+ void OnAddHttpHeaders(HttpHeaders headers);
+}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs
index 4391f970..70fecc8a 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs
@@ -33,6 +33,7 @@ public interface IBotSharpRepository : IHaveServiceProvider
List GetUserByIds(List ids) => throw new NotImplementedException();
List GetUsersByAffiliateId(string affiliateId) => throw new NotImplementedException();
User? GetUserByUserName(string userName) => throw new NotImplementedException();
+ void UpdateUserName(string userId, string userName) => throw new NotImplementedException();
Dashboard? GetDashboard(string id = null) => throw new NotImplementedException();
void CreateUser(User user) => throw new NotImplementedException();
void UpdateExistUser(string userId, User user) => throw new NotImplementedException();
@@ -49,6 +50,7 @@ public interface IBotSharpRepository : IHaveServiceProvider
PagedItems GetUsers(UserFilter filter) => throw new NotImplementedException();
User? GetUserDetails(string userId, bool includeAgent = false) => throw new NotImplementedException();
bool UpdateUser(User user, bool updateUserAgents = false) => throw new NotImplementedException();
+
#endregion
#region Agent
diff --git a/src/Infrastructure/BotSharp.Abstraction/Users/IAuthenticationHook.cs b/src/Infrastructure/BotSharp.Abstraction/Users/IAuthenticationHook.cs
index d953271f..939d509e 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Users/IAuthenticationHook.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Users/IAuthenticationHook.cs
@@ -1,5 +1,4 @@
using BotSharp.Abstraction.Users.Models;
-using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
namespace BotSharp.Abstraction.Users;
diff --git a/src/Infrastructure/BotSharp.Abstraction/Users/IUserService.cs b/src/Infrastructure/BotSharp.Abstraction/Users/IUserService.cs
index 134ca25b..5e56b431 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Users/IUserService.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Users/IUserService.cs
@@ -17,6 +17,7 @@ public interface IUserService
Task GetAffiliateToken(string authorization);
Task GetAdminToken(string authorization);
Task GetToken(string authorization);
+ Task CreateTokenByUser(User user);
Task GetMyProfile();
Task VerifyUserNameExisting(string userName);
Task VerifyEmailExisting(string email);
diff --git a/src/Infrastructure/BotSharp.Abstraction/Users/Models/User.cs b/src/Infrastructure/BotSharp.Abstraction/Users/Models/User.cs
index 7699a58b..8d136dc5 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Users/Models/User.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Users/Models/User.cs
@@ -23,7 +23,6 @@ public class User
public bool Verified { get; set; }
public string RegionCode { get; set; } = "CN";
public string? AffiliateId { get; set; }
- public string? ReferralCode { get; set; }
public string? EmployeeId { get; set; }
public bool IsDisabled { get; set; }
public IEnumerable Permissions { get; set; } = [];
diff --git a/src/Infrastructure/BotSharp.Abstraction/Users/Models/UserActivationModel.cs b/src/Infrastructure/BotSharp.Abstraction/Users/Models/UserActivationModel.cs
index 904bd936..3ea4a915 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Users/Models/UserActivationModel.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Users/Models/UserActivationModel.cs
@@ -4,4 +4,5 @@ public class UserActivationModel
{
public string UserName { get; set; }
public string VerificationCode { get; set; }
+ public string RegionCode { get; set; } = "CN";
}
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs
index 584a4c7e..6889336a 100644
--- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs
+++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs
@@ -40,6 +40,7 @@ public partial class AgentService
record.Samples = agent.Samples ?? [];
record.Utilities = agent.Utilities ?? [];
record.KnowledgeBases = agent.KnowledgeBases ?? [];
+ record.Rules = agent.Rules ?? [];
if (agent.LlmConfig != null && !agent.LlmConfig.IsInherit)
{
record.LlmConfig = agent.LlmConfig;
@@ -104,6 +105,7 @@ public partial class AgentService
.SetSamples(foundAgent.Samples)
.SetUtilities(foundAgent.Utilities)
.SetKnowledgeBases(foundAgent.KnowledgeBases)
+ .SetRules(foundAgent.Rules)
.SetLlmConfig(foundAgent.LlmConfig);
_db.UpdateAgent(clonedAgent, AgentField.All);
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.cs
index 80cdc56c..c54c4fd8 100644
--- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.cs
+++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.cs
@@ -53,15 +53,4 @@ public partial class AgentService : IAgentService
var userAgents = _db.GetUserAgents(userId);
return userAgents;
}
-
- public IEnumerable GetAgentUtilityOptions()
- {
- var utilities = new List();
- var hooks = _services.GetServices();
- foreach (var hook in hooks)
- {
- hook.AddUtilities(utilities);
- }
- return utilities.Where(x => !string.IsNullOrWhiteSpace(x.Name)).OrderBy(x => x.Name).ToList();
- }
}
diff --git a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj
index 1c9955aa..d1232c5e 100644
--- a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj
+++ b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj
@@ -190,10 +190,10 @@
-
+
-
+
diff --git a/src/Infrastructure/BotSharp.Core/BotSharpCoreExtensions.cs b/src/Infrastructure/BotSharp.Core/BotSharpCoreExtensions.cs
index af8a9324..f588b4d1 100644
--- a/src/Infrastructure/BotSharp.Core/BotSharpCoreExtensions.cs
+++ b/src/Infrastructure/BotSharp.Core/BotSharpCoreExtensions.cs
@@ -105,6 +105,11 @@ public static class BotSharpCoreExtensions
var dbSettings = new BotSharpDatabaseSettings();
config.Bind("Database", dbSettings);
+ if (string.IsNullOrEmpty(dbSettings.Redis))
+ {
+ return;
+ }
+
services.AddSingleton(ConnectionMultiplexer.Connect(dbSettings.Redis));
services.AddSingleton();
services.AddSingleton();
diff --git a/src/Infrastructure/BotSharp.Core/Infrastructures/DistributedLocker.cs b/src/Infrastructure/BotSharp.Core/Infrastructures/DistributedLocker.cs
index 48ff193f..c87dbe45 100644
--- a/src/Infrastructure/BotSharp.Core/Infrastructures/DistributedLocker.cs
+++ b/src/Infrastructure/BotSharp.Core/Infrastructures/DistributedLocker.cs
@@ -6,12 +6,12 @@ namespace BotSharp.Core.Infrastructures;
public class DistributedLocker : IDistributedLocker
{
- private readonly IConnectionMultiplexer _redis;
+ private readonly IServiceProvider _services;
private readonly ILogger _logger;
- public DistributedLocker(IConnectionMultiplexer redis, ILogger logger)
+ public DistributedLocker(IServiceProvider services, ILogger logger)
{
- _redis = redis;
+ _services = services;
_logger = logger;
}
@@ -19,7 +19,8 @@ public class DistributedLocker : IDistributedLocker
{
var timeout = TimeSpan.FromSeconds(timeoutInSeconds);
- var @lock = new RedisDistributedLock(resource, _redis.GetDatabase());
+ var redis = _services.GetRequiredService();
+ var @lock = new RedisDistributedLock(resource, redis.GetDatabase());
await using (var handle = await @lock.TryAcquireAsync(timeout))
{
if (handle == null)
@@ -37,7 +38,8 @@ public class DistributedLocker : IDistributedLocker
{
var timeout = TimeSpan.FromSeconds(timeoutInSeconds);
- var @lock = new RedisDistributedLock(resource, _redis.GetDatabase());
+ var redis = _services.GetRequiredService();
+ var @lock = new RedisDistributedLock(resource, redis.GetDatabase());
using (var handle = @lock.TryAcquire(timeout))
{
if (handle == null)
diff --git a/src/Infrastructure/BotSharp.Core/Infrastructures/Events/RedisPublisher.cs b/src/Infrastructure/BotSharp.Core/Infrastructures/Events/RedisPublisher.cs
index 89de2453..cee5cc6f 100644
--- a/src/Infrastructure/BotSharp.Core/Infrastructures/Events/RedisPublisher.cs
+++ b/src/Infrastructure/BotSharp.Core/Infrastructures/Events/RedisPublisher.cs
@@ -39,10 +39,7 @@ public class RedisPublisher : IEventPublisher
// Add a message to the stream, keeping only the latest 1 million messages
var messageId = await db.StreamAddAsync(channel,
- [
- new NameValueEntry("message", message),
- new NameValueEntry("timestamp", DateTime.UtcNow.ToString("o"))
- ],
+ AssembleMessage(message),
maxLength: 1000 * 10000);
_logger.LogInformation($"Published message {channel} {message} ({messageId})");
@@ -82,6 +79,25 @@ public class RedisPublisher : IEventPublisher
return exists;
}
+ public static NameValueEntry[] AssembleMessage(RedisValue message)
+ {
+ return
+ [
+ new NameValueEntry("message", message),
+ new NameValueEntry("timestamp", DateTime.UtcNow.ToString("o"))
+ ];
+ }
+
+ public static NameValueEntry[] AssembleErrorMessage(RedisValue message, string error)
+ {
+ return
+ [
+ new NameValueEntry("message", message),
+ new NameValueEntry("timestamp", DateTime.UtcNow.ToString("o")),
+ new NameValueEntry("error", error)
+ ];
+ }
+
public async Task ReDispatchAsync(string channel, int count = 10, string order = "asc")
{
var db = _redis.GetDatabase();
@@ -93,10 +109,10 @@ public class RedisPublisher : IEventPublisher
try
{
- var messageId = await db.StreamAddAsync(channel, [
- new NameValueEntry("message", entry.Values[0].Value),
- new NameValueEntry("timestamp", DateTime.UtcNow.ToString("o"))
- ]);
+ var message = entry.Values.First(x => x.Name == "message").Value;
+ var messageId = await db.StreamAddAsync(channel,
+ AssembleMessage(message),
+ maxLength: 1000 * 10000);
_logger.LogWarning($"ReDispatched message: {channel} {entry.Values[0].Value} ({messageId})");
@@ -164,20 +180,7 @@ public class RedisPublisher : IEventPublisher
var db = _redis.GetDatabase();
var entries = await db.StreamRangeAsync(channel, "-", "+", count: count, messageOrder: Order.Ascending);
- foreach (var entry in entries)
- {
- _logger.LogInformation($"Fetched message: {channel} {entry.Values[0].Value} ({entry.Id})");
-
- try
- {
- await db.StreamDeleteAsync(channel, [entry.Id]);
-
- _logger.LogWarning($"Deleted message: {channel} {entry.Values[0].Value} ({entry.Id})");
- }
- catch (Exception ex)
- {
- _logger.LogError($"Error processing message: {ex.Message}, event id: {channel} {entry.Id}\r\n{ex}");
- }
- }
+ var deletedCount = await db.StreamDeleteAsync(channel, entries.Select(x => x.Id).ToArray());
+ _logger.LogWarning($"Deleted {deletedCount} messages from Redis stream {channel}");
}
}
diff --git a/src/Infrastructure/BotSharp.Core/Infrastructures/Events/RedisSubscriber.cs b/src/Infrastructure/BotSharp.Core/Infrastructures/Events/RedisSubscriber.cs
index 9a3c9982..61db1d33 100644
--- a/src/Infrastructure/BotSharp.Core/Infrastructures/Events/RedisSubscriber.cs
+++ b/src/Infrastructure/BotSharp.Core/Infrastructures/Events/RedisSubscriber.cs
@@ -42,6 +42,8 @@ public class RedisSubscriber : IEventSubscriber
await CreateConsumerGroup(db, channel, group);
}
+ await CreateConsumerGroup(db, $"{channel}-Error", group);
+
var consumer = Environment.MachineName;
if (port.HasValue)
{
@@ -58,28 +60,36 @@ public class RedisSubscriber : IEventSubscriber
break;
}
- if (priorityEnabled)
+ try
{
- if (await HandleGroupMessage(db, $"{channel}-{EventPriority.High}", group, consumer, received) > 0)
+ if (priorityEnabled)
{
- continue;
- }
+ if (await HandleGroupMessage(db, $"{channel}-{EventPriority.High}", group, consumer, received, $"{channel}-Error") > 0)
+ {
+ continue;
+ }
- if (await HandleGroupMessage(db, $"{channel}-{EventPriority.Medium}", group, consumer, received) > 0)
+ if (await HandleGroupMessage(db, $"{channel}-{EventPriority.Medium}", group, consumer, received, $"{channel}-Error") > 0)
+ {
+ continue;
+ }
+
+ await HandleGroupMessage(db, $"{channel}-{EventPriority.Low}", group, consumer, received, $"{channel}-Error");
+ }
+ else
{
- continue;
+ await HandleGroupMessage(db, channel, group, consumer, received, $"{channel}-Error");
}
-
- await HandleGroupMessage(db, $"{channel}-{EventPriority.Low}", group, consumer, received);
}
- else
+ catch (Exception ex)
{
- await HandleGroupMessage(db, channel, group, consumer, received);
+ _logger.LogError($"Error processing message: {ex.Message}\r\n{ex}");
+ await Task.Delay(1000 * 60);
}
}
}
- private async Task HandleGroupMessage(IDatabase db, string channel, string group, string consumer, Func received)
+ private async Task HandleGroupMessage(IDatabase db, string channel, string group, string consumer, Func received, string errorChannel)
{
var entries = await db.StreamReadGroupAsync(channel, group, consumer, count: 1);
foreach (var entry in entries)
@@ -90,13 +100,24 @@ public class RedisSubscriber : IEventSubscriber
try
{
await received(channel, entry.Values[0].Value);
-
- // Optionally delete the message to save space
- await db.StreamDeleteAsync(channel, [entry.Id]);
}
catch (Exception ex)
{
- _logger.LogError($"Error processing message: {ex.Message}, event id: {channel} {entry.Id}\r\n{ex}");
+ _logger.LogError($"Error processing message: {ex.Message}, event id: {channel} {entry.Id} {entry.Values[0].Value}");
+
+ // Add a message to the Error stream, keeping only the latest 1 million messages
+ await db.StreamAddAsync(errorChannel,
+ RedisPublisher.AssembleErrorMessage(entry.Values[0].Value, ex.Message),
+ messageId: entry.Id,
+ maxLength: 1000 * 10000);
+
+ // Slow down the consumer if there are errors
+ await Task.Delay(1000 * 10);
+ }
+ finally
+ {
+ var deletedCount = await db.StreamDeleteAsync(channel, [entry.Id]);
+ _logger.LogInformation($"Handled message {entry.Id}: {deletedCount == 1}");
}
}
diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs
index 0a8d5b65..d38b2a89 100644
--- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs
+++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs
@@ -60,6 +60,9 @@ namespace BotSharp.Core.Repository
case AgentField.KnowledgeBase:
UpdateAgentKnowledgeBases(agent.Id, agent.KnowledgeBases);
break;
+ case AgentField.Rule:
+ UpdateAgentRules(agent.Id, agent.Rules);
+ break;
case AgentField.MaxMessageCount:
UpdateAgentMaxMessageCount(agent.Id, agent.MaxMessageCount);
break;
@@ -184,6 +187,19 @@ namespace BotSharp.Core.Repository
File.WriteAllText(agentFile, json);
}
+ private void UpdateAgentRules(string agentId, List rules)
+ {
+ if (rules == null) return;
+
+ var (agent, agentFile) = GetAgentFromFile(agentId);
+ if (agent == null) return;
+
+ agent.Rules = rules;
+ agent.UpdatedDateTime = DateTime.UtcNow;
+ var json = JsonSerializer.Serialize(agent, _options);
+ File.WriteAllText(agentFile, json);
+ }
+
private void UpdateAgentRoutingRules(string agentId, List rules)
{
if (rules == null) return;
@@ -240,7 +256,7 @@ namespace BotSharp.Core.Repository
var text = JsonSerializer.Serialize(func, _options);
var file = Path.Combine(functionDir, $"{func.Name}.json");
File.WriteAllText(file, text);
- Thread.Sleep(100);
+ Thread.Sleep(50);
}
}
@@ -328,6 +344,7 @@ namespace BotSharp.Core.Repository
agent.Utilities = inputAgent.Utilities;
agent.KnowledgeBases = inputAgent.KnowledgeBases;
agent.RoutingRules = inputAgent.RoutingRules;
+ agent.Rules = inputAgent.Rules;
agent.LlmConfig = inputAgent.LlmConfig;
agent.MaxMessageCount = inputAgent.MaxMessageCount;
agent.UpdatedDateTime = DateTime.UtcNow;
diff --git a/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs b/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs
index 9bc436a7..18deb7d8 100644
--- a/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs
+++ b/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs
@@ -62,7 +62,7 @@ public class UserService : IUserService
if (!string.IsNullOrWhiteSpace(user.Phone))
{
- record = db.GetUserByPhone(user.Phone);
+ record = db.GetUserByPhone(user.Phone, regionCode: (string.IsNullOrWhiteSpace(user.RegionCode) ? "CN" : user.RegionCode));
}
if (record == null && !string.IsNullOrWhiteSpace(user.Email))
@@ -112,7 +112,7 @@ public class UserService : IUserService
db.UpdateExistUser(hasRegisterId, record);
}
- _logger.LogWarning($"Created new user account: {record.Id} {record.UserName}");
+ _logger.LogWarning($"Created new user account: {record.Id} {record.UserName}, RegionCode: {record.RegionCode}");
Utilities.ClearCache();
var hooks = _services.GetServices();
@@ -127,7 +127,8 @@ public class UserService : IUserService
public async Task UpdatePassword(string password, string verificationCode)
{
var db = _services.GetRequiredService();
- var record = db.GetUserByUserName(_user.UserName);
+
+ var record = db.GetUserById(_user.Id);
if (record == null)
{
@@ -473,7 +474,7 @@ public class UserService : IUserService
var record = id.Contains("@") ? db.GetUserByEmail(id) : db.GetUserByUserName(id);
if (record == null)
{
- record = db.GetUserByPhone(id);
+ record = db.GetUserByPhone(id, regionCode: (string.IsNullOrWhiteSpace(model.RegionCode) ? "CN" : model.RegionCode));
}
if (record == null)
@@ -505,6 +506,20 @@ public class UserService : IUserService
return token;
}
+ public async Task CreateTokenByUser(User user)
+ {
+ var accessToken = GenerateJwtToken(user);
+ var jwt = new JwtSecurityTokenHandler().ReadJwtToken(accessToken);
+ var token = new Token
+ {
+ AccessToken = accessToken,
+ ExpireTime = jwt.Payload.Exp.Value,
+ TokenType = "Bearer",
+ Scope = "api"
+ };
+ return token;
+ }
+
public async Task VerifyUserNameExisting(string userName)
{
if (string.IsNullOrEmpty(userName))
@@ -646,7 +661,7 @@ public class UserService : IUserService
if (!string.IsNullOrEmpty(user.Phone))
{
- record = db.GetUserByPhone(user.Phone);
+ record = db.GetUserByPhone(user.Phone, regionCode: (string.IsNullOrWhiteSpace(user.RegionCode) ? "CN" : user.RegionCode));
}
if (record == null)
@@ -695,7 +710,7 @@ public class UserService : IUserService
var curUser = await GetMyProfile();
var db = _services.GetRequiredService();
var record = db.GetUserById(curUser.Id);
- var existPhone = db.GetUserByPhone(phone);
+ var existPhone = db.GetUserByPhone(phone, regionCode: regionCode);
if (record == null || (existPhone != null && existPhone.RegionCode == regionCode))
{
diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs
index 1885365d..6efb7104 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs
@@ -152,6 +152,24 @@ public class AgentController : ControllerBase
[HttpGet("/agent/utility/options")]
public IEnumerable GetAgentUtilityOptions()
{
- return _agentService.GetAgentUtilityOptions();
+ var utilities = new List();
+ var hooks = _services.GetServices();
+ foreach (var hook in hooks)
+ {
+ hook.AddUtilities(utilities);
+ }
+ return utilities.Where(x => !string.IsNullOrWhiteSpace(x.Name)).OrderBy(x => x.Name).ToList();
+ }
+
+ [HttpGet("/agent/rule/options")]
+ public IEnumerable GetAgentRuleOptions()
+ {
+ var rules = new List();
+ var hooks = _services.GetServices();
+ foreach (var hook in hooks)
+ {
+ hook.AddRules(rules);
+ }
+ return rules.Where(x => !string.IsNullOrWhiteSpace(x.Name)).OrderBy(x => x.Name).ToList();
}
}
\ No newline at end of file
diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/UserController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/UserController.cs
index 9d652a3e..75b33c73 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/UserController.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/UserController.cs
@@ -1,4 +1,3 @@
-using BotSharp.Abstraction.Users.Enums;
using BotSharp.Abstraction.Users.Settings;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
@@ -244,7 +243,7 @@ public class UserController : ControllerBase
var file = fileStorage.GetUserAvatar();
if (string.IsNullOrEmpty(file))
{
- return NotFound();
+ return NoContent();
}
return BuildFileResult(file);
}
diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentCreationModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentCreationModel.cs
index 3caba6ae..a0e8f790 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentCreationModel.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentCreationModel.cs
@@ -55,6 +55,7 @@ public class AgentCreationModel
public List Utilities { get; set; } = new();
public List RoutingRules { get; set; } = new();
public List KnowledgeBases { get; set; } = new();
+ public List Rules { get; set; } = new();
public AgentLlmConfig? LlmConfig { get; set; }
public Agent ToAgent()
@@ -78,6 +79,7 @@ public class AgentCreationModel
Profiles = Profiles,
LlmConfig = LlmConfig,
KnowledgeBases = KnowledgeBases,
+ Rules = Rules,
RoutingRules = RoutingRules?.Select(x => RoutingRuleUpdateModel.ToDomainElement(x))?.ToList() ?? [],
};
}
diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentUpdateModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentUpdateModel.cs
index 66618186..8e268b97 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentUpdateModel.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentUpdateModel.cs
@@ -75,6 +75,9 @@ public class AgentUpdateModel
[JsonPropertyName("routing_rules")]
public List? RoutingRules { get; set; }
+ [JsonPropertyName("rules")]
+ public List? Rules { get; set; }
+
[JsonPropertyName("llm_config")]
public AgentLlmConfig? LlmConfig { get; set; }
@@ -89,15 +92,16 @@ public class AgentUpdateModel
MergeUtility = MergeUtility,
MaxMessageCount = MaxMessageCount,
Type = Type,
- Profiles = Profiles ?? new List(),
- RoutingRules = RoutingRules?.Select(x => RoutingRuleUpdateModel.ToDomainElement(x))?.ToList() ?? new List(),
+ Profiles = Profiles ?? [],
+ RoutingRules = RoutingRules?.Select(x => RoutingRuleUpdateModel.ToDomainElement(x))?.ToList() ?? [],
Instruction = Instruction ?? string.Empty,
- ChannelInstructions = ChannelInstructions ?? new List(),
- Templates = Templates ?? new List(),
- Functions = Functions ?? new List(),
- Responses = Responses ?? new List(),
- Utilities = Utilities ?? new List(),
+ ChannelInstructions = ChannelInstructions ?? [],
+ Templates = Templates ?? [],
+ Functions = Functions ?? [],
+ Responses = Responses ?? [],
+ Utilities = Utilities ?? [],
KnowledgeBases = KnowledgeBases ?? [],
+ Rules = Rules ?? [],
LlmConfig = LlmConfig
};
diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs
index e9479109..de4a13ba 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs
@@ -28,6 +28,9 @@ public class AgentViewModel
[JsonPropertyName("knowledge_bases")]
public List KnowledgeBases { get; set; }
+ [JsonPropertyName("rules")]
+ public List Rules { get; set; }
+
[JsonPropertyName("is_public")]
public bool IsPublic { get; set; }
@@ -72,20 +75,21 @@ public class AgentViewModel
Description = agent.Description,
Type = agent.Type,
Instruction = agent.Instruction,
- ChannelInstructions = agent.ChannelInstructions,
- Templates = agent.Templates,
- Functions = agent.Functions,
- Responses = agent.Responses,
- Samples = agent.Samples,
- Utilities = agent.Utilities,
- KnowledgeBases = agent.KnowledgeBases,
+ ChannelInstructions = agent.ChannelInstructions ?? [],
+ Templates = agent.Templates ?? [],
+ Functions = agent.Functions ?? [],
+ Responses = agent.Responses ?? [],
+ Samples = agent.Samples ?? [],
+ Utilities = agent.Utilities ?? [],
+ KnowledgeBases = agent.KnowledgeBases ?? [],
IsPublic= agent.IsPublic,
Disabled = agent.Disabled,
MergeUtility = agent.MergeUtility,
IconUrl = agent.IconUrl,
MaxMessageCount = agent.MaxMessageCount,
- Profiles = agent.Profiles ?? new List(),
- RoutingRules = agent.RoutingRules,
+ Profiles = agent.Profiles ?? [],
+ RoutingRules = agent.RoutingRules ?? [],
+ Rules = agent.Rules ?? [],
LlmConfig = agent.LlmConfig,
Plugin = agent.Plugin,
CreatedDateTime = agent.CreatedDateTime,
diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Users/UserCreationModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Users/UserCreationModel.cs
index b529a832..4d2594b8 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Users/UserCreationModel.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Users/UserCreationModel.cs
@@ -13,7 +13,6 @@ public class UserCreationModel
public string Type { get; set; } = UserType.Client;
public string Role { get; set; } = UserRole.User;
public string RegionCode { get; set; } = "CN";
- public string? ReferralCode { get; set; }
public User ToUser()
{
return new User
@@ -27,7 +26,6 @@ public class UserCreationModel
Role = Role,
Type = Type,
RegionCode = RegionCode,
- ReferralCode = ReferralCode
};
}
}
diff --git a/src/Plugins/BotSharp.Plugin.HttpHandler/BotSharp.Plugin.HttpHandler.csproj b/src/Plugins/BotSharp.Plugin.HttpHandler/BotSharp.Plugin.HttpHandler.csproj
index 7dc0ac87..61ab8648 100644
--- a/src/Plugins/BotSharp.Plugin.HttpHandler/BotSharp.Plugin.HttpHandler.csproj
+++ b/src/Plugins/BotSharp.Plugin.HttpHandler/BotSharp.Plugin.HttpHandler.csproj
@@ -33,10 +33,6 @@
-
-
-
-
diff --git a/src/Plugins/BotSharp.Plugin.HttpHandler/Functions/HandleHttpRequestFn.cs b/src/Plugins/BotSharp.Plugin.HttpHandler/Functions/HandleHttpRequestFn.cs
index d36aafba..52f5075b 100644
--- a/src/Plugins/BotSharp.Plugin.HttpHandler/Functions/HandleHttpRequestFn.cs
+++ b/src/Plugins/BotSharp.Plugin.HttpHandler/Functions/HandleHttpRequestFn.cs
@@ -1,5 +1,6 @@
using System.Net.Http;
using System.Net.Mime;
+using BotSharp.Abstraction.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
@@ -13,7 +14,6 @@ public class HandleHttpRequestFn : IFunctionCallback
private readonly IServiceProvider _services;
private readonly ILogger _logger;
private readonly IHttpClientFactory _httpClientFactory;
- private readonly IHttpContextAccessor _context;
private readonly BotSharpOptions _options;
public HandleHttpRequestFn(IServiceProvider services,
@@ -25,7 +25,6 @@ public class HandleHttpRequestFn : IFunctionCallback
_services = services;
_logger = logger;
_httpClientFactory = httpClientFactory;
- _context = context;
_options = options;
}
@@ -46,7 +45,7 @@ public class HandleHttpRequestFn : IFunctionCallback
catch (Exception ex)
{
var msg = $"Fail when sending http request. Url: {url}, method: {method}, content: {content}";
- _logger.LogWarning($"{msg}\n(Error: {ex.Message})");
+ _logger.LogError($"{msg}\n(Error: {ex.Message}\r\n{ex.InnerException})");
message.Content = msg;
return false;
}
@@ -57,7 +56,7 @@ public class HandleHttpRequestFn : IFunctionCallback
if (string.IsNullOrEmpty(url)) return null;
using var client = _httpClientFactory.CreateClient();
- AddRequestHeaders(client);
+ PrepareRequestHeaders(client);
var (uri, request) = BuildHttpRequest(url, method, content);
var response = await client.SendAsync(request);
@@ -69,15 +68,12 @@ public class HandleHttpRequestFn : IFunctionCallback
return response;
}
- private void AddRequestHeaders(HttpClient client)
+ private void PrepareRequestHeaders(HttpClient client)
{
- client.DefaultRequestHeaders.Add("Authorization", $"{_context.HttpContext.Request.Headers["Authorization"]}");
-
- var settings = _services.GetRequiredService();
- var origin = !string.IsNullOrEmpty(settings.Origin) ? settings.Origin : $"{_context.HttpContext.Request.Headers["Origin"]}";
- if (!string.IsNullOrEmpty(origin))
+ var hooks = _services.GetServices();
+ foreach (var hook in hooks)
{
- client.DefaultRequestHeaders.Add("Origin", origin);
+ hook.OnAddHttpHeaders(client.DefaultRequestHeaders);
}
}
diff --git a/src/Plugins/BotSharp.Plugin.HttpHandler/Hooks/BasicHttpRequestHook.cs b/src/Plugins/BotSharp.Plugin.HttpHandler/Hooks/BasicHttpRequestHook.cs
new file mode 100644
index 00000000..5de858f2
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.HttpHandler/Hooks/BasicHttpRequestHook.cs
@@ -0,0 +1,40 @@
+using BotSharp.Abstraction.Http;
+using Microsoft.AspNetCore.Http;
+using System.Net.Http.Headers;
+
+namespace BotSharp.Plugin.HttpHandler.Hooks;
+
+public class BasicHttpRequestHook : IHttpRequestHook
+{
+ private readonly IServiceProvider _services;
+ private readonly IHttpContextAccessor _context;
+
+ private const string AUTHORIZATION = "Authorization";
+ private const string ORIGIN = "Origin";
+
+ public BasicHttpRequestHook(
+ IServiceProvider services,
+ IHttpContextAccessor context)
+ {
+ _services = services;
+ _context = context;
+ }
+
+ public void OnAddHttpHeaders(HttpHeaders headers)
+ {
+ var settings = _services.GetRequiredService();
+
+ var auth = $"{_context.HttpContext.Request.Headers[AUTHORIZATION]}";
+ if (!string.IsNullOrEmpty(auth))
+ {
+ headers.Add(AUTHORIZATION, auth);
+ }
+
+ var origin = $"{_context.HttpContext.Request.Headers[ORIGIN]}";
+ origin = !string.IsNullOrEmpty(settings.Origin) ? settings.Origin : origin;
+ if (!string.IsNullOrEmpty(origin))
+ {
+ headers.Add(ORIGIN, origin);
+ }
+ }
+}
diff --git a/src/Plugins/BotSharp.Plugin.HttpHandler/HttpHandlerPlugin.cs b/src/Plugins/BotSharp.Plugin.HttpHandler/HttpHandlerPlugin.cs
index 9c8cab55..a3c85c0b 100644
--- a/src/Plugins/BotSharp.Plugin.HttpHandler/HttpHandlerPlugin.cs
+++ b/src/Plugins/BotSharp.Plugin.HttpHandler/HttpHandlerPlugin.cs
@@ -1,4 +1,5 @@
using BotSharp.Abstraction.Agents;
+using BotSharp.Abstraction.Http;
using BotSharp.Abstraction.Settings;
using Microsoft.Extensions.Configuration;
@@ -21,5 +22,6 @@ public class HttpHandlerPlugin : IBotSharpPlugin
});
services.AddScoped();
+ services.AddScoped();
}
}
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/BotSharp.Plugin.MongoStorage.csproj b/src/Plugins/BotSharp.Plugin.MongoStorage/BotSharp.Plugin.MongoStorage.csproj
index 88709238..5ac884e0 100644
--- a/src/Plugins/BotSharp.Plugin.MongoStorage/BotSharp.Plugin.MongoStorage.csproj
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/BotSharp.Plugin.MongoStorage.csproj
@@ -11,7 +11,7 @@
-
+
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentDocument.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentDocument.cs
index 19945124..54c9eae7 100644
--- a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentDocument.cs
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentDocument.cs
@@ -21,6 +21,7 @@ public class AgentDocument : MongoBase
public List KnowledgeBases { get; set; }
public List Profiles { get; set; }
public List RoutingRules { get; set; }
+ public List Rules { get; set; }
public AgentLlmConfigMongoElement? LlmConfig { get; set; }
public DateTime CreatedTime { get; set; }
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Models/AgentRuleMongoElement.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/AgentRuleMongoElement.cs
new file mode 100644
index 00000000..1b346768
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/AgentRuleMongoElement.cs
@@ -0,0 +1,33 @@
+using BotSharp.Abstraction.Agents.Models;
+
+namespace BotSharp.Plugin.MongoStorage.Models;
+
+public class AgentRuleMongoElement
+{
+ public string Name { get; set; }
+ public bool Disabled { get; set; }
+ public string EventName { get; set; }
+ public string EntityType { get; set; }
+
+ public static AgentRuleMongoElement ToMongoElement(AgentRule rule)
+ {
+ return new AgentRuleMongoElement
+ {
+ Name = rule.Name,
+ Disabled = rule.Disabled,
+ EventName = rule.EventName,
+ EntityType = rule.EntityType
+ };
+ }
+
+ public static AgentRule ToDomainElement(AgentRuleMongoElement rule)
+ {
+ return new AgentRule
+ {
+ Name = rule.Name,
+ Disabled = rule.Disabled,
+ EventName = rule.EventName,
+ EntityType = rule.EntityType
+ };
+ }
+}
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/MongoDbContext.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/MongoDbContext.cs
index 89eb18ad..82e9f0d4 100644
--- a/src/Plugins/BotSharp.Plugin.MongoStorage/MongoDbContext.cs
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/MongoDbContext.cs
@@ -36,7 +36,7 @@ public class MongoDbContext
Key = x.Split("=")[0],
Value = x.Split("=")[1]
}).ToList();
-
+
var source = queries.FirstOrDefault(x => x.Key.IsEqualTo(DB_NAME_INDEX));
if (source != null)
{
@@ -168,4 +168,5 @@ public class MongoDbContext
public IMongoCollection CrontabItems
=> Database.GetCollection($"{_collectionPrefix}_CronTabItems");
+
}
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs
index 7f86d144..af615298 100644
--- a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs
@@ -61,6 +61,9 @@ public partial class MongoRepository
case AgentField.KnowledgeBase:
UpdateAgentKnowledgeBases(agent.Id, agent.KnowledgeBases);
break;
+ case AgentField.Rule:
+ UpdateAgentRules(agent.Id, agent.Rules);
+ break;
case AgentField.MaxMessageCount:
UpdateAgentMaxMessageCount(agent.Id, agent.MaxMessageCount);
break;
@@ -256,6 +259,20 @@ public partial class MongoRepository
_dc.Agents.UpdateOne(filter, update);
}
+ private void UpdateAgentRules(string agentId, List rules)
+ {
+ if (rules == null) return;
+
+ var elements = rules?.Select(x => AgentRuleMongoElement.ToMongoElement(x))?.ToList() ?? [];
+
+ var filter = Builders.Filter.Eq(x => x.Id, agentId);
+ var update = Builders.Update
+ .Set(x => x.Rules, elements)
+ .Set(x => x.UpdatedTime, DateTime.UtcNow);
+
+ _dc.Agents.UpdateOne(filter, update);
+ }
+
private void UpdateAgentLlmConfig(string agentId, AgentLlmConfig? config)
{
var llmConfig = AgentLlmConfigMongoElement.ToMongoElement(config);
@@ -297,12 +314,12 @@ public partial class MongoRepository
.Set(x => x.Samples, agent.Samples)
.Set(x => x.Utilities, agent.Utilities.Select(u => AgentUtilityMongoElement.ToMongoElement(u)).ToList())
.Set(x => x.KnowledgeBases, agent.KnowledgeBases.Select(u => AgentKnowledgeBaseMongoElement.ToMongoElement(u)).ToList())
+ .Set(x => x.Rules, agent.Rules.Select(e => AgentRuleMongoElement.ToMongoElement(e)).ToList())
.Set(x => x.LlmConfig, AgentLlmConfigMongoElement.ToMongoElement(agent.LlmConfig))
.Set(x => x.IsPublic, agent.IsPublic)
.Set(x => x.UpdatedTime, DateTime.UtcNow);
var res = _dc.Agents.UpdateOne(filter, update);
- Console.WriteLine();
}
#endregion
@@ -455,6 +472,7 @@ public partial class MongoRepository
RoutingRules = x.RoutingRules?.Select(r => RoutingRuleMongoElement.ToMongoElement(r))?.ToList() ?? [],
Utilities = x.Utilities?.Select(u => AgentUtilityMongoElement.ToMongoElement(u))?.ToList() ?? [],
KnowledgeBases = x.KnowledgeBases?.Select(k => AgentKnowledgeBaseMongoElement.ToMongoElement(k))?.ToList() ?? [],
+ Rules = x.Rules?.Select(e => AgentRuleMongoElement.ToMongoElement(e))?.ToList() ?? [],
CreatedTime = x.CreatedDateTime,
UpdatedTime = x.UpdatedDateTime
}).ToList();
@@ -546,7 +564,8 @@ public partial class MongoRepository
Responses = agentDoc.Responses?.Select(r => AgentResponseMongoElement.ToDomainElement(r))?.ToList() ?? [],
RoutingRules = agentDoc.RoutingRules?.Select(r => RoutingRuleMongoElement.ToDomainElement(agentDoc.Id, agentDoc.Name, r))?.ToList() ?? [],
Utilities = agentDoc.Utilities?.Select(u => AgentUtilityMongoElement.ToDomainElement(u))?.ToList() ?? [],
- KnowledgeBases = agentDoc.KnowledgeBases?.Select(x => AgentKnowledgeBaseMongoElement.ToDomainElement(x))?.ToList() ?? []
+ KnowledgeBases = agentDoc.KnowledgeBases?.Select(x => AgentKnowledgeBaseMongoElement.ToDomainElement(x))?.ToList() ?? [],
+ Rules = agentDoc.Rules?.Select(e => AgentRuleMongoElement.ToDomainElement(e))?.ToList() ?? []
};
}
}
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.User.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.User.cs
index 3c76e21d..29bd36be 100644
--- a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.User.cs
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.User.cs
@@ -112,6 +112,14 @@ public partial class MongoRepository
_dc.Users.UpdateOne(filter, update);
}
+ public void UpdateUserName(string userId, string userName)
+ {
+ var filter = Builders.Filter.Eq(x => x.Id, userId);
+ var update = Builders.Update
+ .Set(x => x.UserName, userName);
+ _dc.Users.UpdateOne(filter, update);
+ }
+
public void UpdateUserVerified(string userId)
{
var filter = Builders.Filter.Eq(x => x.Id, userId);
@@ -151,7 +159,7 @@ public partial class MongoRepository
var update = Builders.Update.Set(x => x.Phone, phone)
.Set(x => x.UpdatedTime, DateTime.UtcNow)
.Set(x => x.RegionCode, regionCode)
- .Set(x => x.UserName, phone)
+ //.Set(x => x.UserName, phone)
.Set(x => x.FirstName, phone);
_dc.Users.UpdateOne(filter, update);
}
@@ -331,10 +339,10 @@ public partial class MongoRepository
.FirstOrDefault(x => x.Id == userId || (x.ExternalId != null && x.ExternalId == userId));
if (user == null) return;
var curDash = user.Dashboard ?? new Dashboard();
- curDash.ConversationList.Add(new DashboardConversation
- {
+ curDash.ConversationList.Add(new DashboardConversation
+ {
Id = Guid.NewGuid().ToString(),
- ConversationId = conversationId
+ ConversationId = conversationId
});
var filter = Builders.Filter.Eq(x => x.Id, userId);
diff --git a/src/Plugins/BotSharp.Plugin.OpenAI/Providers/ProviderHelper.cs b/src/Plugins/BotSharp.Plugin.OpenAI/Providers/ProviderHelper.cs
index b385b380..d3db3544 100644
--- a/src/Plugins/BotSharp.Plugin.OpenAI/Providers/ProviderHelper.cs
+++ b/src/Plugins/BotSharp.Plugin.OpenAI/Providers/ProviderHelper.cs
@@ -9,8 +9,9 @@ public class ProviderHelper
{
var settingsService = services.GetRequiredService();
var settings = settingsService.GetSetting(provider, model);
- var client = new OpenAIClient(new ApiKeyCredential(settings.ApiKey));
- return client;
+ var options = !string.IsNullOrEmpty(settings.Endpoint) ?
+ new OpenAIClientOptions { Endpoint = new Uri(settings.Endpoint) } : null;
+ return new OpenAIClient(new ApiKeyCredential(settings.ApiKey), options);
}
public static List GetChatSamples(List lines)
diff --git a/src/Plugins/BotSharp.Plugin.Selenium/BotSharp.Plugin.Selenium.csproj b/src/Plugins/BotSharp.Plugin.Selenium/BotSharp.Plugin.Selenium.csproj
new file mode 100644
index 00000000..2a4e3e08
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.Selenium/BotSharp.Plugin.Selenium.csproj
@@ -0,0 +1,22 @@
+
+
+
+ $(TargetFramework)
+ enable
+ $(LangVersion)
+ $(BotSharpVersion)
+ $(GeneratePackageOnBuild)
+ $(GenerateDocumentationFile)
+ $(SolutionDir)packages
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumInstance.cs b/src/Plugins/BotSharp.Plugin.Selenium/Drivers/SeleniumInstance.cs
similarity index 97%
rename from src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumInstance.cs
rename to src/Plugins/BotSharp.Plugin.Selenium/Drivers/SeleniumInstance.cs
index 5e1f5eaf..253ba487 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumInstance.cs
+++ b/src/Plugins/BotSharp.Plugin.Selenium/Drivers/SeleniumInstance.cs
@@ -1,7 +1,7 @@
using OpenQA.Selenium.Chrome;
using System.IO;
-namespace BotSharp.Plugin.WebDriver.Drivers.SeleniumDriver;
+namespace BotSharp.Plugin.Selenium.Drivers;
public class SeleniumInstance : IDisposable
{
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumWebDriver.DoAction.cs b/src/Plugins/BotSharp.Plugin.Selenium/Drivers/SeleniumWebDriver.DoAction.cs
similarity index 93%
rename from src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumWebDriver.DoAction.cs
rename to src/Plugins/BotSharp.Plugin.Selenium/Drivers/SeleniumWebDriver.DoAction.cs
index bb9afd87..931e6736 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumWebDriver.DoAction.cs
+++ b/src/Plugins/BotSharp.Plugin.Selenium/Drivers/SeleniumWebDriver.DoAction.cs
@@ -1,7 +1,6 @@
-using OpenQA.Selenium;
using OpenQA.Selenium.Interactions;
-namespace BotSharp.Plugin.WebDriver.Drivers.SeleniumDriver;
+namespace BotSharp.Plugin.Selenium.Drivers;
public partial class SeleniumWebDriver
{
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumWebDriver.EvaluateScript.cs b/src/Plugins/BotSharp.Plugin.Selenium/Drivers/SeleniumWebDriver.EvaluateScript.cs
similarity index 86%
rename from src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumWebDriver.EvaluateScript.cs
rename to src/Plugins/BotSharp.Plugin.Selenium/Drivers/SeleniumWebDriver.EvaluateScript.cs
index 9a59cb81..3fb6b39a 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumWebDriver.EvaluateScript.cs
+++ b/src/Plugins/BotSharp.Plugin.Selenium/Drivers/SeleniumWebDriver.EvaluateScript.cs
@@ -1,4 +1,4 @@
-namespace BotSharp.Plugin.WebDriver.Drivers.SeleniumDriver;
+namespace BotSharp.Plugin.Selenium.Drivers;
public partial class SeleniumWebDriver
{
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumWebDriver.GetAttributeValue.cs b/src/Plugins/BotSharp.Plugin.Selenium/Drivers/SeleniumWebDriver.GetAttributeValue.cs
similarity index 91%
rename from src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumWebDriver.GetAttributeValue.cs
rename to src/Plugins/BotSharp.Plugin.Selenium/Drivers/SeleniumWebDriver.GetAttributeValue.cs
index 0402b2db..ff99d29d 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumWebDriver.GetAttributeValue.cs
+++ b/src/Plugins/BotSharp.Plugin.Selenium/Drivers/SeleniumWebDriver.GetAttributeValue.cs
@@ -1,4 +1,4 @@
-namespace BotSharp.Plugin.WebDriver.Drivers.SeleniumDriver;
+namespace BotSharp.Plugin.Selenium.Drivers;
public partial class SeleniumWebDriver
{
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumWebDriver.GoToPage.cs b/src/Plugins/BotSharp.Plugin.Selenium/Drivers/SeleniumWebDriver.GoToPage.cs
similarity index 92%
rename from src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumWebDriver.GoToPage.cs
rename to src/Plugins/BotSharp.Plugin.Selenium/Drivers/SeleniumWebDriver.GoToPage.cs
index db7d36a3..15a71480 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumWebDriver.GoToPage.cs
+++ b/src/Plugins/BotSharp.Plugin.Selenium/Drivers/SeleniumWebDriver.GoToPage.cs
@@ -1,4 +1,4 @@
-namespace BotSharp.Plugin.WebDriver.Drivers.SeleniumDriver;
+namespace BotSharp.Plugin.Selenium.Drivers;
public partial class SeleniumWebDriver
{
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumWebDriver.HttpRequest.cs b/src/Plugins/BotSharp.Plugin.Selenium/Drivers/SeleniumWebDriver.HttpRequest.cs
similarity index 95%
rename from src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumWebDriver.HttpRequest.cs
rename to src/Plugins/BotSharp.Plugin.Selenium/Drivers/SeleniumWebDriver.HttpRequest.cs
index c9940318..affeaf62 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumWebDriver.HttpRequest.cs
+++ b/src/Plugins/BotSharp.Plugin.Selenium/Drivers/SeleniumWebDriver.HttpRequest.cs
@@ -1,6 +1,6 @@
using System.Net.Http;
-namespace BotSharp.Plugin.WebDriver.Drivers.SeleniumDriver;
+namespace BotSharp.Plugin.Selenium.Drivers;
public partial class SeleniumWebDriver
{
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumWebDriver.LaunchBrowser.cs b/src/Plugins/BotSharp.Plugin.Selenium/Drivers/SeleniumWebDriver.LaunchBrowser.cs
similarity index 85%
rename from src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumWebDriver.LaunchBrowser.cs
rename to src/Plugins/BotSharp.Plugin.Selenium/Drivers/SeleniumWebDriver.LaunchBrowser.cs
index 4e8b6498..9c104a59 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumWebDriver.LaunchBrowser.cs
+++ b/src/Plugins/BotSharp.Plugin.Selenium/Drivers/SeleniumWebDriver.LaunchBrowser.cs
@@ -1,4 +1,4 @@
-namespace BotSharp.Plugin.WebDriver.Drivers.SeleniumDriver;
+namespace BotSharp.Plugin.Selenium.Drivers;
public partial class SeleniumWebDriver
{
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumWebDriver.LocateElement.cs b/src/Plugins/BotSharp.Plugin.Selenium/Drivers/SeleniumWebDriver.LocateElement.cs
similarity index 97%
rename from src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumWebDriver.LocateElement.cs
rename to src/Plugins/BotSharp.Plugin.Selenium/Drivers/SeleniumWebDriver.LocateElement.cs
index 4d96b9a6..184106a5 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumWebDriver.LocateElement.cs
+++ b/src/Plugins/BotSharp.Plugin.Selenium/Drivers/SeleniumWebDriver.LocateElement.cs
@@ -1,7 +1,6 @@
-using OpenQA.Selenium;
using System.Collections.ObjectModel;
-namespace BotSharp.Plugin.WebDriver.Drivers.SeleniumDriver;
+namespace BotSharp.Plugin.Selenium.Drivers;
public partial class SeleniumWebDriver
{
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumWebDriver.cs b/src/Plugins/BotSharp.Plugin.Selenium/Drivers/SeleniumWebDriver.cs
similarity index 93%
rename from src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumWebDriver.cs
rename to src/Plugins/BotSharp.Plugin.Selenium/Drivers/SeleniumWebDriver.cs
index 15dd0bc1..0e6dd0a3 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumWebDriver.cs
+++ b/src/Plugins/BotSharp.Plugin.Selenium/Drivers/SeleniumWebDriver.cs
@@ -1,4 +1,4 @@
-namespace BotSharp.Plugin.WebDriver.Drivers.SeleniumDriver;
+namespace BotSharp.Plugin.Selenium.Drivers;
public partial class SeleniumWebDriver : IWebBrowser
{
@@ -86,4 +86,9 @@ public partial class SeleniumWebDriver : IWebBrowser
{
throw new NotImplementedException();
}
+
+ public Task PressKey(MessageInfo message, string key)
+ {
+ throw new NotImplementedException();
+ }
}
diff --git a/src/Plugins/BotSharp.Plugin.Selenium/Using.cs b/src/Plugins/BotSharp.Plugin.Selenium/Using.cs
new file mode 100644
index 00000000..abadf8fa
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.Selenium/Using.cs
@@ -0,0 +1,23 @@
+global using System;
+global using System.Collections.Generic;
+global using System.Text;
+global using System.Threading.Tasks;
+global using System.Text.Json;
+global using System.Linq;
+global using System.Text.RegularExpressions;
+global using Microsoft.Extensions.Configuration;
+global using Microsoft.Extensions.DependencyInjection;
+global using Microsoft.Extensions.Logging;
+global using BotSharp.Abstraction.Browsing.Enums;
+global using BotSharp.Abstraction.Conversations;
+global using BotSharp.Abstraction.Plugins;
+global using BotSharp.Abstraction.Conversations.Models;
+global using BotSharp.Abstraction.Functions;
+global using BotSharp.Abstraction.Agents.Models;
+global using BotSharp.Abstraction.Templating;
+global using BotSharp.Abstraction.Agents;
+global using BotSharp.Abstraction.Utilities;
+global using BotSharp.Abstraction.Browsing.Models;
+global using BotSharp.Abstraction.Browsing;
+
+global using OpenQA.Selenium;
\ No newline at end of file
diff --git a/src/Plugins/BotSharp.Plugin.SqlDriver/Hooks/SqlDriverPlanningHook.cs b/src/Plugins/BotSharp.Plugin.SqlDriver/Hooks/SqlDriverPlanningHook.cs
index bb008319..231d793a 100644
--- a/src/Plugins/BotSharp.Plugin.SqlDriver/Hooks/SqlDriverPlanningHook.cs
+++ b/src/Plugins/BotSharp.Plugin.SqlDriver/Hooks/SqlDriverPlanningHook.cs
@@ -1,13 +1,9 @@
-using BotSharp.Abstraction.Agents.Enums;
using BotSharp.Abstraction.Messaging.Enums;
using BotSharp.Abstraction.Messaging.Models.RichContent.Template;
using BotSharp.Abstraction.Messaging.Models.RichContent;
using BotSharp.Abstraction.Messaging;
using BotSharp.Abstraction.Planning;
-using BotSharp.Abstraction.Routing;
using BotSharp.Core.Infrastructures;
-using System.Text.RegularExpressions;
-using BotSharp.Plugin.SqlDriver.Interfaces;
namespace BotSharp.Plugin.SqlDriver.Hooks;
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/BotSharp.Plugin.WebDriver.csproj b/src/Plugins/BotSharp.Plugin.WebDriver/BotSharp.Plugin.WebDriver.csproj
index 296e17c3..15c2868c 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/BotSharp.Plugin.WebDriver.csproj
+++ b/src/Plugins/BotSharp.Plugin.WebDriver/BotSharp.Plugin.WebDriver.csproj
@@ -3,7 +3,7 @@
$(TargetFramework)
enable
- 12.0
+ $(LangVersion)
$(BotSharpVersion)
$(GeneratePackageOnBuild)
$(GenerateDocumentationFile)
@@ -11,16 +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 b5155cd5..95b88eee 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightInstance.cs
+++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightInstance.cs
@@ -45,28 +45,36 @@ public class PlaywrightInstance : IDisposable
_playwright = await Playwright.CreateAsync();
}
- string tempFolderPath = $"{Path.GetTempPath()}\\playwright\\{ctxId}";
-
- _contexts[ctxId] = await _playwright.Chromium.LaunchPersistentContextAsync(tempFolderPath, new BrowserTypeLaunchPersistentContextOptions
+ if (!string.IsNullOrEmpty(args.RemoteHostUrl))
{
- Headless = args.Headless,
- Channel = "chrome",
- ViewportSize = new ViewportSize
+ var browser = await _playwright.Chromium.ConnectOverCDPAsync(args.RemoteHostUrl);
+ _contexts[ctxId] = browser.Contexts[0];
+ }
+ else
+ {
+ string userDataDir = args.UserDataDir ?? $"{Path.GetTempPath()}\\playwright\\{ctxId}";
+ _contexts[ctxId] = await _playwright.Chromium.LaunchPersistentContextAsync(userDataDir, new BrowserTypeLaunchPersistentContextOptions
{
- Width = 1600,
- Height = 900
- },
- IgnoreDefaultArgs =
- [
- "--enable-automation",
- ],
- Args =
- [
- "--disable-infobars",
- "--test-type"
- // "--start-maximized"
- ]
- });
+ Headless = args.Headless,
+ Channel = "chrome",
+ ViewportSize = new ViewportSize
+ {
+ Width = 1600,
+ Height = 900
+ },
+ IgnoreDefaultArgs =
+ [
+ "--enable-automation",
+ ],
+ Args =
+ [
+ "--disable-infobars",
+ "--test-type"
+ // "--start-maximized"
+ ]
+ });
+ }
+
_pages[ctxId] = new List();
_contexts[ctxId].Page += async (sender, page) =>
@@ -100,12 +108,7 @@ public class PlaywrightInstance : IDisposable
return _contexts[ctxId];
}
- public async Task NewPage(MessageInfo message,
- bool enableResponseCallback = false,
- bool responseInMemory = false,
- List? responseContainer = null,
- string[]? excludeResponseUrls = null,
- string[]? includeResponseUrls = null)
+ public async Task NewPage(MessageInfo message, PageActionArgs args)
{
var context = await GetContext(message.ContextId);
var page = await context.NewPageAsync();
@@ -115,70 +118,78 @@ public class PlaywrightInstance : IDisposable
var js = @"Object.defineProperties(navigator, {webdriver:{get:()=>false}});";
await page.AddInitScriptAsync(js);
- if (!enableResponseCallback)
+ if (!args.EnableResponseCallback)
{
return page;
}
page.Response += async (sender, e) =>
{
- if (e.Status != 204 &&
- e.Headers.ContainsKey("content-type") &&
- (e.Request.ResourceType == "fetch" || e.Request.ResourceType == "xhr") &&
- (excludeResponseUrls == null || !excludeResponseUrls.Any(url => e.Url.ToLower().Contains(url))) &&
- (includeResponseUrls == null || includeResponseUrls.Any(url => e.Url.ToLower().Contains(url))))
- {
- Serilog.Log.Information($"{e.Request.Method}: {e.Url}");
-
- try
- {
- var result = new WebPageResponseData
- {
- Url = e.Url.ToLower(),
- PostData = e.Request?.PostData ?? string.Empty,
- ResponseInMemory = responseInMemory
- };
-
- if (e.Headers["content-type"].Contains("application/json"))
- {
- if (e.Status == 200 && e.Ok)
- {
- var json = await e.JsonAsync();
- result.ResponseData = JsonSerializer.Serialize(json);
- }
- }
- else
- {
- var html = await e.TextAsync();
- result.ResponseData = html;
- }
-
- if (responseContainer != null && responseInMemory)
- {
- responseContainer.Add(result);
- }
-
- Serilog.Log.Warning($"Response status: {e.Status} {e.StatusText}, OK: {e.Ok}");
- var webPageResponseHooks = _services.GetServices();
- foreach (var hook in webPageResponseHooks)
- {
- hook.OnDataFetched(message, result);
- }
- }
- catch (ObjectDisposedException ex)
- {
- Serilog.Log.Information(ex.Message);
- }
- catch (Exception ex)
- {
- Serilog.Log.Error($"{e.Url}\r\n" + ex.ToString());
- }
- }
+ await HandleFetchResponse(e, message, args);
};
return page;
}
+ public async Task HandleFetchResponse(IResponse response, MessageInfo message, PageActionArgs args)
+ {
+ if (response.Status != 204 &&
+ response.Headers.ContainsKey("content-type") &&
+ (response.Request.ResourceType == "fetch" || response.Request.ResourceType == "xhr") &&
+ (args.ExcludeResponseUrls == null || !args.ExcludeResponseUrls.Any(url => response.Url.ToLower().Contains(url))) &&
+ (args.IncludeResponseUrls == null || args.IncludeResponseUrls.Any(url => response.Url.ToLower().Contains(url))))
+ {
+ Serilog.Log.Information($"{response.Request.Method}: {response.Url}");
+
+ try
+ {
+ var result = new WebPageResponseData
+ {
+ Url = response.Url.ToLower(),
+ PostData = response.Request?.PostData ?? string.Empty,
+ ResponseInMemory = args.ResponseInMemory
+ };
+
+ var html = await response.TextAsync();
+ if (response.Headers["content-type"].Contains("application/json"))
+ {
+ if (response.Status == 200 && response.Ok)
+ {
+ if (!string.IsNullOrWhiteSpace(html))
+ {
+ var json = await response.JsonAsync();
+ result.ResponseData = JsonSerializer.Serialize(json);
+ }
+ }
+ }
+ else
+ {
+ result.ResponseData = html;
+ }
+
+ if (args.ResponseContainer != null && args.ResponseInMemory)
+ {
+ args.ResponseContainer.Add(result);
+ }
+
+ Serilog.Log.Warning($"Response status: {response.Status} {response.StatusText}, OK: {response.Ok}");
+ var webPageResponseHooks = _services.GetServices();
+ foreach (var hook in webPageResponseHooks)
+ {
+ hook.OnDataFetched(message, result);
+ }
+ }
+ catch (ObjectDisposedException ex)
+ {
+ Serilog.Log.Information(ex.Message);
+ }
+ catch (Exception ex)
+ {
+ Serilog.Log.Error($"{response.Url}\r\n" + ex.ToString());
+ }
+ }
+ }
+
///
/// Wait page and network until timeout in seconds
///
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.ActionOnElement.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.ActionOnElement.cs
index ab1a0731..7a5f4820 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.ActionOnElement.cs
+++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.ActionOnElement.cs
@@ -9,6 +9,7 @@ public partial class PlaywrightWebDriver
if (result.IsSuccess)
{
await DoAction(message, action, result);
+ result.UrlAfterAction = _instance.GetPage(message.ContextId)?.Url;
}
return result;
}
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 40fec84e..b851cd1a 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.DoAction.cs
+++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.DoAction.cs
@@ -113,6 +113,7 @@ public partial class PlaywrightWebDriver
}
// Release mouse button
+ await Task.Delay(1000);
await mouse.UpAsync();
}
else
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.GetAttributeValue.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.GetAttributeValue.cs
index 035bcf3b..ef266d08 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.GetAttributeValue.cs
+++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.GetAttributeValue.cs
@@ -19,4 +19,25 @@ public partial class PlaywrightWebDriver
Body = value ?? string.Empty
};
}
+
+ public async Task SetAttributeValue(MessageInfo message, ElementLocatingArgs location)
+ {
+ var page = _instance.GetPage(message.ContextId);
+ ILocator locator = page.Locator(location.Selector);
+ var elementCount = await locator.CountAsync();
+
+ if (elementCount > 0)
+ {
+ foreach (var element in await locator.AllAsync())
+ {
+ var script = $"element => element.{location.AttributeName} = '{location.AttributeValue}'";
+ var result = await locator.EvaluateAsync(script);
+ }
+ }
+
+ return new BrowserActionResult
+ {
+ IsSuccess = true
+ };
+ }
}
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.GoToPage.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.GoToPage.cs
index 2f339ca6..7f0501cf 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.GoToPage.cs
+++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.GoToPage.cs
@@ -8,32 +8,41 @@ public partial class PlaywrightWebDriver
var context = await _instance.GetContext(message.ContextId);
try
{
- var page = await _instance.NewPage(message, enableResponseCallback: args.EnableResponseCallback,
- responseInMemory: args.ResponseInMemory,
- responseContainer: args.ResponseContainer,
- excludeResponseUrls: args.ExcludeResponseUrls,
- includeResponseUrls: args.IncludeResponseUrls);
-
- Serilog.Log.Information($"goto page: {args.Url}");
-
- if (args.OpenNewTab && page != null && page.Url == "about:blank")
+ IPage? page = null;
+ if (!args.OpenNewTab)
{
- page = await _instance.NewPage(message,
- enableResponseCallback: args.EnableResponseCallback,
- responseInMemory: args.ResponseInMemory,
- responseContainer: args.ResponseContainer,
- excludeResponseUrls: args.ExcludeResponseUrls,
- includeResponseUrls: args.IncludeResponseUrls);
+ page = _instance.Contexts[message.ContextId].Pages.LastOrDefault();
+
+ if (page != null)
+ {
+ await page.EvaluateAsync(@"() => {
+ window.open('', '_blank');
+ }");
+
+ if (args.EnableResponseCallback)
+ {
+ page.Response += async (sender, e) =>
+ {
+ await _instance.HandleFetchResponse(e, message, args);
+ };
+ }
+ }
+ }
+ else
+ {
+ page = await _instance.NewPage(message, args);
+
+ Serilog.Log.Information($"goto page: {args.Url}");
+
+ if (args.OpenNewTab && page != null && page.Url == "about:blank")
+ {
+ page = await _instance.NewPage(message, args);
+ }
}
if (page == null)
{
- page = await _instance.NewPage(message,
- enableResponseCallback: args.EnableResponseCallback,
- responseInMemory: args.ResponseInMemory,
- responseContainer: args.ResponseContainer,
- excludeResponseUrls: args.ExcludeResponseUrls,
- includeResponseUrls: args.IncludeResponseUrls);
+ page = await _instance.NewPage(message, args);
}
// Active current tab
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.LocateElement.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.LocateElement.cs
index 8695fc5c..613d2b22 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.LocateElement.cs
+++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.LocateElement.cs
@@ -14,6 +14,13 @@ public partial class PlaywrightWebDriver
{
var result = new BrowserActionResult();
var page = _instance.GetPage(message.ContextId);
+ if (page == null)
+ {
+ return new BrowserActionResult
+ {
+ IsSuccess = false
+ };
+ }
ILocator locator = page.Locator("body");
int count = 0;
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Functions/OpenBrowserFn.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Functions/OpenBrowserFn.cs
index 6f4c3654..6a5a1ac1 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/Functions/OpenBrowserFn.cs
+++ b/src/Plugins/BotSharp.Plugin.WebDriver/Functions/OpenBrowserFn.cs
@@ -1,5 +1,3 @@
-using SQLitePCL;
-
namespace BotSharp.Plugin.WebDriver.Functions;
public class OpenBrowserFn : IFunctionCallback
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/WebPageHelper.cs b/src/Plugins/BotSharp.Plugin.WebDriver/WebPageHelper.cs
index 113403eb..aaf61aa4 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/WebPageHelper.cs
+++ b/src/Plugins/BotSharp.Plugin.WebDriver/WebPageHelper.cs
@@ -1,10 +1,25 @@
using HtmlAgilityPack;
-using System.Net.Http;
namespace BotSharp.Plugin.WebDriver;
public static class WebPageHelper
{
+ public static HtmlNode GetElement(string html, string selector)
+ {
+ var htmlDoc = new HtmlDocument();
+ htmlDoc.LoadHtml(html);
+
+ return htmlDoc.DocumentNode.SelectSingleNode(selector);
+ }
+
+ public static HtmlNodeCollection GetElements(string html, string selector)
+ {
+ var htmlDoc = new HtmlDocument();
+ htmlDoc.LoadHtml(html);
+
+ return htmlDoc.DocumentNode.SelectNodes(selector);
+ }
+
public static string RemoveElements(string html, string selector)
{
var htmlDoc = new HtmlDocument();