Skip to content

X-Twilio-BotSharp #820

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ public class ConversationChannel
public const string Messenger = "messenger";
public const string Email = "email";
public const string Cron = "cron";
public const string Database = "database";
}
71 changes: 65 additions & 6 deletions src/Infrastructure/BotSharp.Core.Rules/Engines/RuleEngine.cs
Original file line number Diff line number Diff line change
@@ -1,26 +1,85 @@
using BotSharp.Abstraction.Conversations;
using BotSharp.Abstraction.Conversations.Enums;
using BotSharp.Abstraction.Models;
using BotSharp.Abstraction.Repositories.Filters;
using BotSharp.Abstraction.Routing;
using BotSharp.Abstraction.Utilities;
using BotSharp.Core.Rules.Triggers;
using Microsoft.Extensions.Logging;
using System.Data;

namespace BotSharp.Core.Rules.Engines;

public class RuleEngine : IRuleEngine
{
private readonly IServiceProvider _services;
public RuleEngine(IServiceProvider services)
private readonly ILogger _logger;

public RuleEngine(IServiceProvider services, ILogger<RuleEngine> logger)
{
_services = services;
_logger = logger;
}

public async Task Triggered(IRuleTrigger trigger, string data)
{
// Pull all user defined rules

var agentService = _services.GetRequiredService<IAgentService>();
var agents = await agentService.GetAgents(new AgentFilter
{
Pager = new Pagination
{
Size = 1000
}
});

var preFilteredAgents = agents.Items.Where(x =>
x.Rules.Exists(r => r.TriggerName == trigger.Name &&
!x.Disabled)).ToList();

// Trigger the agents
var instructService = _services.GetRequiredService<IInstructService>();
var convService = _services.GetRequiredService<IConversationService>();

foreach (var agent in preFilteredAgents)
{
var conv = await convService.NewConversation(new Conversation
{
AgentId = agent.Id
});

var message = new RoleDialogModel(AgentRole.User, data);

var states = new List<MessageState>
{
new("channel", ConversationChannel.Database),
new("channel_id", trigger.EntityId)
};
convService.SetConversationId(conv.Id, states);

await convService.SendMessage(agent.Id,
message,
null,
msg => Task.CompletedTask);

/*foreach (var rule in agent.Rules)
{
var userSay = $"===Input data with Before and After values===\r\n{data}\r\n\r\n===Trigger Criteria===\r\n{rule.Criteria}\r\n\r\nJust output 1 or 0 without explanation: ";

var userSay = $"===Input data===\r\n{data}\r\n\r\nWhen WO NTE is greater than 100, notify resident.";
var result = await instructService.Execute(BuiltInAgentId.RulesInterpreter, new RoleDialogModel(AgentRole.User, userSay), "criteria_check", "#TEMPLATE#");

var result = await instructService.Execute(BuiltInAgentId.RulesInterpreter, new RoleDialogModel(AgentRole.User, data), "criteria_check", "#TEMPLATE#");
// Check if meet the criteria
if (result.Text == "1")
{
// Hit rule
_logger.LogInformation($"Hit rule {rule.TriggerName} {rule.EntityType} {rule.EventName}, {data}");

string[] rules = [];
// Check if meet the criteria
await convService.SendMessage(agent.Id,
new RoleDialogModel(AgentRole.User, $"The conversation was triggered by {rule.Criteria}"),
null,
msg => Task.CompletedTask);
}
}*/
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ public interface IRuleTrigger
{
string Channel => throw new NotImplementedException("Please set the channel of trigger");

string EventName { get; set; }
string Name { get; set; }

string EntityType { get; set; }

string EntityId { get; set; }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "201e49a2-40b3-4ccd-b8cc-2476565a1b40",
"name": "Rules Agent",
"description": "Utility assistant that can be used to complete many different tasks",
"description": "Rules understands and converts user-defined rules into Triggers, Criterias and Actions",
"type": "static",
"createdDateTime": "2024-12-30T00:00:00Z",
"updatedDateTime": "2024-12-30T00:00:00Z",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
You are a rule interpreter, analyze and respond according to the following steps:
1. Understand the rules customized by the user;
2. Determine whether the input data meets the user's action execution conditions;
3. If it meets the conditions, output "true", otherwise output "false"
3. If it meets the conditions, output number "1", otherwise output "0"
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace BotSharp.Plugin.HttpHandler.Functions;
public class HandleHttpRequestFn : IFunctionCallback
{
public string Name => "util-http-handle_http_request";
public string Indication => "Handling http request";
public string Indication => "Give me a second, I'm taking care of it!";

private readonly IServiceProvider _services;
private readonly ILogger<HandleHttpRequestFn> _logger;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using BotSharp.Abstraction.Files;
using BotSharp.Abstraction.Options;
using BotSharp.Abstraction.Routing;
using BotSharp.Core.Infrastructures;
using BotSharp.Plugin.Twilio.Interfaces;
using BotSharp.Plugin.Twilio.Models;
Expand Down Expand Up @@ -49,10 +50,28 @@ public async Task<bool> Execute(RoleDialogModel message)
return false;
}

var convService = _services.GetRequiredService<IConversationService>();
var convStorage = _services.GetRequiredService<IConversationStorage>();
var routing = _services.GetRequiredService<IRoutingContext>();
var fileStorage = _services.GetRequiredService<IFileStorageService>();
var sessionManager = _services.GetRequiredService<ITwilioSessionManager>();
var convService = _services.GetRequiredService<IConversationService>();
var conversationId = convService.ConversationId;

// Fork conversation
var entryAgentId = routing.EntryAgentId;
var newConv = await convService.NewConversation(new Abstraction.Conversations.Models.Conversation
{
AgentId = entryAgentId,
Channel = ConversationChannel.Phone
});
var conversationId = newConv.Id;
convStorage.Append(conversationId, new RoleDialogModel(AgentRole.User, "Hi, I'm calling to check my work order quote status, please help me locate my work order number and let me know what to do next.")
{
CurrentAgentId = entryAgentId
});
convStorage.Append(conversationId, new RoleDialogModel(AgentRole.Assistant, args.InitialMessage)
{
CurrentAgentId = entryAgentId
});

// Generate audio
var completion = CompletionProvider.GetAudioCompletion(_services, "openai", "tts-1");
Expand All @@ -72,7 +91,7 @@ public async Task<bool> Execute(RoleDialogModel message)
to: new PhoneNumber(args.PhoneNumber),
from: new PhoneNumber(_twilioSetting.PhoneNumber));

message.Content = $"The generated phone message: {args.InitialMessage}" ?? message.Content;
message.Content = $"The generated phone message: {args.InitialMessage}. \r\n[Conversation ID: {conversationId}]" ?? message.Content;
message.StopCompletion = true;
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ private async Task ProcessUserMessageAsync(CallerMessage message)
var httpContext = sp.GetRequiredService<IHttpContextAccessor>();
httpContext.HttpContext = new DefaultHttpContext();
httpContext.HttpContext.User = new ClaimsPrincipal(new ClaimsIdentity());
httpContext.HttpContext.Request.Headers["X-Twilio-BotSharp"] = "LOST";

AssistantMessage reply = null;
var inputMsg = new RoleDialogModel(AgentRole.User, message.Content);
Expand All @@ -75,8 +76,11 @@ private async Task ProcessUserMessageAsync(CallerMessage message)
var progressService = sp.GetRequiredService<IConversationProgressService>();
InitProgressService(message, sessionManager, progressService);
InitConversation(message, inputMsg, conv, routing);

var result = await conv.SendMessage(config.AgentId,

var conversation = await conv.GetConversation(message.ConversationId);
var agentId = string.IsNullOrWhiteSpace(conversation.AgentId) ? config.AgentId : conversation.AgentId;

var result = await conv.SendMessage(agentId,
inputMsg,
replyMessage: BuildPostbackMessageModel(conv, message),
async msg =>
Expand Down