Redefine IFunctionCallback.Execute.
This commit is contained in:
parent
362ce4a236
commit
f6dec6e6e2
|
|
@ -1,4 +1,5 @@
|
|||
using BotSharp.Abstraction.Conversations.Models;
|
||||
using BotSharp.Abstraction.MLTasks;
|
||||
|
||||
namespace BotSharp.Abstraction.Conversations;
|
||||
|
||||
|
|
@ -8,8 +9,39 @@ public interface IConversationService
|
|||
Task<Conversation> GetConversation(string id);
|
||||
Task<List<Conversation>> GetConversations();
|
||||
Task DeleteConversation(string id);
|
||||
Task<bool> SendMessage(string agentId, string conversationId, RoleDialogModel lastDalog, Func<RoleDialogModel, Task> onMessageReceived, Func<RoleDialogModel, Task> onFunctionExecuting);
|
||||
Task<bool> SendMessage(string agentId, string conversationId, List<RoleDialogModel> wholeDialogs, Func<RoleDialogModel, Task> onMessageReceived);
|
||||
|
||||
IChatCompletion GetChatCompletion();
|
||||
|
||||
/// <summary>
|
||||
/// Send message to LLM
|
||||
/// </summary>
|
||||
/// <param name="agentId"></param>
|
||||
/// <param name="conversationId"></param>
|
||||
/// <param name="lastDalog"></param>
|
||||
/// <param name="onMessageReceived"></param>
|
||||
/// <param name="onFunctionExecuting">This delegate is useful when you want to report progress on UI</param>
|
||||
/// <returns></returns>
|
||||
Task<bool> SendMessage(string agentId,
|
||||
string conversationId,
|
||||
RoleDialogModel lastDalog,
|
||||
Func<RoleDialogModel, Task> onMessageReceived,
|
||||
Func<RoleDialogModel, Task> onFunctionExecuting);
|
||||
|
||||
/// <summary>
|
||||
/// Send message to LLM if frontend passed over the dialog history
|
||||
/// </summary>
|
||||
/// <param name="agentId"></param>
|
||||
/// <param name="conversationId"></param>
|
||||
/// <param name="wholeDialogs"></param>
|
||||
/// <param name="onMessageReceived"></param>
|
||||
/// <param name="onFunctionExecuting">This delegate is useful when you want to report progress on UI</param>
|
||||
/// <returns></returns>
|
||||
Task<bool> SendMessage(string agentId,
|
||||
string conversationId,
|
||||
List<RoleDialogModel> wholeDialogs,
|
||||
Func<RoleDialogModel, Task> onMessageReceived,
|
||||
Func<RoleDialogModel, Task> onFunctionExecuting);
|
||||
|
||||
List<RoleDialogModel> GetDialogHistory(string conversationId, int lastCount = 20);
|
||||
Task CleanHistory(string agentId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
using BotSharp.Abstraction.Conversations.Models;
|
||||
|
||||
namespace BotSharp.Abstraction.Functions;
|
||||
|
||||
public interface IFunctionCallback
|
||||
{
|
||||
string Name { get; }
|
||||
Task<string> Execute(string args);
|
||||
Task<bool> Execute(RoleDialogModel message);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,13 +48,12 @@ public class ConversationController : ControllerBase, IApiAdapter
|
|||
|
||||
var response = new MessageResponseModel();
|
||||
|
||||
await conv.SendMessage(agentId, conversationId, new RoleDialogModel("user", input.Text), async msg =>
|
||||
{
|
||||
response.Text += msg.Content;
|
||||
}, async fn =>
|
||||
{
|
||||
|
||||
});
|
||||
await conv.SendMessage(agentId, conversationId,
|
||||
new RoleDialogModel("user", input.Text),
|
||||
async msg =>
|
||||
response.Text += msg.Content,
|
||||
async fn
|
||||
=> await Task.CompletedTask);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,7 @@
|
|||
using BotSharp.Abstraction.Agents.Enums;
|
||||
using BotSharp.Abstraction.Conversations;
|
||||
using BotSharp.Abstraction.Conversations.Models;
|
||||
using BotSharp.Abstraction.Functions;
|
||||
using BotSharp.Abstraction.Knowledges.Models;
|
||||
using BotSharp.Abstraction.MLTasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace BotSharp.Core.Conversations.Services;
|
||||
|
||||
|
|
@ -74,7 +70,8 @@ public class ConversationService : IConversationService
|
|||
return record.ToConversation();
|
||||
}
|
||||
|
||||
public async Task<bool> SendMessage(string agentId, string conversationId, RoleDialogModel lastDalog,
|
||||
public async Task<bool> SendMessage(string agentId, string conversationId,
|
||||
RoleDialogModel lastDalog,
|
||||
Func<RoleDialogModel, Task> onMessageReceived,
|
||||
Func<RoleDialogModel, Task> onFunctionExecuting)
|
||||
{
|
||||
|
|
@ -82,41 +79,17 @@ public class ConversationService : IConversationService
|
|||
|
||||
var wholeDialogs = GetDialogHistory(conversationId);
|
||||
|
||||
var response = await SendMessage(agentId, conversationId, wholeDialogs, async msg =>
|
||||
{
|
||||
if (msg.Role == "function")
|
||||
{
|
||||
// Invoke functions
|
||||
var functions = _services.GetServices<IFunctionCallback>().Where(x => x.Name == msg.FunctionName);
|
||||
foreach (var fn in functions)
|
||||
{
|
||||
await onFunctionExecuting(msg);
|
||||
|
||||
msg.ExecutionResult = await fn.Execute(msg.Content);
|
||||
|
||||
var result = msg.ExecutionResult.Replace("\r", " ").Replace("\n", " ");
|
||||
var content = $"{result}";
|
||||
// Console.WriteLine($"{msg.Role}: {content}");
|
||||
_storage.Append(conversationId, new RoleDialogModel(msg.Role, content)
|
||||
{
|
||||
FunctionName = msg.FunctionName,
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var content = msg.Content.Replace("\r", " ").Replace("\n", " ");
|
||||
// Console.WriteLine($"{msg.Role}: {content}");
|
||||
_storage.Append(conversationId, new RoleDialogModel(msg.Role, content));
|
||||
|
||||
await onMessageReceived(msg);
|
||||
}
|
||||
});
|
||||
var response = await SendMessage(agentId, conversationId, wholeDialogs,
|
||||
onMessageReceived: onMessageReceived,
|
||||
onFunctionExecuting: onFunctionExecuting);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public async Task<bool> SendMessage(string agentId, string conversationId, List<RoleDialogModel> wholeDialogs, Func<RoleDialogModel, Task> onMessageReceived)
|
||||
public async Task<bool> SendMessage(string agentId, string conversationId,
|
||||
List<RoleDialogModel> wholeDialogs,
|
||||
Func<RoleDialogModel, Task> onMessageReceived,
|
||||
Func<RoleDialogModel, Task> onFunctionExecuting)
|
||||
{
|
||||
var converation = await GetConversation(conversationId);
|
||||
|
||||
|
|
@ -152,8 +125,6 @@ public class ConversationService : IConversationService
|
|||
});
|
||||
}*/
|
||||
|
||||
var chatCompletion = GetChatCompletion();
|
||||
|
||||
var hooks = _services.GetServices<IConversationHook>().ToList();
|
||||
|
||||
// Before chat completion hook
|
||||
|
|
@ -166,48 +137,83 @@ public class ConversationService : IConversationService
|
|||
await hook.BeforeCompletion();
|
||||
}
|
||||
|
||||
var chatCompletion = GetChatCompletion();
|
||||
var result = await chatCompletion.GetChatCompletionsAsync(agent, wholeDialogs, async msg =>
|
||||
{
|
||||
if (msg.Role == "function")
|
||||
{
|
||||
// Before executing functions
|
||||
foreach (var hook in hooks)
|
||||
{
|
||||
await hook.OnFunctionExecuting(msg);
|
||||
}
|
||||
// Save states
|
||||
var jo = JsonSerializer.Deserialize<object>(msg.Content);
|
||||
if (jo is JsonElement root)
|
||||
{
|
||||
foreach (JsonProperty property in root.EnumerateObject())
|
||||
{
|
||||
stateService.SetState(property.Name, property.Value.ToString());
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
||||
if (msg.Role == AgentRole.Function)
|
||||
{
|
||||
// After functions have been executed
|
||||
foreach (var hook in hooks)
|
||||
{
|
||||
await hook.OnFunctionExecuted(msg);
|
||||
}
|
||||
await onMessageReceived(msg);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void SaveStateByArgs(string args)
|
||||
{
|
||||
var stateService = _services.GetRequiredService<IConversationStateService>();
|
||||
var jo = JsonSerializer.Deserialize<object>(args);
|
||||
if (jo is JsonElement root)
|
||||
{
|
||||
foreach (JsonProperty property in root.EnumerateObject())
|
||||
{
|
||||
stateService.SetState(property.Name, property.Value.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CallFunctions(string conversationId, RoleDialogModel msg)
|
||||
{
|
||||
var hooks = _services.GetServices<IConversationHook>().ToList();
|
||||
|
||||
// Invoke functions
|
||||
var functions = _services.GetServices<IFunctionCallback>()
|
||||
.Where(x => x.Name == msg.FunctionName)
|
||||
.ToList();
|
||||
|
||||
foreach (var fn in functions)
|
||||
{
|
||||
// Before executing functions
|
||||
foreach (var hook in hooks)
|
||||
{
|
||||
await hook.OnFunctionExecuting(msg);
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
await hook.OnFunctionExecuted(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IChatCompletion GetChatCompletion()
|
||||
{
|
||||
var completions = _services.GetServices<IChatCompletion>();
|
||||
|
|
@ -222,6 +228,8 @@ public class ConversationService : IConversationService
|
|||
public List<RoleDialogModel> GetDialogHistory(string conversationId, int lastCount = 20)
|
||||
{
|
||||
var dialogs = _storage.GetDialogs(conversationId);
|
||||
return dialogs.TakeLast(lastCount).ToList();
|
||||
return dialogs
|
||||
.Where(x => x.CreatedAt > DateTime.UtcNow.AddHours(-8))
|
||||
.TakeLast(lastCount).ToList();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ public class ConversationStateService : IConversationStateService, IDisposable
|
|||
{
|
||||
var currentValue = value;
|
||||
_state[name] = currentValue;
|
||||
_logger.LogInformation($"Set state: {name} - {value}");
|
||||
_logger.LogInformation($"Set state: {name} = {value}");
|
||||
foreach (var hook in hooks)
|
||||
{
|
||||
hook.OnStateChanged(name, preValue, currentValue).Wait();
|
||||
|
|
|
|||
|
|
@ -5,11 +5,9 @@ namespace BotSharp.Core.Conversations.Services;
|
|||
|
||||
public class ConversationStorage : IConversationStorage
|
||||
{
|
||||
private readonly IAgentService _agent;
|
||||
private readonly MyDatabaseSettings _dbSettings;
|
||||
public ConversationStorage(IAgentService agent, MyDatabaseSettings dbSettings)
|
||||
public ConversationStorage(MyDatabaseSettings dbSettings)
|
||||
{
|
||||
_agent = agent;
|
||||
_dbSettings = dbSettings;
|
||||
}
|
||||
|
||||
|
|
@ -18,7 +16,15 @@ public class ConversationStorage : IConversationStorage
|
|||
var conversationFile = GetStorageFile(conversationId);
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine($"{dialog.Role}|{dialog.CreatedAt}|{dialog.FunctionName}");
|
||||
sb.AppendLine($" - {dialog.Content}");
|
||||
|
||||
var content = dialog.Content.Trim().Replace("\r", " ").Replace("\n", " ");
|
||||
if (string.IsNullOrEmpty(content))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
sb.AppendLine($" - {content}");
|
||||
|
||||
var conversation = sb.ToString();
|
||||
File.AppendAllText(conversationFile, conversation);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,11 @@ global using System.Collections.Generic;
|
|||
global using System.Text;
|
||||
global using System.Threading.Tasks;
|
||||
global using System.Linq;
|
||||
global using System.Text.Json;
|
||||
global using Microsoft.Extensions.DependencyInjection;
|
||||
global using BotSharp.Abstraction.Plugins;
|
||||
global using Microsoft.Extensions.Logging;
|
||||
global using EntityFrameworkCore.BootKit;
|
||||
global using BotSharp.Abstraction.Plugins;
|
||||
global using BotSharp.Abstraction.Agents;
|
||||
global using BotSharp.Abstraction.Conversations;
|
||||
global using BotSharp.Abstraction.Knowledges;
|
||||
|
|
|
|||
|
|
@ -70,7 +70,9 @@ public class ChatbotUiController : ControllerBase, IApiAdapter
|
|||
input.ConversationId,
|
||||
conversations,
|
||||
async msg =>
|
||||
await OnChunkReceived(outputStream, msg));
|
||||
await OnChunkReceived(outputStream, msg),
|
||||
async fn
|
||||
=> await Task.CompletedTask);
|
||||
|
||||
await OnEventCompleted(outputStream);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue