diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/AgentHookBase.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/AgentHookBase.cs
index 34a657b1..6953dee9 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/AgentHookBase.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/AgentHookBase.cs
@@ -1,3 +1,5 @@
+using BotSharp.Abstraction.Conversations.Models;
+
namespace BotSharp.Abstraction.Agents;
public abstract class AgentHookBase : IAgentHook
@@ -33,8 +35,12 @@ public abstract class AgentHookBase : IAgentHook
return true;
}
- public virtual Agent OnAgentLoaded()
+ public virtual void OnAgentLoaded(Agent agent)
{
- return _agent;
+ }
+
+ public virtual bool OnAgentRouting(RoleDialogModel message, ref string id)
+ {
+ return true;
}
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentHook.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentHook.cs
index b91fc073..7b0b73dd 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentHook.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentHook.cs
@@ -24,5 +24,5 @@ public interface IAgentHook
///
///
///
- Agent OnAgentLoaded();
+ void OnAgentLoaded(Agent agent);
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentRouting.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentRouting.cs
new file mode 100644
index 00000000..2a1f18fa
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentRouting.cs
@@ -0,0 +1,6 @@
+namespace BotSharp.Abstraction.Agents;
+
+public interface IAgentRouting
+{
+ Task LoadCurrentAgent();
+}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs
index 122a14be..1e22d6f6 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs
@@ -1,5 +1,3 @@
-using BotSharp.Abstraction.Conversations.Models;
-
namespace BotSharp.Abstraction.Agents.Models;
public class Agent
@@ -29,4 +27,7 @@ public class Agent
/// Domain knowledges
///
public string Knowledges { get; set; }
+
+ public override string ToString()
+ => $"{Name} {Id}";
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Settings/AgentSettings.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Settings/AgentSettings.cs
index f51e1941..6b092805 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/Settings/AgentSettings.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Settings/AgentSettings.cs
@@ -2,5 +2,9 @@ namespace BotSharp.Abstraction.Agents.Settings;
public class AgentSettings
{
+ ///
+ /// Router Agent Id
+ ///
+ public string RouterId { get; set; }
public string DataDir { get; set; }
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs
index dc883adf..3886445a 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs
@@ -8,25 +8,25 @@ public class RoleDialogModel
public string Role { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public string Content { get; set; }
+ public string CurrentAgentId { get; set; }
///
/// Function name if LLM response function call
///
public string? FunctionName { get; set; }
+ public string? FunctionArgs { get; set; }
+
///
/// Function execution result
///
public string? ExecutionResult { get; set; }
- ///
- /// When function callback has been executed, system will pass result to LLM again,
- /// Set this property to True to stop calling LLM.
- ///
- public bool StopSubsequentInteraction { get; set; }
-
public bool IsConversationEnd { get; set; }
+ public bool NeedReloadAgent { get; set; }
+ public bool StopPropagate { get; set; }
+
///
/// Channel name
///
diff --git a/src/Infrastructure/BotSharp.Abstraction/MLTasks/IChatCompletion.cs b/src/Infrastructure/BotSharp.Abstraction/MLTasks/IChatCompletion.cs
index 2e8f6438..26fecf8a 100644
--- a/src/Infrastructure/BotSharp.Abstraction/MLTasks/IChatCompletion.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/MLTasks/IChatCompletion.cs
@@ -4,7 +4,7 @@ namespace BotSharp.Abstraction.MLTasks;
public interface IChatCompletion
{
- string GetChatCompletions(Agent agent, List conversations);
+ // string GetChatCompletions(Agent agent, List conversations, Func onMessageReceived);
Task GetChatCompletionsAsync(Agent agent, List conversations, Func onMessageReceived);
Task GetChatCompletionsStreamingAsync(Agent agent, List conversations, Func onMessageReceived);
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Utilities/StringExtensions.cs b/src/Infrastructure/BotSharp.Abstraction/Utilities/StringExtensions.cs
index 0da63437..651adad7 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Utilities/StringExtensions.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Utilities/StringExtensions.cs
@@ -1,3 +1,6 @@
+using System.Linq;
+using System.Text.RegularExpressions;
+
namespace BotSharp.Abstraction.Utilities;
public static class StringExtensions
@@ -15,4 +18,19 @@ public static class StringExtensions
else
return str;
}
+
+ public static string CleanPhoneNumber(this string phoneNumber)
+ {
+ if (phoneNumber != null && !phoneNumber.All(char.IsDigit))
+ {
+ phoneNumber = Regex.Replace(phoneNumber, @"[^\d]", "");
+ }
+
+ if (phoneNumber != null && phoneNumber.Length > 10)
+ {
+ phoneNumber = phoneNumber.Substring(1);
+ }
+
+ return phoneNumber;
+ }
}
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentRouter.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentRouter.cs
new file mode 100644
index 00000000..8f112392
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentRouter.cs
@@ -0,0 +1,37 @@
+using BotSharp.Abstraction.Agents.Models;
+
+namespace BotSharp.Core.Agents.Services;
+
+public class AgentRouter : IAgentRouting
+{
+ private readonly IServiceProvider _services;
+ private readonly ILogger _logger;
+ private readonly AgentSettings _settings;
+
+ public AgentRouter(IServiceProvider services,
+ ILogger logger,
+ AgentSettings settings)
+ {
+ _services = services;
+ _logger = logger;
+ _settings = settings;
+ }
+
+ public async Task LoadCurrentAgent()
+ {
+ // Load current agent from state
+ var stateService = _services.GetRequiredService();
+ var currentAgentId = stateService.GetState("agentId");
+ if (string.IsNullOrEmpty(currentAgentId))
+ {
+ currentAgentId = _settings.RouterId;
+ }
+ var agentService = _services.GetRequiredService();
+ var agent = await agentService.LoadAgent(currentAgentId);
+
+ // Set agent and trigger state changed
+ stateService.SetState("agentId", currentAgentId);
+
+ return agent;
+ }
+}
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs
index 5d9d7b4f..09c463ee 100644
--- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs
+++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs
@@ -39,9 +39,11 @@ public partial class AgentService
hook.OnSamplesLoaded(ref samples);
}
- hook.OnAgentLoaded();
+ hook.OnAgentLoaded(agent);
}
+ _logger.LogInformation($"Loaded agent {agent}.");
+
return agent;
}
}
diff --git a/src/Infrastructure/BotSharp.Core/BotSharpServiceCollectionExtensions.cs b/src/Infrastructure/BotSharp.Core/BotSharpServiceCollectionExtensions.cs
index 66d8d4a3..c746438e 100644
--- a/src/Infrastructure/BotSharp.Core/BotSharpServiceCollectionExtensions.cs
+++ b/src/Infrastructure/BotSharp.Core/BotSharpServiceCollectionExtensions.cs
@@ -33,6 +33,8 @@ public static class BotSharpServiceCollectionExtensions
RegisterPlugins(services, config);
+ services.AddScoped();
+
return services;
}
diff --git a/src/Infrastructure/BotSharp.Core/Conversations/ConversationController.cs b/src/Infrastructure/BotSharp.Core/Conversations/ConversationController.cs
index a576c26c..e9dec02b 100644
--- a/src/Infrastructure/BotSharp.Core/Conversations/ConversationController.cs
+++ b/src/Infrastructure/BotSharp.Core/Conversations/ConversationController.cs
@@ -51,7 +51,7 @@ public class ConversationController : ControllerBase, IApiAdapter
await conv.SendMessage(agentId, conversationId,
new RoleDialogModel("user", input.Text),
async msg =>
- response.Text += msg.Content,
+ response.Text = msg.Content,
async fn
=> await Task.CompletedTask);
diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs
index 8cdfdb23..12b6fed7 100644
--- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs
+++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs
@@ -1,3 +1,6 @@
+using Amazon.SecurityToken.Model.Internal.MarshallTransformations;
+using BotSharp.Abstraction.Agents.Enums;
+using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Conversations.Models;
using BotSharp.Abstraction.Functions;
using BotSharp.Abstraction.MLTasks;
@@ -12,7 +15,7 @@ public class ConversationService : IConversationService
private readonly ConversationSetting _settings;
private readonly IConversationStorage _storage;
- public ConversationService(IServiceProvider services,
+ public ConversationService(IServiceProvider services,
IUserIdentity user,
ConversationSetting settings,
IConversationStorage storage,
@@ -69,11 +72,12 @@ public class ConversationService : IConversationService
return record.ToConversation();
}
- public async Task SendMessage(string agentId, string conversationId,
- RoleDialogModel lastDalog,
- Func onMessageReceived,
+ public async Task SendMessage(string agentId, string conversationId,
+ RoleDialogModel lastDalog,
+ Func onMessageReceived,
Func onFunctionExecuting)
{
+ lastDalog.CurrentAgentId = agentId;
_storage.Append(conversationId, lastDalog);
var wholeDialogs = GetDialogHistory(conversationId);
@@ -95,11 +99,9 @@ public class ConversationService : IConversationService
var stateService = _services.GetRequiredService();
stateService.SetConversation(conversationId);
stateService.Load();
- stateService.SetState("agentId", agentId);
- // load agent
- var agentService = _services.GetRequiredService();
- var agent = await agentService.LoadAgent(agentId);
+ var router = _services.GetRequiredService();
+ var agent = await router.LoadCurrentAgent();
// Get relevant domain knowledge
/*if (_settings.EnableKnowledgeBase)
@@ -127,39 +129,100 @@ public class ConversationService : IConversationService
var chatCompletion = GetChatCompletion();
var result = await chatCompletion.GetChatCompletionsAsync(agent, wholeDialogs, async msg =>
{
- if (msg.Role == "function")
+ await HandleMessage(conversationId, agent, msg, onMessageReceived, onFunctionExecuting);
+
+ if (msg.NeedReloadAgent)
{
- // Save states
- SaveStateByArgs(msg.Content);
-
- // Call functions
- await onFunctionExecuting(msg);
- await CallFunctions(conversationId, msg);
- }
- else
- {
- // Add to dialog history
- _storage.Append(conversationId, new RoleDialogModel(msg.Role, msg.Content));
-
- // After chat completion hook
- foreach (var hook in hooks)
- {
- await hook.AfterCompletion(msg);
- }
-
- await onMessageReceived(msg);
- }
-
- // Clean conversation
- if (msg.IsConversationEnd)
- {
- stateService.CleanState();
+ await HandleMessageIfAgentReloaded(conversationId, agent, msg, wholeDialogs, onMessageReceived, onFunctionExecuting);
}
});
return result;
}
+ private async Task HandleMessage(string conversationId, Agent agent, RoleDialogModel msg,
+ Func onMessageReceived,
+ Func onFunctionExecuting)
+ {
+ if (msg.Role == "function")
+ {
+ // Save states
+ SaveStateByArgs(msg.FunctionArgs);
+
+ // Call functions
+ await onFunctionExecuting(msg);
+ await CallFunctions(msg);
+
+ // Add to dialog history
+ if (msg.ExecutionResult != null)
+ {
+ if (msg.NeedReloadAgent)
+ {
+ _logger.LogInformation($"Skipped append dialog log: {msg.FunctionName}\n{msg.FunctionArgs}\n{msg.ExecutionResult}");
+ return;
+ }
+
+ _storage.Append(conversationId, new RoleDialogModel(msg.Role, msg.Content)
+ {
+ CurrentAgentId = agent.Id,
+ FunctionName = msg.FunctionName,
+ FunctionArgs = msg.FunctionArgs,
+ ExecutionResult = msg.ExecutionResult
+ });
+ }
+ }
+ else
+ {
+ // Add to dialog history
+ _storage.Append(conversationId, new RoleDialogModel(msg.Role, msg.Content)
+ {
+ CurrentAgentId = agent.Id
+ });
+
+ var hooks = _services.GetServices().ToList();
+ // After chat completion hook
+ foreach (var hook in hooks)
+ {
+ await hook.AfterCompletion(msg);
+ }
+
+ await onMessageReceived(msg);
+ }
+ }
+
+ private async Task HandleMessageIfAgentReloaded(string conversationId, Agent agent,
+ RoleDialogModel msg,
+ List wholeDialogs,
+ Func onMessageReceived,
+ Func onFunctionExecuting)
+ {
+ var state = _services.GetRequiredService();
+ var currentAgentId = state.GetState("agentId");
+
+ // Send to LLM to get final response when agent is switched.
+ var conv = _services.GetRequiredService();
+ var chatCompletion = conv.GetChatCompletion();
+ var agentService = _services.GetRequiredService();
+ var newAgent = await agentService.LoadAgent(currentAgentId);
+ await chatCompletion.GetChatCompletionsAsync(newAgent, wholeDialogs, async newMsg =>
+ {
+ if (newMsg.Role == AgentRole.Function)
+ {
+ await HandleMessage(conversationId, agent, newMsg, onMessageReceived, onFunctionExecuting);
+ }
+ else
+ {
+ msg.StopPropagate = true;
+ await onMessageReceived(newMsg);
+
+ _storage.Append(conversationId, new RoleDialogModel(newMsg.Role, newMsg.Content)
+ {
+ CurrentAgentId = agent.Id
+ });
+ }
+ });
+ }
+
private void SaveStateByArgs(string args)
{
var stateService = _services.GetRequiredService();
@@ -173,7 +236,7 @@ public class ConversationService : IConversationService
}
}
- private async Task CallFunctions(string conversationId, RoleDialogModel msg)
+ private async Task CallFunctions(RoleDialogModel msg)
{
var hooks = _services.GetServices().ToList();
@@ -182,6 +245,12 @@ public class ConversationService : IConversationService
.Where(x => x.Name == msg.FunctionName)
.ToList();
+ if (functions.Count == 0)
+ {
+ _logger.LogError($"Can't find function implementation of {msg.FunctionName}.");
+ return;
+ }
+
foreach (var fn in functions)
{
// Before executing functions
@@ -193,12 +262,6 @@ public class ConversationService : IConversationService
// Execute function
await fn.Execute(msg);
- // Add to dialog history
- _storage.Append(conversationId, new RoleDialogModel(msg.Role, msg.ExecutionResult)
- {
- FunctionName = msg.FunctionName,
- });
-
// After functions have been executed
foreach (var hook in hooks)
{
diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs
index ca98268c..0d2d249e 100644
--- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs
+++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs
@@ -1,3 +1,4 @@
+using BotSharp.Abstraction.Agents.Enums;
using BotSharp.Abstraction.Conversations.Models;
using System.IO;
@@ -15,15 +16,40 @@ public class ConversationStorage : IConversationStorage
{
var conversationFile = GetStorageFile(conversationId);
var sb = new StringBuilder();
- sb.AppendLine($"{dialog.Role}|{dialog.CreatedAt}|{dialog.FunctionName}");
- var content = dialog.Content.Trim().Replace("\r", " ").Replace("\n", " ");
- if (string.IsNullOrEmpty(content))
+ if (dialog.Role == AgentRole.Function)
{
- return;
- }
+ var args = dialog.FunctionArgs.Replace("\r", " ").Replace("\n", " ").Trim();
- sb.AppendLine($" - {content}");
+ sb.AppendLine($"{dialog.CreatedAt}|{dialog.Role}|{dialog.CurrentAgentId}|{dialog.FunctionName}|{args}");
+
+ var content = dialog.ExecutionResult.Replace("\r", " ").Replace("\n", " ").Trim();
+ if (string.IsNullOrEmpty(content))
+ {
+ return;
+ }
+ sb.AppendLine($" - {content}");
+ }
+ else if (dialog.Role == AgentRole.Assistant)
+ {
+ sb.AppendLine($"{dialog.CreatedAt}|{dialog.Role}|||");
+ var content = dialog.Content.Replace("\r", " ").Replace("\n", " ").Trim();
+ if (string.IsNullOrEmpty(content))
+ {
+ return;
+ }
+ sb.AppendLine($" - {content}");
+ }
+ else
+ {
+ sb.AppendLine($"{dialog.CreatedAt}|{dialog.Role}|{dialog.CurrentAgentId}||");
+ var content = dialog.Content.Replace("\r", " ").Replace("\n", " ").Trim();
+ if (string.IsNullOrEmpty(content))
+ {
+ return;
+ }
+ sb.AppendLine($" - {content}");
+ }
var conversation = sb.ToString();
File.AppendAllText(conversationFile, conversation);
@@ -39,13 +65,18 @@ public class ConversationStorage : IConversationStorage
{
var meta = dialogs[i];
var dialog = dialogs[i + 1];
- var role = meta.Split('|')[0];
- var createdAt = DateTime.Parse(meta.Split('|')[1]);
+ var createdAt = DateTime.Parse(meta.Split('|')[0]);
+ var role = meta.Split('|')[1];
+ var currentAgentId = meta.Split('|')[2];
+ var funcName = meta.Split('|')[3];
+ var funcArgs= meta.Split('|')[4];
var text = dialog.Substring(4);
- var funcName = meta.Split('|')[2];
+
results.Add(new RoleDialogModel(role, text)
{
+ CurrentAgentId = currentAgentId,
FunctionName = funcName,
+ FunctionArgs = funcArgs,
CreatedAt = createdAt
});
}
diff --git a/src/Infrastructure/BotSharp.Core/Plugins/LLamaSharp/ChatCompletionProvider.cs b/src/Infrastructure/BotSharp.Core/Plugins/LLamaSharp/ChatCompletionProvider.cs
index 02516b9a..20d67820 100644
--- a/src/Infrastructure/BotSharp.Core/Plugins/LLamaSharp/ChatCompletionProvider.cs
+++ b/src/Infrastructure/BotSharp.Core/Plugins/LLamaSharp/ChatCompletionProvider.cs
@@ -14,7 +14,7 @@ public class ChatCompletionProvider : IChatCompletion
_services = services;
}
- public string GetChatCompletions(Agent agent, List conversations)
+ public string GetChatCompletions(Agent agent, List conversations, Func onMessageReceived)
{
throw new NotImplementedException();
}
diff --git a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs
index e3e146f4..f71475e3 100644
--- a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs
+++ b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs
@@ -25,27 +25,41 @@ public class ChatCompletionProvider : IChatCompletion
_logger = logger;
}
- public string GetChatCompletions(Agent agent, List conversations)
+ private OpenAIClient GetClient()
{
var client = new OpenAIClient(new Uri(_settings.Endpoint), new AzureKeyCredential(_settings.ApiKey));
+ return client;
+ }
+
+ /*public string GetChatCompletions(Agent agent, List conversations, Func onMessageReceived)
+ {
+ var client = GetClient();
var chatCompletionsOptions = PrepareOptions(agent, conversations);
var response = client.GetChatCompletions(_settings.DeploymentModel.ChatCompletionModel, chatCompletionsOptions);
+ var choice = response.Value.Choices[0];
+ var message = choice.Message;
- string output = "";
- foreach (var choice in response.Value.Choices)
+ if (choice.FinishReason == CompletionsFinishReason.FunctionCall)
{
- var message = choice.Message;
- if (message.Content == null)
- continue;
- Console.Write(message.Content);
- output += message.Content;
+ response = HandleFunctionCall(message,
+ onMessageReceived,
+ chatCompletionsOptions).Result;
}
- _logger.LogInformation(output);
+ choice = response.Value.Choices[0];
+ message = choice.Message;
- return output.Trim();
- }
+ _logger.LogInformation(message.Content);
+
+ if (!string.IsNullOrEmpty(message.Content))
+ {
+ onMessageReceived(new RoleDialogModel(ChatRole.Assistant.ToString(), message.Content))
+ .Wait();
+ }
+
+ return message.Content.Trim();
+ }*/
public List GetChatSamples(string sampleText)
{
@@ -95,7 +109,7 @@ public class ChatCompletionProvider : IChatCompletion
public async Task GetChatCompletionsAsync(Agent agent, List conversations, Func onMessageReceived)
{
- var client = new OpenAIClient(new Uri(_settings.Endpoint), new AzureKeyCredential(_settings.ApiKey));
+ var client = GetClient();
var chatCompletionsOptions = PrepareOptions(agent, conversations);
var response = await client.GetChatCompletionsAsync(_settings.DeploymentModel.ChatCompletionModel, chatCompletionsOptions);
@@ -104,51 +118,24 @@ public class ChatCompletionProvider : IChatCompletion
if (choice.FinishReason == CompletionsFinishReason.FunctionCall)
{
- if (message.FunctionCall == null || message.FunctionCall.Arguments == null)
- {
- return false;
- }
- _logger.LogInformation($"{message.FunctionCall.Name}: {message.FunctionCall.Arguments}");
- var funcContextIn = new RoleDialogModel(ChatRole.Function.ToString(), message.FunctionCall.Arguments)
- {
- FunctionName = message.FunctionCall.Name
- };
-
- // Execute functions
- await onMessageReceived(funcContextIn);
-
- if (funcContextIn.StopSubsequentInteraction)
- {
- // Emit a fake message that should be populated by whom set StopSubsequentInteraction as True.
- await onMessageReceived(new RoleDialogModel(ChatRole.Assistant.ToString(), ""));
- return true;
- }
-
- if (funcContextIn.IsConversationEnd)
- {
- await onMessageReceived(new RoleDialogModel(ChatRole.Assistant.ToString(), funcContextIn.Content)
- {
- IsConversationEnd = true
- });
- return true;
- }
-
- // After function is executed, pass the result to LLM
- chatCompletionsOptions.Messages.Add(new ChatMessage(ChatRole.Function, funcContextIn.ExecutionResult)
- {
- Name = funcContextIn.FunctionName
- });
- response = client.GetChatCompletions(_settings.DeploymentModel.ChatCompletionModel, chatCompletionsOptions);
+ response = await HandleFunctionCall(agent,
+ message,
+ onMessageReceived,
+ chatCompletionsOptions);
}
- choice = response.Value.Choices[0];
- message = choice.Message;
-
- _logger.LogInformation(message.Content);
-
- if (!string.IsNullOrEmpty(message.Content))
+ if (response != null)
{
- await onMessageReceived(new RoleDialogModel(ChatRole.Assistant.ToString(), message.Content));
+ choice = response.Value.Choices[0];
+ message = choice.Message;
+
+ _logger.LogInformation(message.Content);
+
+ if (!string.IsNullOrEmpty(message.Content))
+ {
+ var msgByLlm = new RoleDialogModel(ChatRole.Assistant.ToString(), message.Content);
+ await onMessageReceived(msgByLlm);
+ }
}
return true;
@@ -198,10 +185,61 @@ public class ChatCompletionProvider : IChatCompletion
return true;
}
+ private async Task> HandleFunctionCall(Agent agent,
+ ChatMessage message,
+ Func onMessageReceived,
+ ChatCompletionsOptions chatCompletionsOptions)
+ {
+ Response response = default;
+
+ if (message.FunctionCall == null || message.FunctionCall.Arguments == null)
+ {
+ return response;
+ }
+
+ _logger.LogInformation($"{message.FunctionCall.Name}: {message.FunctionCall.Arguments}");
+ var funcContextIn = new RoleDialogModel(ChatRole.Function.ToString(), message.Content)
+ {
+ CurrentAgentId = agent.Id,
+ FunctionName = message.FunctionCall.Name,
+ FunctionArgs = message.FunctionCall.Arguments
+ };
+
+ // Execute functions
+ await onMessageReceived(funcContextIn);
+
+ if (funcContextIn.StopPropagate)
+ {
+ return response;
+ }
+
+ if (funcContextIn.IsConversationEnd)
+ {
+ await onMessageReceived(new RoleDialogModel(ChatRole.Assistant.ToString(), funcContextIn.Content)
+ {
+ IsConversationEnd = true
+ });
+ return response;
+ }
+
+ // After function is executed, pass the result to LLM
+ if (funcContextIn.ExecutionResult != null)
+ {
+ chatCompletionsOptions.Messages.Add(new ChatMessage(ChatRole.Function, funcContextIn.ExecutionResult)
+ {
+ Name = funcContextIn.FunctionName
+ });
+ var client = GetClient();
+ response = client.GetChatCompletions(_settings.DeploymentModel.ChatCompletionModel, chatCompletionsOptions);
+ }
+
+ return response;
+ }
+
private ChatCompletionsOptions PrepareOptions(Agent agent, List conversations)
{
var chatCompletionsOptions = new ChatCompletionsOptions();
-
+
if (!string.IsNullOrEmpty(agent.Instruction))
{
chatCompletionsOptions.Messages.Add(new ChatMessage(ChatRole.System, agent.Instruction));
@@ -244,6 +282,10 @@ public class ChatCompletionProvider : IChatCompletion
}
}
+ // https://community.openai.com/t/cheat-sheet-mastering-temperature-and-top-p-in-chatgpt-api-a-few-tips-and-tricks-on-controlling-the-creativity-deterministic-output-of-prompt-responses/172683
+ chatCompletionsOptions.Temperature = 0.5f;
+ chatCompletionsOptions.NucleusSamplingFactor = 0.5f;
+
_logger.LogInformation(string.Join("\n", chatCompletionsOptions.Messages.Select(x => $"{x.Role}: {x.Content}")));
return chatCompletionsOptions;
}