Merge branch 'master' of https://github.com/SciSharp/BotSharp into features/init-reactive-x
This commit is contained in:
commit
35652a7b71
|
|
@ -4,5 +4,6 @@ namespace BotSharp.Abstraction.Browsing;
|
|||
|
||||
public interface IWebDriverHook
|
||||
{
|
||||
Task<List<string>> GetUploadFiles(MessageInfo message);
|
||||
Task<List<string>> GetUploadFiles(MessageInfo message) => Task.FromResult(new List<string>());
|
||||
Task OnLocateElement(MessageInfo message, string content) => Task.CompletedTask;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,20 +8,24 @@ public class MessageState
|
|||
[JsonPropertyName("active_rounds")]
|
||||
public int ActiveRounds { get; set; } = -1;
|
||||
|
||||
[JsonPropertyName("global")]
|
||||
public bool Global { get; set; }
|
||||
|
||||
public MessageState()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public MessageState(string key, object value, int activeRounds = -1)
|
||||
public MessageState(string key, object value, int activeRounds = -1, bool isGlobal = false)
|
||||
{
|
||||
Key = key;
|
||||
Value = value;
|
||||
ActiveRounds = activeRounds;
|
||||
Global = isGlobal;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Key: {Key} => Value: {Value}, ActiveRounds: {ActiveRounds}";
|
||||
return $"Key: {Key} => Value: {Value}, ActiveRounds: {ActiveRounds}, Global: {Global}";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ public class ConversationFilter
|
|||
public string? Title { get; set; }
|
||||
public string? TitleAlias { get; set; }
|
||||
public string? AgentId { get; set; }
|
||||
public List<string>? AgentIds { get; set; }
|
||||
public string? Status { get; set; }
|
||||
public string? Channel { get; set; }
|
||||
public string? ChannelId { get; set; }
|
||||
|
|
|
|||
|
|
@ -7,6 +7,15 @@ public class SideCarOptions
|
|||
|
||||
public static SideCarOptions Empty()
|
||||
{
|
||||
return new SideCarOptions();
|
||||
return new();
|
||||
}
|
||||
|
||||
public static SideCarOptions InheritStates(IEnumerable<string>? targetStates = null)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
IsInheritStates = true,
|
||||
InheritStateKeys = targetStates
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ public partial class ConversationService : IConversationService
|
|||
{
|
||||
_conversationId = conversationId;
|
||||
_state.Load(_conversationId, isReadOnly);
|
||||
states.ForEach(x => _state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External));
|
||||
states.ForEach(x => _state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, isNeedVersion: !x.Global, source: StateSource.External));
|
||||
}
|
||||
|
||||
public async Task<Conversation> GetConversationRecordOrCreateNew(string agentId)
|
||||
|
|
|
|||
|
|
@ -475,7 +475,7 @@ namespace BotSharp.Core.Repository
|
|||
|
||||
if (!filter.AgentNames.IsNullOrEmpty())
|
||||
{
|
||||
query = query.Where(x => filter.AgentNames.Contains(x.Name));
|
||||
query = query.Where(x => filter.AgentNames.Contains(x.Name, StringComparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(filter.SimilarName))
|
||||
|
|
|
|||
|
|
@ -396,6 +396,12 @@ public partial class FileRepository
|
|||
Directory.CreateDirectory(dir);
|
||||
}
|
||||
|
||||
if (filter?.AgentId != null)
|
||||
{
|
||||
filter.AgentIds ??= [];
|
||||
filter.AgentIds.Add(filter.AgentId);
|
||||
}
|
||||
|
||||
var totalDirs = Directory.GetDirectories(dir);
|
||||
foreach (var d in totalDirs)
|
||||
{
|
||||
|
|
@ -419,9 +425,9 @@ public partial class FileRepository
|
|||
{
|
||||
matched = matched && record.TitleAlias.Contains(filter.TitleAlias);
|
||||
}
|
||||
if (filter?.AgentId != null)
|
||||
if (filter?.AgentIds != null && filter.AgentIds.Any())
|
||||
{
|
||||
matched = matched && record.AgentId == filter.AgentId;
|
||||
matched = matched && filter.AgentIds.Contains(record.AgentId);
|
||||
}
|
||||
if (filter?.Status != null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,10 +4,12 @@ using BotSharp.Abstraction.Templating;
|
|||
using BotSharp.Abstraction.Translation.Models;
|
||||
using Fluid;
|
||||
using Fluid.Ast;
|
||||
using Fluid.Values;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace BotSharp.Core.Templating;
|
||||
|
||||
|
|
@ -36,9 +38,11 @@ public class TemplateRender : ITemplateRender
|
|||
_options.MemberAccessStrategy.Register<UserIdentity>();
|
||||
_options.MemberAccessStrategy.Register<TranslationInput>();
|
||||
|
||||
_parser.RegisterIdentifierTag("link", (string identifier, TextWriter writer, TextEncoder encoder, TemplateContext context) =>
|
||||
_options.Filters.AddFilter("from_agent", FromAgentFilter);
|
||||
|
||||
_parser.RegisterExpressionTag("link", (Expression expression, TextWriter writer, TextEncoder encoder, TemplateContext context) =>
|
||||
{
|
||||
return RenderIdentifierTag("link", identifier, writer, encoder, context);
|
||||
return RenderTag("link", expression, writer, encoder, context, services);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -82,20 +86,46 @@ public class TemplateRender : ITemplateRender
|
|||
|
||||
|
||||
#region Private methods
|
||||
private static async ValueTask<Completion> RenderIdentifierTag(string tag, string identifier, TextWriter writer, TextEncoder encoder, TemplateContext context)
|
||||
private static async ValueTask<Completion> RenderTag(
|
||||
string tag,
|
||||
Expression expression,
|
||||
TextWriter writer,
|
||||
TextEncoder encoder,
|
||||
TemplateContext context,
|
||||
IServiceProvider services)
|
||||
{
|
||||
try
|
||||
{
|
||||
var value = await context.Model.GetValueAsync(TemplateRenderConstant.RENDER_AGENT, context);
|
||||
var agent = value?.ToObjectValue() as Agent;
|
||||
var found = agent?.Templates?.FirstOrDefault(x => x.Name.IsEqualTo(identifier));
|
||||
var key = $"{agent?.Id} | {tag} | {identifier}";
|
||||
var value = await expression.EvaluateAsync(context);
|
||||
var expStr = value?.ToStringValue() ?? string.Empty;
|
||||
|
||||
if (found == null || (context.AmbientValues.TryGetValue(key, out var visited) && (bool)visited))
|
||||
value = await context.Model.GetValueAsync(TemplateRenderConstant.RENDER_AGENT, context);
|
||||
var agent = value?.ToObjectValue() as Agent;
|
||||
|
||||
var splited = Regex.Split(expStr, @"\s*from_agent\s*", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)
|
||||
.Where(x => !string.IsNullOrWhiteSpace(x))
|
||||
.Select(x => x.Trim())
|
||||
.ToArray();
|
||||
|
||||
var templateName = splited.ElementAtOrDefault(0);
|
||||
var agentName = splited.ElementAtOrDefault(1);
|
||||
|
||||
if (splited.Length > 1 && !agentName.IsEqualTo(agent?.Name))
|
||||
{
|
||||
using var scope = services.CreateScope();
|
||||
var agentService = scope.ServiceProvider.GetRequiredService<IAgentService>();
|
||||
var result = await agentService.GetAgents(new() { SimilarName = agentName });
|
||||
agent = result?.Items?.FirstOrDefault();
|
||||
}
|
||||
|
||||
var template = agent?.Templates?.FirstOrDefault(x => x.Name.IsEqualTo(templateName));
|
||||
var key = $"{tag} | {agent?.Id} | {templateName}";
|
||||
|
||||
if (template == null || (context.AmbientValues.TryGetValue(key, out var visited) && (bool)visited))
|
||||
{
|
||||
writer.Write(string.Empty);
|
||||
}
|
||||
else if (_parser.TryParse(found.Content, out var t, out _))
|
||||
else if (_parser.TryParse(template.Content, out var t, out _))
|
||||
{
|
||||
context.AmbientValues[key] = true;
|
||||
var rendered = t.Render(context);
|
||||
|
|
@ -115,6 +145,16 @@ public class TemplateRender : ITemplateRender
|
|||
return Completion.Normal;
|
||||
}
|
||||
|
||||
private static ValueTask<FluidValue> FromAgentFilter(
|
||||
FluidValue input,
|
||||
FilterArguments arguments,
|
||||
TemplateContext context)
|
||||
{
|
||||
var inputStr = input?.ToStringValue() ?? string.Empty;
|
||||
var fromAgent = arguments.At(0).ToStringValue();
|
||||
return new StringValue($"{inputStr} from_agent {fromAgent}");
|
||||
}
|
||||
|
||||
private static bool IsStringType(Type type)
|
||||
{
|
||||
return type == typeof(string);
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@ Follow these steps to handle user request:
|
|||
2. Determine which agent is suitable to handle this conversation. Try to minimize the routing of human service.
|
||||
3. Extract and populate agent required arguments, think carefully, leave it as blank object if user didn't provide the specific arguments.
|
||||
4. You must include all required args for the selected agent, but you must not make up any parameters when there is no exact value provided, those parameters must set value as null if not declared.
|
||||
5. If user is greeting, you can call function response_to_user with a greeting message.
|
||||
5. Call function route_to_agent if user have specific requests and available agent to proceed. Do not ask user to provide any required args by yourself. The requested agent will handle and fill the required args internally.
|
||||
6. If user is greeting or do not have specific request, then you can call function response_to_user with a greeting message.
|
||||
|
||||
{% if routing_requirements and routing_requirements != empty %}
|
||||
[REQUIREMENTS]
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
using BotSharp.Abstraction.Agents.Enums;
|
||||
using BotSharp.Abstraction.Conversations.Enums;
|
||||
using BotSharp.Abstraction.Repositories.Filters;
|
||||
using BotSharp.Abstraction.Statistics.Enums;
|
||||
using BotSharp.Abstraction.Statistics.Models;
|
||||
using BotSharp.Abstraction.Statistics.Services;
|
||||
using BotSharp.Abstraction.Users;
|
||||
|
||||
namespace BotSharp.Logger.Hooks;
|
||||
|
|
|
|||
|
|
@ -30,7 +30,8 @@ public class InstructModeController : ControllerBase
|
|||
.SetState("model_id", input.ModelId, source: StateSource.External)
|
||||
.SetState("instruction", input.Instruction, source: StateSource.External)
|
||||
.SetState("input_text", input.Text, source: StateSource.External)
|
||||
.SetState("template_name", input.Template, source: StateSource.External);
|
||||
.SetState("template_name", input.Template, source: StateSource.External)
|
||||
.SetState("channel", input.Channel, source: StateSource.External);
|
||||
|
||||
var instructor = _services.GetRequiredService<IInstructService>();
|
||||
var result = await instructor.Execute(agentId,
|
||||
|
|
|
|||
|
|
@ -82,8 +82,8 @@ public class ChatStreamMiddleware
|
|||
var (eventType, data) = MapEvents(conn, receivedText);
|
||||
if (eventType == "start")
|
||||
{
|
||||
var states = InitStates(data);
|
||||
await ConnectToModel(hub, webSocket, states);
|
||||
var request = InitRequest(data);
|
||||
await ConnectToModel(hub, webSocket, request?.States);
|
||||
}
|
||||
else if (eventType == "media")
|
||||
{
|
||||
|
|
@ -157,16 +157,15 @@ public class ChatStreamMiddleware
|
|||
});
|
||||
}
|
||||
|
||||
private List<MessageState> InitStates(string data)
|
||||
private ChatStreamRequest? InitRequest(string data)
|
||||
{
|
||||
try
|
||||
{
|
||||
var states = JsonSerializer.Deserialize<List<MessageState>>(data, BotSharpOptions.defaultJsonOptions);
|
||||
return states ?? [];
|
||||
return JsonSerializer.Deserialize<ChatStreamRequest>(data, BotSharpOptions.defaultJsonOptions);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return [];
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
using BotSharp.Abstraction.Models;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace BotSharp.Plugin.ChatHub.Models.Stream;
|
||||
|
||||
public class ChatStreamRequest
|
||||
{
|
||||
[JsonPropertyName("states")]
|
||||
public List<MessageState> States { get; set; } = [];
|
||||
}
|
||||
|
|
@ -346,6 +346,12 @@ public partial class MongoRepository
|
|||
var convBuilder = Builders<ConversationDocument>.Filter;
|
||||
var convFilters = new List<FilterDefinition<ConversationDocument>>() { convBuilder.Empty };
|
||||
|
||||
if (filter?.AgentId != null)
|
||||
{
|
||||
filter.AgentIds ??= [];
|
||||
filter.AgentIds.Add(filter.AgentId);
|
||||
}
|
||||
|
||||
// Filter conversations
|
||||
if (!string.IsNullOrEmpty(filter?.Id))
|
||||
{
|
||||
|
|
@ -359,9 +365,9 @@ public partial class MongoRepository
|
|||
{
|
||||
convFilters.Add(convBuilder.Regex(x => x.Title, new BsonRegularExpression(filter.TitleAlias, "i")));
|
||||
}
|
||||
if (!string.IsNullOrEmpty(filter?.AgentId))
|
||||
if (filter?.AgentIds != null && filter.AgentIds.Any())
|
||||
{
|
||||
convFilters.Add(convBuilder.Eq(x => x.AgentId, filter.AgentId));
|
||||
convFilters.Add(convBuilder.In(x => x.AgentId, filter.AgentIds));
|
||||
}
|
||||
if (!string.IsNullOrEmpty(filter?.Status))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ public class ExecuteQueryFn : IFunctionCallback
|
|||
var results = dbType.ToLower() switch
|
||||
{
|
||||
"mysql" => RunQueryInMySql(args.SqlStatements),
|
||||
"sqlserver" => RunQueryInSqlServer(args.SqlStatements),
|
||||
"sqlserver" or "mssql" => RunQueryInSqlServer(args.SqlStatements),
|
||||
"redshift" => RunQueryInRedshift(args.SqlStatements),
|
||||
_ => throw new NotImplementedException($"Database type {dbType} is not supported.")
|
||||
};
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ public class GetTableDefinitionFn : IFunctionCallback
|
|||
var tableDdls = dbType switch
|
||||
{
|
||||
"mysql" => GetDdlFromMySql(tables),
|
||||
"sqlserver" => GetDdlFromSqlServer(tables),
|
||||
"sqlserver" or "mssql" => GetDdlFromSqlServer(tables),
|
||||
"redshift" => GetDdlFromRedshift(tables),
|
||||
_ => throw new NotImplementedException($"Database type {dbType} is not supported.")
|
||||
};
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ public class SqlSelect : IFunctionCallback
|
|||
var result = dbType switch
|
||||
{
|
||||
"mysql" => RunQueryInMySql(args),
|
||||
"sqlserver" => RunQueryInSqlServer(args),
|
||||
"sqlserver" or "mssql" => RunQueryInSqlServer(args),
|
||||
"redshift" => RunQueryInRedshift(args),
|
||||
_ => throw new NotImplementedException($"Database type {dbType} is not supported.")
|
||||
};
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ public class SqlValidateFn : IFunctionCallback
|
|||
var validateSql = dbType.ToLower() switch
|
||||
{
|
||||
"mysql" => $"EXPLAIN\r\n{sql.Replace("SET ", "-- SET ", StringComparison.InvariantCultureIgnoreCase).Replace(";", "; EXPLAIN ").TrimEnd("EXPLAIN ".ToCharArray())}",
|
||||
"sqlserver" => $"SET PARSEONLY ON;\r\n{sql}\r\nSET PARSEONLY OFF;",
|
||||
"sqlserver" or "mssql" => $"SET PARSEONLY ON;\r\n{sql}\r\nSET PARSEONLY OFF;",
|
||||
"redshift" => $"explain\r\n{sql}",
|
||||
_ => throw new NotImplementedException($"Database type {dbType} is not supported.")
|
||||
};
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ public class GetTableDefinitionFn : IFunctionCallback
|
|||
var tableDdls = dbType switch
|
||||
{
|
||||
"mysql" => GetDdlFromMySql(tables),
|
||||
"sqlserver" => GetDdlFromSqlServer(tables),
|
||||
"sqlserver" or "mssql" => GetDdlFromSqlServer(tables),
|
||||
"redshift" => GetDdlFromRedshift(tables,schema),
|
||||
_ => throw new NotImplementedException($"Database type {dbType} is not supported.")
|
||||
};
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ public class SqlSelect : IFunctionCallback
|
|||
var result = dbType switch
|
||||
{
|
||||
"mysql" => RunQueryInMySql(args),
|
||||
"sqlserver" => RunQueryInSqlServer(args),
|
||||
"sqlserver" or "mssql" => RunQueryInSqlServer(args),
|
||||
"redshift" => RunQueryInRedshift(args),
|
||||
_ => throw new NotImplementedException($"Database type {dbType} is not supported.")
|
||||
};
|
||||
|
|
|
|||
|
|
@ -166,16 +166,16 @@ public class TwilioInboundController : TwilioController
|
|||
|
||||
var states = new List<MessageState>
|
||||
{
|
||||
new("channel", ConversationChannel.Phone),
|
||||
new("calling_phone", request.From),
|
||||
new("phone_direction", request.Direction),
|
||||
new("twilio_call_sid", request.CallSid),
|
||||
new("channel", ConversationChannel.Phone, isGlobal: true),
|
||||
new("calling_phone", request.From, isGlobal: true),
|
||||
new("phone_direction", request.Direction, isGlobal: true),
|
||||
new("twilio_call_sid", request.CallSid, isGlobal: true),
|
||||
};
|
||||
|
||||
if (request.Direction == "inbound")
|
||||
{
|
||||
states.Add(new MessageState("calling_phone_from", request.From));
|
||||
states.Add(new MessageState("calling_phone_to", request.To));
|
||||
states.Add(new MessageState("calling_phone_from", request.From, isGlobal: true));
|
||||
states.Add(new MessageState("calling_phone_to", request.To, isGlobal: true));
|
||||
}
|
||||
|
||||
var requestStates = ParseStates(request.States);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ using BotSharp.Plugin.Twilio.Interfaces;
|
|||
using BotSharp.Plugin.Twilio.Models;
|
||||
using BotSharp.Plugin.Twilio.OutboundPhoneCallHandler.LlmContexts;
|
||||
using Twilio.Rest.Api.V2010.Account;
|
||||
using Twilio.TwiML.Messaging;
|
||||
using Twilio.Types;
|
||||
using Conversation = BotSharp.Abstraction.Conversations.Models.Conversation;
|
||||
using Task = System.Threading.Tasks.Task;
|
||||
|
|
@ -176,7 +177,7 @@ public class OutboundPhoneCallFn : IFunctionCallback
|
|||
});
|
||||
|
||||
var utcNow = DateTime.UtcNow;
|
||||
var excludStates = new List<string>
|
||||
var excludeStates = new List<string>
|
||||
{
|
||||
"provider",
|
||||
"model",
|
||||
|
|
@ -185,22 +186,34 @@ public class OutboundPhoneCallFn : IFunctionCallback
|
|||
"llm_total_cost"
|
||||
};
|
||||
|
||||
var curStates = state.GetStates().Select(x => new MessageState(x.Key, x.Value)).ToList();
|
||||
var curConvStates = state.GetStates().Select(x => new MessageState(x.Key, x.Value)).ToList();
|
||||
var subConvStates = new List<MessageState>
|
||||
{
|
||||
new(StateConst.ORIGIN_CONVERSATION_ID, originConversationId),
|
||||
new("channel", "phone"),
|
||||
new("phone_from", call.From),
|
||||
new("phone_direction", call.Direction),
|
||||
new("phone_number", call.To),
|
||||
new("twilio_call_sid", call.Sid)
|
||||
new(StateConst.ORIGIN_CONVERSATION_ID, originConversationId, isGlobal: true),
|
||||
new("channel", "phone", isGlobal: true),
|
||||
new("phone_from", call.From, isGlobal: true),
|
||||
new("phone_direction", call.Direction, isGlobal: true),
|
||||
new("phone_number", call.To, isGlobal: true),
|
||||
new("twilio_call_sid", call.Sid, isGlobal: true)
|
||||
};
|
||||
var subStateKeys = subConvStates.Select(x => x.Key).ToList();
|
||||
var included = curStates.Where(x => !subStateKeys.Contains(x.Key) && !excludStates.Contains(x.Key));
|
||||
var newStates = subConvStates.Concat(included).Select(x => new StateKeyValue
|
||||
var included = curConvStates.Where(x => !subStateKeys.Contains(x.Key) && !excludeStates.Contains(x.Key));
|
||||
|
||||
var mappedCurConvStates = MapStates(included, messageId, utcNow);
|
||||
var mappedSubConvStates = MapStates(subConvStates, messageId, utcNow);
|
||||
var allStates = mappedCurConvStates.Concat(mappedSubConvStates).ToList();
|
||||
|
||||
db.UpdateConversationStates(newConversationId, allStates);
|
||||
}
|
||||
|
||||
private IEnumerable<StateKeyValue> MapStates(IEnumerable<MessageState> states, string messageId, DateTime updateTime)
|
||||
{
|
||||
if (states.IsNullOrEmpty()) return [];
|
||||
|
||||
return states.Select(x => new StateKeyValue
|
||||
{
|
||||
Key = x.Key,
|
||||
Versioning = true,
|
||||
Versioning = !x.Global,
|
||||
Values = [
|
||||
new StateValue
|
||||
{
|
||||
|
|
@ -209,11 +222,9 @@ public class OutboundPhoneCallFn : IFunctionCallback
|
|||
Active = true,
|
||||
ActiveRounds = x.ActiveRounds,
|
||||
Source = StateSource.Application,
|
||||
UpdateTime = utcNow
|
||||
UpdateTime = updateTime
|
||||
}
|
||||
]
|
||||
}).ToList();
|
||||
|
||||
db.UpdateConversationStates(newConversationId, newStates);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,6 +114,11 @@ public partial class PlaywrightWebDriver
|
|||
// fix if html has &
|
||||
result.Body = HttpUtility.HtmlDecode(html);
|
||||
result.IsSuccess = true;
|
||||
var hooks = _services.GetServices<IWebDriverHook>();
|
||||
foreach (var hook in hooks)
|
||||
{
|
||||
await hook.OnLocateElement(message, result.Body);
|
||||
}
|
||||
}
|
||||
else if (count > 1)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ public class UtilWebCloseBrowserFn : IFunctionCallback
|
|||
ContextId = webDriverService.GetMessageContext(message)
|
||||
};
|
||||
|
||||
await browser.CloseBrowser(message.CurrentAgentId);
|
||||
await browser.CloseBrowser(msg.ContextId);
|
||||
|
||||
message.Content = $"Browser closed.";
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ public class UtilWebLocateElementFn : IFunctionCallback
|
|||
MessageId = message.MessageId,
|
||||
ContextId = webDriverService.GetMessageContext(message)
|
||||
};
|
||||
browser.SetServiceProvider(_services);
|
||||
var result = await browser.LocateElement(msg, locatorArgs);
|
||||
|
||||
message.Content = $"Locating element {(result.IsSuccess ? "success" : "failed")}. ";
|
||||
|
|
|
|||
Loading…
Reference in a new issue