Function execution status.

This commit is contained in:
hchen 2023-07-27 16:56:57 -05:00
parent 842880dbbf
commit 60ce930d4c
11 changed files with 143 additions and 12 deletions

View file

@ -46,6 +46,11 @@ public abstract class ConversationCompletionHookBase : IConversationCompletionHo
return Task.CompletedTask;
}
public virtual async Task<IFunctionExecutionResult> OnFunctionExecution(string name, string args)
{
return new FunctionExecutionValidationResult("true", "");
}
public virtual Task AfterCompletion(RoleDialogModel message)
{
return Task.CompletedTask;

View file

@ -18,5 +18,6 @@ public interface IConversationCompletionHook
IConversationCompletionHook SetChatCompletion(IChatCompletion chatCompletion);
Task BeforeCompletion();
Task<IFunctionExecutionResult> OnFunctionExecution(string name, string args);
Task AfterCompletion(RoleDialogModel message);
}

View file

@ -7,4 +7,9 @@ public class FunctionDef
public string Name { get; set; }
public string Description { get; set; }
public JsonDocument Parameters { get; set; }
public override string ToString()
{
return $"{Name}: {Description}";
}
}

View file

@ -0,0 +1,7 @@
namespace BotSharp.Abstraction.Conversations.Models;
public enum FunctionExecutionStatus
{
Success = 1,
Failure = 2
}

View file

@ -0,0 +1,21 @@
using System.Text.Json.Serialization;
namespace BotSharp.Abstraction.Conversations.Models;
public class FunctionExecutionValidationResult : IFunctionExecutionResult
{
private string _validationStatus;
public string _validationMessage;
public FunctionExecutionValidationResult(string validationStatus, string validationMessage = "")
{
_validationStatus = validationStatus;
_validationMessage = validationMessage;
}
[JsonPropertyName("validation_status")]
public string ValidationStatus => _validationStatus;
[JsonPropertyName("validation_message")]
public string ValidationMessage => _validationMessage;
}

View file

@ -0,0 +1,9 @@
using System.Text.Json.Serialization;
namespace BotSharp.Abstraction.Conversations.Models;
public class IFunctionExecutionResult
{
[JsonPropertyName("execution_status")]
public FunctionExecutionStatus ExecutionStatus { get; set; }
}

View file

@ -11,7 +11,12 @@ public class RoleDialogModel
/// <summary>
/// Function name if LLM response function call
/// </summary>
public string? Name { get; set; }
public string? Function { get; set; }
/// <summary>
/// Function execution result
/// </summary>
public string? ExecutionResult { get; set; }
public RoleDialogModel(string role, string text)
{

View file

@ -5,5 +5,6 @@ namespace BotSharp.Abstraction.MLTasks;
public interface IChatCompletion
{
string GetChatCompletions(Agent agent, List<RoleDialogModel> conversations);
Task<bool> GetChatCompletionsAsync(Agent agent, List<RoleDialogModel> conversations, Func<RoleDialogModel, Task> onMessageReceived);
Task<bool> GetChatCompletionsStreamingAsync(Agent agent, List<RoleDialogModel> conversations, Func<RoleDialogModel, Task> onMessageReceived);
}

View file

@ -2,6 +2,7 @@ using BotSharp.Abstraction.Conversations.Models;
using BotSharp.Abstraction.Conversations.Settings;
using BotSharp.Abstraction.Knowledges.Models;
using BotSharp.Abstraction.MLTasks;
using System.Text.Json;
namespace BotSharp.Core.Conversations.Services;
@ -75,8 +76,17 @@ public class ConversationService : IConversationService
var response = await SendMessage(agentId, conversationId, wholeDialogs, async msg =>
{
await onMessageReceived(msg);
_storage.Append(agentId, conversationId, new RoleDialogModel(msg.Role, msg.Content));
var content = msg.Content.Replace("\r", " ").Replace("\n", " ");
if (msg.Role == "function")
{
content += $"[{msg.Function}] {content}";
_storage.Append(agentId, conversationId, new RoleDialogModel(msg.Role, content));
}
else
{
await onMessageReceived(msg);
_storage.Append(agentId, conversationId, new RoleDialogModel(msg.Role, content));
}
});
return response;
@ -100,23 +110,39 @@ public class ConversationService : IConversationService
var chatCompletion = GetChatCompletion();
// Before chat completion hook
var hooks = _services.GetServices<IConversationCompletionHook>().ToList();
hooks.ForEach(hook =>
// Before chat completion hook
foreach (var hook in hooks)
{
hook.SetAgent(agent)
await hook.SetAgent(agent)
.SetConversation(converation)
.SetDialogs(wholeDialogs)
.SetChatCompletion(chatCompletion)
.BeforeCompletion();
});
var result = await chatCompletion.GetChatCompletionsStreamingAsync(agent, wholeDialogs, async msg =>
}
var result = await chatCompletion.GetChatCompletionsAsync(agent, wholeDialogs, async msg =>
{
// After chat completion hook
hooks.ForEach(async hook => await hook.AfterCompletion(msg));
await onMessageReceived(msg);
if (msg.Role == "function")
{
// Execute functions
foreach (var hook in hooks)
{
var executionResult = await hook.OnFunctionExecution(msg.Function, msg.Content);
msg.ExecutionResult = JsonSerializer.Serialize(executionResult);
}
}
else
{
// After chat completion hook
foreach (var hook in hooks)
{
await hook.AfterCompletion(msg);
}
await onMessageReceived(msg);
}
});
return result;

View file

@ -19,6 +19,11 @@ public class ChatCompletionProvider : IChatCompletion
throw new NotImplementedException();
}
public Task<bool> GetChatCompletionsAsync(Agent agent, List<RoleDialogModel> conversations, Func<RoleDialogModel, Task> onMessageReceived)
{
throw new NotImplementedException();
}
public async Task<bool> GetChatCompletionsStreamingAsync(Agent agent, List<RoleDialogModel> conversations, Func<RoleDialogModel, Task> onMessageReceived)
{
string totalResponse = "";

View file

@ -86,6 +86,41 @@ public class ChatCompletionProvider : IChatCompletion
return functions;
}
public async Task<bool> GetChatCompletionsAsync(Agent agent, List<RoleDialogModel> conversations, Func<RoleDialogModel, Task> onMessageReceived)
{
var client = new OpenAIClient(new Uri(_settings.Endpoint), new AzureKeyCredential(_settings.ApiKey));
var chatCompletionsOptions = PrepareOptions(agent, conversations);
var response = await client.GetChatCompletionsAsync(_settings.DeploymentModel.ChatCompletionModel, chatCompletionsOptions);
var choice = response.Value.Choices[0];
var message = choice.Message;
if (choice.FinishReason == CompletionsFinishReason.FunctionCall)
{
if (message.FunctionCall == null || message.FunctionCall.Arguments == null)
{
return false;
}
Console.Write(message.FunctionCall.Name);
Console.Write(message.FunctionCall.Arguments);
var funcContextIn = new RoleDialogModel(ChatRole.Function.ToString(), message.FunctionCall.Arguments)
{
Function = message.FunctionCall.Name
};
await onMessageReceived(funcContextIn);
// After function is executed, pass the result to LLM
throw new NotImplementedException();
}
else
{
Console.Write(message.Content);
await onMessageReceived(new RoleDialogModel(ChatRole.Assistant.ToString(), message.Content));
}
return true;
}
public async Task<bool> GetChatCompletionsStreamingAsync(Agent agent, List<RoleDialogModel> conversations, Func<RoleDialogModel, Task> onMessageReceived)
{
var client = new OpenAIClient(new Uri(_settings.Endpoint), new AzureKeyCredential(_settings.ApiKey));
@ -99,6 +134,17 @@ public class ChatCompletionProvider : IChatCompletion
{
if (choice.FinishReason == CompletionsFinishReason.FunctionCall)
{
var args = "";
await foreach (var message in choice.GetMessageStreaming())
{
if (message.FunctionCall == null || message.FunctionCall.Arguments == null)
continue;
Console.Write(message.FunctionCall.Arguments);
args += message.FunctionCall.Arguments;
}
await onMessageReceived(new RoleDialogModel(ChatRole.Assistant.ToString(), args));
continue;
}
await foreach (var message in choice.GetMessageStreaming())