optimize conversation Progeess, hotfix invoke function progress question
This commit is contained in:
parent
793905436b
commit
3f8e506ec7
|
|
@ -0,0 +1,10 @@
|
|||
namespace BotSharp.Abstraction.Conversations;
|
||||
|
||||
public delegate Task FunctionExecuting(RoleDialogModel msg);
|
||||
public delegate Task FunctionExecuted(RoleDialogModel msg);
|
||||
|
||||
public interface IConversationProgressService
|
||||
{
|
||||
FunctionExecuted OnFunctionExecuted { get; set; }
|
||||
FunctionExecuting OnFunctionExecuting { get; set; }
|
||||
}
|
||||
|
|
@ -39,9 +39,7 @@ public interface IConversationService
|
|||
Task<bool> SendMessage(string agentId,
|
||||
RoleDialogModel lastDalog,
|
||||
PostbackMessageModel? replyMessage,
|
||||
Func<RoleDialogModel, Task> onResponseReceived,
|
||||
Func<RoleDialogModel, Task> onFunctionExecuting,
|
||||
Func<RoleDialogModel, Task> onFunctionExecuted);
|
||||
Func<RoleDialogModel, Task> onResponseReceived);
|
||||
|
||||
List<RoleDialogModel> GetDialogHistory(int lastCount = 100, bool fromBreakpoint = true);
|
||||
Task CleanHistory(string agentId);
|
||||
|
|
|
|||
|
|
@ -16,5 +16,5 @@ public interface IRoutingHandler
|
|||
|
||||
void SetDialogs(List<RoleDialogModel> dialogs);
|
||||
|
||||
Task<bool> Handle(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message, Func<RoleDialogModel, Task> onFunctionExecuting);
|
||||
Task<bool> Handle(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,9 +28,9 @@ public interface IRoutingService
|
|||
|
||||
List<RoutingHandlerDef> GetHandlers(Agent router);
|
||||
void ResetRecursiveCounter();
|
||||
Task<bool> InvokeAgent(string agentId, List<RoleDialogModel> dialogs, Func<RoleDialogModel, Task> onFunctionExecuting);
|
||||
Task<bool> InvokeFunction(string name, RoleDialogModel messages, Func<RoleDialogModel, Task>? onFunctionExecuting = null);
|
||||
Task<RoleDialogModel> InstructLoop(RoleDialogModel message, List<RoleDialogModel> dialogs, Func<RoleDialogModel, Task> onFunctionExecuting);
|
||||
Task<bool> InvokeAgent(string agentId, List<RoleDialogModel> dialogs);
|
||||
Task<bool> InvokeFunction(string name, RoleDialogModel messages);
|
||||
Task<RoleDialogModel> InstructLoop(RoleDialogModel message, List<RoleDialogModel> dialogs);
|
||||
|
||||
/// <summary>
|
||||
/// Talk to a specific Agent directly, bypassing the Router
|
||||
|
|
|
|||
|
|
@ -7,6 +7,5 @@ public interface IExecutor
|
|||
Task<RoleDialogModel> Execute(IRoutingService routing,
|
||||
FunctionCallFromLlm inst,
|
||||
RoleDialogModel message,
|
||||
List<RoleDialogModel> dialogs,
|
||||
Func<RoleDialogModel, Task> onFunctionExecuting);
|
||||
List<RoleDialogModel> dialogs);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ public class ConversationPlugin : IBotSharpPlugin
|
|||
|
||||
services.AddScoped<IConversationStorage, ConversationStorage>();
|
||||
services.AddScoped<IConversationService, ConversationService>();
|
||||
services.AddScoped<IConversationProgressService, ConversationProgressService>();
|
||||
services.AddScoped<IConversationStateService, ConversationStateService>();
|
||||
services.AddScoped<ITranslationService, TranslationService>();
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
namespace BotSharp.Core.Conversations.Services
|
||||
{
|
||||
public class ConversationProgressService : IConversationProgressService
|
||||
{
|
||||
|
||||
public FunctionExecuting OnFunctionExecuting { get; set; }
|
||||
|
||||
|
||||
public FunctionExecuted OnFunctionExecuted { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -10,9 +10,7 @@ public partial class ConversationService
|
|||
public async Task<bool> SendMessage(string agentId,
|
||||
RoleDialogModel message,
|
||||
PostbackMessageModel? replyMessage,
|
||||
Func<RoleDialogModel, Task> onMessageReceived,
|
||||
Func<RoleDialogModel, Task> onFunctionExecuting,
|
||||
Func<RoleDialogModel, Task> onFunctionExecuted)
|
||||
Func<RoleDialogModel, Task> onMessageReceived)
|
||||
{
|
||||
var conversation = await GetConversationRecordOrCreateNew(agentId);
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
|
|
@ -78,7 +76,7 @@ public partial class ConversationService
|
|||
|
||||
if (agent.Type == AgentType.Routing)
|
||||
{
|
||||
response = await routing.InstructLoop(message, dialogs, onFunctionExecuting);
|
||||
response = await routing.InstructLoop(message, dialogs);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -103,9 +103,7 @@ public class EvaluatingService : IEvaluatingService
|
|||
await conv.SendMessage(agentId,
|
||||
inputMsg,
|
||||
replyMessage: null,
|
||||
async msg => response = msg,
|
||||
_ => Task.CompletedTask,
|
||||
_ => Task.CompletedTask);
|
||||
async msg => response = msg);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ public class FallbackToRouterFn : IFunctionCallback
|
|||
routing.Context.Replace(targetAgent.Id);
|
||||
message.CurrentAgentId = targetAgent.Id;
|
||||
|
||||
var response = await routing.InstructLoop(message, dialogs, null);
|
||||
var response = await routing.InstructLoop(message, dialogs);
|
||||
|
||||
message.Content = response.Content;
|
||||
message.StopCompletion = true;
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ public class RetrieveDataFromAgentRoutingHandler : RoutingHandlerBase//, IRoutin
|
|||
{
|
||||
}
|
||||
|
||||
public async Task<bool> Handle(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message, Func<RoleDialogModel, Task> onFunctionExecuting)
|
||||
public async Task<bool> Handle(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message)
|
||||
{
|
||||
var context = _services.GetRequiredService<IRoutingContext>();
|
||||
var agentId = context.GetCurrentAgentId();
|
||||
|
|
@ -47,7 +47,7 @@ public class RetrieveDataFromAgentRoutingHandler : RoutingHandlerBase//, IRoutin
|
|||
}
|
||||
};
|
||||
|
||||
var ret = await routing.InvokeAgent(agentId, dialogs, onFunctionExecuting);
|
||||
var ret = await routing.InvokeAgent(agentId, dialogs);
|
||||
var response = dialogs.Last();
|
||||
inst.Response = response.Content;
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ public class RouteToAgentRoutingHandler : RoutingHandlerBase, IRoutingHandler
|
|||
{
|
||||
}
|
||||
|
||||
public async Task<bool> Handle(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message, Func<RoleDialogModel, Task> onFunctionExecuting)
|
||||
public async Task<bool> Handle(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message)
|
||||
{
|
||||
var states = _services.GetRequiredService<IConversationStateService>();
|
||||
var goalAgent = states.GetState(StateConst.EXPECTED_GOAL_AGENT);
|
||||
|
|
@ -88,7 +88,7 @@ public class RouteToAgentRoutingHandler : RoutingHandlerBase, IRoutingHandler
|
|||
}
|
||||
else
|
||||
{
|
||||
var ret = await routing.InvokeAgent(agentId, _dialogs, onFunctionExecuting);
|
||||
var ret = await routing.InvokeAgent(agentId, _dialogs);
|
||||
}
|
||||
|
||||
var response = _dialogs.Last();
|
||||
|
|
|
|||
|
|
@ -16,8 +16,7 @@ public class InstructExecutor : IExecutor
|
|||
public async Task<RoleDialogModel> Execute(IRoutingService routing,
|
||||
FunctionCallFromLlm inst,
|
||||
RoleDialogModel message,
|
||||
List<RoleDialogModel> dialogs,
|
||||
Func<RoleDialogModel, Task> onFunctionExecuting)
|
||||
List<RoleDialogModel> dialogs)
|
||||
{
|
||||
message.Instruction = inst;
|
||||
|
||||
|
|
@ -25,7 +24,7 @@ public class InstructExecutor : IExecutor
|
|||
var handler = handlers.FirstOrDefault(x => x.Name == inst.Function);
|
||||
handler.SetDialogs(dialogs);
|
||||
|
||||
var handled = await handler.Handle(routing, inst, message, onFunctionExecuting);
|
||||
var handled = await handler.Handle(routing, inst, message);
|
||||
|
||||
// For client display purpose
|
||||
var response = dialogs.Last();
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ namespace BotSharp.Core.Routing;
|
|||
public partial class RoutingService
|
||||
{
|
||||
private int _currentRecursionDepth = 0;
|
||||
public async Task<bool> InvokeAgent(string agentId, List<RoleDialogModel> dialogs, Func<RoleDialogModel, Task> onFunctionExecuting)
|
||||
public async Task<bool> InvokeAgent(string agentId, List<RoleDialogModel> dialogs)
|
||||
{
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
var agent = await agentService.LoadAgent(agentId);
|
||||
|
|
@ -47,7 +47,7 @@ public partial class RoutingService
|
|||
message.FunctionArgs = response.FunctionArgs;
|
||||
message.CurrentAgentId = agent.Id;
|
||||
|
||||
await InvokeFunction(message, dialogs, onFunctionExecuting);
|
||||
await InvokeFunction(message, dialogs);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -67,7 +67,7 @@ public partial class RoutingService
|
|||
return true;
|
||||
}
|
||||
|
||||
private async Task<bool> InvokeFunction(RoleDialogModel message, List<RoleDialogModel> dialogs, Func<RoleDialogModel, Task>? onFunctionExecuting = null)
|
||||
private async Task<bool> InvokeFunction(RoleDialogModel message, List<RoleDialogModel> dialogs)
|
||||
{
|
||||
// execute function
|
||||
// Save states
|
||||
|
|
@ -76,7 +76,7 @@ public partial class RoutingService
|
|||
|
||||
var routing = _services.GetRequiredService<IRoutingService>();
|
||||
// Call functions
|
||||
await routing.InvokeFunction(message.FunctionName, message, onFunctionExecuting);
|
||||
await routing.InvokeFunction(message.FunctionName, message);
|
||||
|
||||
// Pass execution result to LLM to get response
|
||||
if (!message.StopCompletion)
|
||||
|
|
@ -101,7 +101,7 @@ public partial class RoutingService
|
|||
|
||||
// Send to Next LLM
|
||||
var agentId = routing.Context.GetCurrentAgentId();
|
||||
await InvokeAgent(agentId, dialogs, onFunctionExecuting);
|
||||
await InvokeAgent(agentId, dialogs);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
using BotSharp.Abstraction.Functions;
|
||||
|
||||
namespace BotSharp.Core.Routing;
|
||||
|
||||
public partial class RoutingService
|
||||
{
|
||||
public async Task<bool> InvokeFunction(string name, RoleDialogModel message, Func<RoleDialogModel, Task>? onFunctionExecuting = null)
|
||||
public async Task<bool> InvokeFunction(string name, RoleDialogModel message)
|
||||
{
|
||||
var function = _services.GetServices<IFunctionCallback>().FirstOrDefault(x => x.Name == name);
|
||||
if (function == null)
|
||||
|
|
@ -23,11 +22,13 @@ public partial class RoutingService
|
|||
.OrderBy(x => x.Priority)
|
||||
.ToList();
|
||||
|
||||
var progressService = _services.GetService<IConversationProgressService>();
|
||||
|
||||
// Before executing functions
|
||||
clonedMessage.Indication = function.Indication;
|
||||
if (onFunctionExecuting != null)
|
||||
if (progressService?.OnFunctionExecuting != null)
|
||||
{
|
||||
await onFunctionExecuting(clonedMessage);
|
||||
await progressService.OnFunctionExecuting(clonedMessage);
|
||||
}
|
||||
|
||||
foreach (var hook in hooks)
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ public partial class RoutingService : IRoutingService
|
|||
ExecutingDirectly = true
|
||||
};
|
||||
|
||||
var result = await handler.Handle(this, inst, message, null);
|
||||
var result = await handler.Handle(this, inst, message);
|
||||
|
||||
var response = dialogs.Last();
|
||||
response.MessageId = message.MessageId;
|
||||
|
|
@ -64,7 +64,7 @@ public partial class RoutingService : IRoutingService
|
|||
return response;
|
||||
}
|
||||
|
||||
public async Task<RoleDialogModel> InstructLoop(RoleDialogModel message, List<RoleDialogModel> dialogs, Func<RoleDialogModel, Task> onFunctionExecuting)
|
||||
public async Task<RoleDialogModel> InstructLoop(RoleDialogModel message, List<RoleDialogModel> dialogs)
|
||||
{
|
||||
RoleDialogModel response = default;
|
||||
|
||||
|
|
@ -125,12 +125,12 @@ public partial class RoutingService : IRoutingService
|
|||
if (inst.HandleDialogsByPlanner)
|
||||
{
|
||||
var dialogWithoutContext = planner.BeforeHandleContext(inst, message, dialogs);
|
||||
response = await executor.Execute(this, inst, message, dialogWithoutContext, onFunctionExecuting);
|
||||
response = await executor.Execute(this, inst, message, dialogWithoutContext);
|
||||
planner.AfterHandleContext(dialogs, dialogWithoutContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
response = await executor.Execute(this, inst, message, dialogs, onFunctionExecuting);
|
||||
response = await executor.Execute(this, inst, message, dialogs);
|
||||
}
|
||||
|
||||
await planner.AgentExecuted(_router, inst, response, dialogs);
|
||||
|
|
|
|||
|
|
@ -281,9 +281,7 @@ public class ConversationController : ControllerBase
|
|||
response.RichContent = msg.SecondaryRichContent ?? msg.RichContent;
|
||||
response.Instruction = msg.Instruction;
|
||||
response.Data = msg.Data;
|
||||
},
|
||||
_ => Task.CompletedTask,
|
||||
_ => Task.CompletedTask);
|
||||
});
|
||||
|
||||
var state = _services.GetRequiredService<IConversationStateService>();
|
||||
response.States = state.GetStates();
|
||||
|
|
@ -321,6 +319,7 @@ public class ConversationController : ControllerBase
|
|||
Response.Headers.Append(Microsoft.Net.Http.Headers.HeaderNames.ContentType, "text/event-stream");
|
||||
Response.Headers.Append(Microsoft.Net.Http.Headers.HeaderNames.CacheControl, "no-cache");
|
||||
Response.Headers.Append(Microsoft.Net.Http.Headers.HeaderNames.Connection, "keep-alive");
|
||||
InitProgressService(conversationId);
|
||||
|
||||
await conv.SendMessage(agentId, inputMsg,
|
||||
replyMessage: input.Postback,
|
||||
|
|
@ -335,25 +334,6 @@ public class ConversationController : ControllerBase
|
|||
response.States = state.GetStates();
|
||||
|
||||
await OnChunkReceived(Response, response);
|
||||
},
|
||||
// executing
|
||||
async msg =>
|
||||
{
|
||||
var indicator = new ChatResponseModel
|
||||
{
|
||||
ConversationId = conversationId,
|
||||
MessageId = msg.MessageId,
|
||||
Text = msg.Indication,
|
||||
Function = "indicating",
|
||||
Instruction = msg.Instruction,
|
||||
States = new Dictionary<string, string>()
|
||||
};
|
||||
await OnChunkReceived(Response, indicator);
|
||||
},
|
||||
// executed
|
||||
async msg =>
|
||||
{
|
||||
|
||||
});
|
||||
|
||||
response.States = state.GetStates();
|
||||
|
|
@ -362,6 +342,25 @@ public class ConversationController : ControllerBase
|
|||
|
||||
// await OnEventCompleted(Response);
|
||||
}
|
||||
|
||||
private void InitProgressService(string conversationId)
|
||||
{
|
||||
var progressService = _services.GetService<IConversationProgressService>();
|
||||
progressService.OnFunctionExecuting = async msg =>
|
||||
{
|
||||
var indicator = new ChatResponseModel
|
||||
{
|
||||
ConversationId = conversationId,
|
||||
MessageId = msg.MessageId,
|
||||
Text = msg.Indication,
|
||||
Function = "indicating",
|
||||
Instruction = msg.Instruction,
|
||||
States = new Dictionary<string, string>()
|
||||
};
|
||||
await OnChunkReceived(Response, indicator);
|
||||
};
|
||||
progressService.OnFunctionExecuted = async msg => { };
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Files and attachments
|
||||
|
|
|
|||
|
|
@ -63,6 +63,9 @@ namespace BotSharp.Plugin.Twilio.Services
|
|||
var conv = sp.GetRequiredService<IConversationService>();
|
||||
var routing = sp.GetRequiredService<IRoutingService>();
|
||||
var config = sp.GetRequiredService<TwilioSetting>();
|
||||
var sessionManager = sp.GetRequiredService<ITwilioSessionManager>();
|
||||
var progressService = sp.GetRequiredService<IConversationProgressService>();
|
||||
InitProgressService(message, sessionManager, progressService);
|
||||
|
||||
routing.Context.SetMessageId(message.ConversationId, inputMsg.MessageId);
|
||||
var states = new List<MessageState>
|
||||
|
|
@ -77,7 +80,6 @@ namespace BotSharp.Plugin.Twilio.Services
|
|||
}
|
||||
conv.SetConversationId(message.ConversationId, states);
|
||||
|
||||
var sessionManager = sp.GetRequiredService<ITwilioSessionManager>();
|
||||
var result = await conv.SendMessage(config.AgentId,
|
||||
inputMsg,
|
||||
replyMessage: null,
|
||||
|
|
@ -90,15 +92,7 @@ namespace BotSharp.Plugin.Twilio.Services
|
|||
Content = msg.Content,
|
||||
MessageId = msg.MessageId
|
||||
};
|
||||
},
|
||||
async msg =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(msg.Indication))
|
||||
{
|
||||
await sessionManager.SetReplyIndicationAsync(message.ConversationId, message.SeqNumber, msg.Indication);
|
||||
}
|
||||
},
|
||||
async functionExecuted => { }
|
||||
}
|
||||
);
|
||||
|
||||
var completion = CompletionProvider.GetAudioCompletion(sp, "openai", "tts-1");
|
||||
|
|
@ -130,5 +124,17 @@ namespace BotSharp.Plugin.Twilio.Services
|
|||
reply.Content = null;
|
||||
await sessionManager.SetAssistantReplyAsync(message.ConversationId, message.SeqNumber, reply);
|
||||
}
|
||||
|
||||
private static void InitProgressService(CallerMessage message, ITwilioSessionManager sessionManager, IConversationProgressService progressService)
|
||||
{
|
||||
progressService.OnFunctionExecuting = async msg =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(msg.Indication))
|
||||
{
|
||||
await sessionManager.SetReplyIndicationAsync(message.ConversationId, message.SeqNumber, msg.Indication);
|
||||
}
|
||||
};
|
||||
progressService.OnFunctionExecuted = async msg => { };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue