diff --git a/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj b/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj index 18ddee55..ba1ea69d 100644 --- a/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj +++ b/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj @@ -31,8 +31,4 @@ - - - - diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationStateService.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationStateService.cs index 26655e2b..07b713c9 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationStateService.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationStateService.cs @@ -5,6 +5,7 @@ namespace BotSharp.Abstraction.Conversations; /// public interface IConversationStateService { + string GetConversationId(); ConversationState Load(string conversationId); string GetState(string name, string defaultValue = ""); bool ContainsState(string name); diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs index f08e5a66..0aa0cd04 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs @@ -32,6 +32,8 @@ public class RoleDialogModel : ITrackableMessage /// [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public object Data { get; set; } + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public object? RichContent { get; set; } /// /// Stop conversation completion diff --git a/src/Infrastructure/BotSharp.Abstraction/Messaging/Models/RichContent/QuickReplyElement.cs b/src/Infrastructure/BotSharp.Abstraction/Messaging/Models/RichContent/QuickReplyElement.cs new file mode 100644 index 00000000..1be8f208 --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Messaging/Models/RichContent/QuickReplyElement.cs @@ -0,0 +1,15 @@ + +namespace BotSharp.Abstraction.Messaging.Models.RichContent +{ + public class QuickReplyElement + { + [JsonPropertyName("content_type")] + public string ContentType { get; set; } = string.Empty; + public string Title { get; set; } = string.Empty; + public string? Payload { get; set; } + [JsonPropertyName("image_url")] + public string? ImageUrl { get; set; } + [JsonPropertyName("postback_url")] + public string? PostBackUrl { get; set; } + } +} diff --git a/src/Infrastructure/BotSharp.Abstraction/Messaging/Models/RichContent/QuickReplyMessage.cs b/src/Infrastructure/BotSharp.Abstraction/Messaging/Models/RichContent/QuickReplyMessage.cs new file mode 100644 index 00000000..b14b27e1 --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Messaging/Models/RichContent/QuickReplyMessage.cs @@ -0,0 +1,9 @@ + +namespace BotSharp.Abstraction.Messaging.Models.RichContent +{ + public class QuickReplyMessage : TextMessage + { + [JsonPropertyName("quick_replies")] + public List QuickReplies { get; set; } = new List(); + } +} diff --git a/src/Infrastructure/BotSharp.Abstraction/Messaging/Models/RichContent/Recipient.cs b/src/Infrastructure/BotSharp.Abstraction/Messaging/Models/RichContent/Recipient.cs new file mode 100644 index 00000000..5c77924a --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Messaging/Models/RichContent/Recipient.cs @@ -0,0 +1,8 @@ + +namespace BotSharp.Abstraction.Messaging.Models.RichContent +{ + public class Recipient + { + public string Id { get; set; } = string.Empty; + } +} diff --git a/src/Infrastructure/BotSharp.Abstraction/Messaging/Models/RichContent/RichContent.cs b/src/Infrastructure/BotSharp.Abstraction/Messaging/Models/RichContent/RichContent.cs new file mode 100644 index 00000000..221dc96d --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Messaging/Models/RichContent/RichContent.cs @@ -0,0 +1,13 @@ +namespace BotSharp.Abstraction.Messaging.Models.RichContent +{ + public class RichContent + { + public Recipient Recipient { get; set; } = new Recipient(); + /// + /// RESPONSE + /// + [JsonPropertyName("messaging_type")] + public string MessagingType => "RESPONSE"; + public T Message { get; set; } + } +} diff --git a/src/Infrastructure/BotSharp.Abstraction/Messaging/Models/RichContent/SenderActionMessage.cs b/src/Infrastructure/BotSharp.Abstraction/Messaging/Models/RichContent/SenderActionMessage.cs new file mode 100644 index 00000000..6b652e4e --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Messaging/Models/RichContent/SenderActionMessage.cs @@ -0,0 +1,15 @@ + +namespace BotSharp.Abstraction.Messaging.Models.RichContent +{ + public class SenderActionMessage + { + /* + * Requests to display sender action should only include the sender_action parameter and the recipient object. + * All other Send API properties, such as text and templates, should be sent in a separate request. + */ + public Recipient Recipient { get; set; } = new Recipient(); + + [JsonPropertyName("sender_action")] + public string SenderAction { get; set; } = string.Empty; + } +} diff --git a/src/Infrastructure/BotSharp.Abstraction/Messaging/Models/RichContent/Template/AttachmentTemplate.cs b/src/Infrastructure/BotSharp.Abstraction/Messaging/Models/RichContent/Template/AttachmentTemplate.cs new file mode 100644 index 00000000..89f2137e --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Messaging/Models/RichContent/Template/AttachmentTemplate.cs @@ -0,0 +1,9 @@ + +namespace BotSharp.Abstraction.Messaging.Models.RichContent.Template +{ + public class AttachmentTemplate + { + public string Type => "template"; + public T Payload { get; set; } + } +} diff --git a/src/Infrastructure/BotSharp.Abstraction/Messaging/Models/RichContent/Template/ButtonTemplate.cs b/src/Infrastructure/BotSharp.Abstraction/Messaging/Models/RichContent/Template/ButtonTemplate.cs new file mode 100644 index 00000000..f610a682 --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Messaging/Models/RichContent/Template/ButtonTemplate.cs @@ -0,0 +1,17 @@ + +namespace BotSharp.Abstraction.Messaging.Models.RichContent.Template +{ + public class ButtonTemplate : TextMessage + { + [JsonPropertyName("template_type")] + public string TemplateType => "button"; + public List Buttons { get; set; } = new List(); + } + + public class ButtonElement + { + public string Type { get; set; } = string.Empty; + public string? Url { get; set; } + public string Title { get; set; } = string.Empty; + } +} diff --git a/src/Infrastructure/BotSharp.Abstraction/Messaging/Models/RichContent/Template/CommonTemplate.cs b/src/Infrastructure/BotSharp.Abstraction/Messaging/Models/RichContent/Template/CommonTemplate.cs new file mode 100644 index 00000000..e4b3ea8c --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Messaging/Models/RichContent/Template/CommonTemplate.cs @@ -0,0 +1,10 @@ + +namespace BotSharp.Abstraction.Messaging.Models.RichContent.Template +{ + public class CommonTemplate + { + [JsonPropertyName("template_type")] + public string TemplateType { get; set; } = string.Empty; + public T Elements { get; set; } + } +} diff --git a/src/Infrastructure/BotSharp.Abstraction/Messaging/Models/RichContent/Template/TemplateMessage.cs b/src/Infrastructure/BotSharp.Abstraction/Messaging/Models/RichContent/Template/TemplateMessage.cs new file mode 100644 index 00000000..77b4a55f --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Messaging/Models/RichContent/Template/TemplateMessage.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace BotSharp.Abstraction.Messaging.Models.RichContent.Template +{ + public class TemplateMessage + { + public T Attachment { get; set; } + } +} diff --git a/src/Infrastructure/BotSharp.Abstraction/Messaging/Models/RichContent/TextMessage.cs b/src/Infrastructure/BotSharp.Abstraction/Messaging/Models/RichContent/TextMessage.cs new file mode 100644 index 00000000..94d85894 --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Messaging/Models/RichContent/TextMessage.cs @@ -0,0 +1,8 @@ + +namespace BotSharp.Abstraction.Messaging.Models.RichContent +{ + public class TextMessage + { + public string Text { get; set; } = string.Empty; + } +} \ No newline at end of file diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs index 387a18e7..482857d9 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs @@ -1,4 +1,5 @@ using BotSharp.Abstraction.Agents.Models; +using BotSharp.Abstraction.Messaging.Models.RichContent; using BotSharp.Abstraction.Routing; using BotSharp.Abstraction.Routing.Settings; using System.Drawing; @@ -100,6 +101,14 @@ public partial class ConversationService _logger.LogInformation(text); #endif + // Only read content from RichContent for UI rendering. When richContent is null, create a basic text message for richContent. + var state = _services.GetRequiredService(); + message.RichContent = message.RichContent ?? new RichContent + { + Recipient = new Recipient { Id = state.GetConversationId() }, + Message = new TextMessage { Text = message.Content } + }; + var hooks = _services.GetServices().ToList(); foreach (var hook in hooks) { diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStateService.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStateService.cs index 1f0fe199..7004b929 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStateService.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStateService.cs @@ -28,6 +28,8 @@ public class ConversationStateService : IConversationStateService, IDisposable _states = new ConversationState(); } + public string GetConversationId() => _conversationId; + public IConversationStateService SetState(string name, T value) { if (value == null) diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs index 5fb5cd7c..80692bc9 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs @@ -12,7 +12,7 @@ public class ConversationController : ControllerBase, IApiAdapter private readonly IServiceProvider _services; private readonly IUserIdentity _user; - public ConversationController(IServiceProvider services, + public ConversationController(IServiceProvider services, IUserIdentity user) { _services = services; @@ -40,8 +40,8 @@ public class ConversationController : ControllerBase, IApiAdapter } [HttpPost("/conversation/{agentId}/{conversationId}")] - public async Task SendMessage([FromRoute] string agentId, - [FromRoute] string conversationId, + public async Task SendMessage([FromRoute] string agentId, + [FromRoute] string conversationId, [FromBody] NewMessageModel input) { var conv = _services.GetRequiredService(); @@ -73,6 +73,7 @@ public class ConversationController : ControllerBase, IApiAdapter response.Data = inputMsg.Data; response.Function = inputMsg.FunctionName; response.Instruction = inputMsg.Instruction; + response.RichContent = inputMsg.RichContent; return response; } diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/MessageResponseModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/MessageResponseModel.cs index 4dcf0c58..4fe7781c 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/MessageResponseModel.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/MessageResponseModel.cs @@ -1,6 +1,5 @@ using BotSharp.Abstraction.Functions.Models; using BotSharp.Abstraction.Models; -using BotSharp.Abstraction.Routing.Models; namespace BotSharp.OpenAPI.ViewModels.Conversations; @@ -11,4 +10,5 @@ public class MessageResponseModel : ITrackableMessage public string Function { get; set; } public object Data { get; set; } public FunctionCallFromLlm Instruction { get; set; } + public object? RichContent { get; set; } }