diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs index ea6a03d86..1592aa8f7 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs @@ -1,5 +1,3 @@ -using BotSharp.Abstraction.Functions.Models; - namespace BotSharp.Abstraction.Conversations; public abstract class ConversationHookBase : IConversationHook diff --git a/src/Infrastructure/BotSharp.Abstraction/Models/MessageConfig.cs b/src/Infrastructure/BotSharp.Abstraction/Models/MessageConfig.cs index 17ffeee44..1c4fc26bf 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Models/MessageConfig.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Models/MessageConfig.cs @@ -17,13 +17,13 @@ public class MessageConfig : TruncateMessageRequest /// /// The sampling temperature to use that controls the apparent creativity of generated completions. /// - public float Temperature { get; set; } = 0.5f; + public float Temperature { get; set; } = 0f; /// /// An alternative value to Temperature, called nucleus sampling, that causes /// the model to consider the results of the tokens with probability mass. /// - public float SamplingFactor { get; set; } = 0.5f; + public float SamplingFactor { get; set; } = 0f; /// /// Conversation states from input diff --git a/src/Infrastructure/BotSharp.Core/Templating/TemplateRender.cs b/src/Infrastructure/BotSharp.Core/Templating/TemplateRender.cs index 62d5c3e0c..a5aef0f4b 100644 --- a/src/Infrastructure/BotSharp.Core/Templating/TemplateRender.cs +++ b/src/Infrastructure/BotSharp.Core/Templating/TemplateRender.cs @@ -27,6 +27,7 @@ public TemplateRender(IServiceProvider services, ILogger logger) _options.MemberAccessStrategy.Register(); _options.MemberAccessStrategy.Register(); _options.MemberAccessStrategy.Register(); + _options.MemberAccessStrategy.Register(); } public string Render(string template, Dictionary dict) diff --git a/src/Infrastructure/BotSharp.Core/Users/Services/UserIdentity.cs b/src/Infrastructure/BotSharp.Core/Users/Services/UserIdentity.cs index 8e5852ccf..b8acdeeac 100644 --- a/src/Infrastructure/BotSharp.Core/Users/Services/UserIdentity.cs +++ b/src/Infrastructure/BotSharp.Core/Users/Services/UserIdentity.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Http; using System.Security.Claims; +using System.Text.Json.Serialization; namespace BotSharp.Core.Users.Services; @@ -17,12 +18,14 @@ public UserIdentity(IHttpContextAccessor contextAccessor) public string Id => _claims?.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier)?.Value!; + [JsonPropertyName("user_name")] public string UserName => _claims?.FirstOrDefault(x => x.Type == ClaimTypes.Name)?.Value!; public string Email => _claims?.FirstOrDefault(x => x.Type == ClaimTypes.Email)?.Value!; + [JsonPropertyName("first_name")] public string FirstName { get @@ -36,9 +39,21 @@ public string FirstName } } + [JsonPropertyName("last_name")] public string LastName => _claims?.FirstOrDefault(x => x.Type == ClaimTypes.Surname)?.Value!; + [JsonPropertyName("full_name")] public string FullName - => $"{FirstName} {LastName}".Trim(); + { + get + { + var fullName = _claims?.FirstOrDefault(x => x.Type == "full_name")?.Value; + if (!string.IsNullOrEmpty(fullName)) + { + return fullName; + } + return $"{FirstName} {LastName}".Trim(); + } + } } diff --git a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs index 9b855af48..139db8087 100644 --- a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs +++ b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs @@ -254,8 +254,8 @@ public async Task GetChatCompletionsStreamingAsync(Agent agent, List(); - var temperature = float.Parse(state.GetState("temperature", "0.5")); - var samplingFactor = float.Parse(state.GetState("sampling_factor", "0.5")); + var temperature = float.Parse(state.GetState("temperature", "0.0")); + var samplingFactor = float.Parse(state.GetState("sampling_factor", "0.0")); chatCompletionsOptions.Temperature = temperature; chatCompletionsOptions.NucleusSamplingFactor = samplingFactor; // chatCompletionsOptions.FrequencyPenalty = 0; diff --git a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/TextCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/TextCompletionProvider.cs index 1078a36b5..f2ca51111 100644 --- a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/TextCompletionProvider.cs +++ b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/TextCompletionProvider.cs @@ -63,8 +63,8 @@ public async Task GetCompletion(string text, string agentId, string mess completionsOptions.StopSequences.Add($"{AgentRole.Assistant}:"); var state = _services.GetRequiredService(); - var temperature = float.Parse(state.GetState("temperature", "0.5")); - var samplingFactor = float.Parse(state.GetState("sampling_factor", "0.5")); + var temperature = float.Parse(state.GetState("temperature", "0.0")); + var samplingFactor = float.Parse(state.GetState("sampling_factor", "0.0")); completionsOptions.Temperature = temperature; completionsOptions.NucleusSamplingFactor = samplingFactor; completionsOptions.DeploymentName = _model; diff --git a/src/Plugins/BotSharp.Plugin.ChatHub/ChatHubPlugin.cs b/src/Plugins/BotSharp.Plugin.ChatHub/ChatHubPlugin.cs index 7825f0f10..5bd9a8ced 100644 --- a/src/Plugins/BotSharp.Plugin.ChatHub/ChatHubPlugin.cs +++ b/src/Plugins/BotSharp.Plugin.ChatHub/ChatHubPlugin.cs @@ -19,8 +19,9 @@ public void RegisterDI(IServiceCollection services, IConfiguration config) { // Register hooks services.AddScoped(); - services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.AddScoped(); + services.AddScoped(); } } diff --git a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs index 23c48ee39..187c2bf42 100644 --- a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs +++ b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs @@ -1,7 +1,5 @@ -using BotSharp.Abstraction.Messaging; using BotSharp.Abstraction.Messaging.Enums; using BotSharp.Abstraction.Messaging.JsonConverters; -using BotSharp.Abstraction.Messaging.Models.RichContent; using Microsoft.AspNetCore.SignalR; namespace BotSharp.Plugin.ChatHub.Hooks; @@ -31,42 +29,6 @@ public ChatHubConversationHook(IServiceProvider services, }; } - public override async Task OnUserAgentConnectedInitially(Conversation conversation) - { - var agentService = _services.GetRequiredService(); - var agent = await agentService.LoadAgent(conversation.AgentId); - - // Check if the Welcome template exists. - var welcomeTemplate = agent.Templates?.FirstOrDefault(x => x.Name == ".welcome"); - if (welcomeTemplate != null) - { - var richContentService = _services.GetRequiredService(); - var messages = richContentService.ConvertToMessages(welcomeTemplate.Content); - - foreach (var message in messages) - { - var json = JsonSerializer.Serialize(new ChatResponseModel() - { - ConversationId = conversation.Id, - Text = message.Text, - RichContent = new RichContent(message), - Sender = new UserViewModel() - { - FirstName = "AI", - LastName = "Assistant", - Role = AgentRole.Assistant - } - }, _serializerOptions); - - await Task.Delay(300); - - await _chatHub.Clients.User(_user.Id).SendAsync("OnMessageReceivedFromAssistant", json); - } - } - - await base.OnUserAgentConnectedInitially(conversation); - } - public override async Task OnConversationInitialized(Conversation conversation) { var userService = _services.GetRequiredService(); diff --git a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs index 3a166e2b6..f06020808 100644 --- a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs +++ b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs @@ -233,7 +233,7 @@ public async Task OnAgentQueueEmptied(string agentId, string? reason = null) await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", BuildContentLog(input)); } - public async Task OnRoutingInstructionRevised(FunctionCallFromLlm instruct, RoleDialogModel message) + public async Task OnRoutingInstructionReceived(FunctionCallFromLlm instruct, RoleDialogModel message) { var conversationId = _state.GetConversationId(); var agent = await _agentService.LoadAgent(message.CurrentAgentId); @@ -249,6 +249,22 @@ public async Task OnRoutingInstructionRevised(FunctionCallFromLlm instruct, Role }; await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", BuildContentLog(input)); } + + public async Task OnRoutingInstructionRevised(FunctionCallFromLlm instruct, RoleDialogModel message) + { + var conversationId = _state.GetConversationId(); + var agent = await _agentService.LoadAgent(message.CurrentAgentId); + var log = $"Revised user goal agent to: {agent?.Name}"; + + var input = new ContentLogInputModel(conversationId, message) + { + Name = agent?.Name, + AgentId = agent?.Id, + Source = ContentLogSource.HardRule, + Log = log + }; + await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", BuildContentLog(input)); + } #endregion diff --git a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/WelcomeHook.cs b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/WelcomeHook.cs new file mode 100644 index 000000000..9c8237e7e --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/WelcomeHook.cs @@ -0,0 +1,85 @@ +using BotSharp.Abstraction.Messaging.Models.RichContent; +using BotSharp.Abstraction.Messaging; +using BotSharp.Abstraction.Templating; +using BotSharp.Abstraction.Messaging.JsonConverters; +using Microsoft.AspNetCore.SignalR; + +namespace BotSharp.Plugin.ChatHub.Hooks; + +public class WelcomeHook : ConversationHookBase +{ + private readonly IServiceProvider _services; + private readonly IHubContext _chatHub; + private readonly IUserIdentity _user; + private readonly IConversationStorage _storage; + private readonly JsonSerializerOptions _serializerOptions; + public WelcomeHook(IServiceProvider services, + IHubContext chatHub, + IUserIdentity user, + IConversationStorage storage) + { + _services = services; + _chatHub = chatHub; + _user = user; + _storage = storage; + + _serializerOptions = new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + Converters = + { + new RichContentJsonConverter(), + new TemplateMessageJsonConverter(), + } + }; + } + + public override async Task OnUserAgentConnectedInitially(Conversation conversation) + { + var agentService = _services.GetRequiredService(); + var agent = await agentService.LoadAgent(conversation.AgentId); + + // Check if the Welcome template exists. + var welcomeTemplate = agent.Templates?.FirstOrDefault(x => x.Name == ".welcome"); + if (welcomeTemplate != null) + { + // Render template + var templating = _services.GetRequiredService(); + var user = _services.GetRequiredService(); + var richContent = templating.Render(welcomeTemplate.Content, new Dictionary + { + { "user", user } + }); + var richContentService = _services.GetRequiredService(); + var messages = richContentService.ConvertToMessages(richContent); + + foreach (var message in messages) + { + var json = JsonSerializer.Serialize(new ChatResponseModel() + { + ConversationId = conversation.Id, + Text = message.Text, + RichContent = new RichContent(message), + Sender = new UserViewModel() + { + FirstName = agent.Name, + LastName = "", + Role = AgentRole.Assistant + } + }, _serializerOptions); + + await Task.Delay(300); + + _storage.Append(conversation.Id, new RoleDialogModel(AgentRole.Assistant, message.Text) + { + MessageId = conversation.Id, + CurrentAgentId = agent.Id, + }); + + await _chatHub.Clients.User(_user.Id).SendAsync("OnMessageReceivedFromAssistant", json); + } + } + + await base.OnUserAgentConnectedInitially(conversation); + } +}