BotSharp/src/Infrastructure/BotSharp.Core.SideCar/Services/BotSharpConversationSideCar.cs

154 lines
5.1 KiB
C#
Raw Normal View History

2024-12-03 17:52:25 +00:00
/*****************************************************************************
Copyright 2024 Written by Jicheng Lu. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
******************************************************************************/
2024-11-22 02:33:55 +00:00
using BotSharp.Core.Infrastructures;
2024-11-04 22:44:41 +00:00
namespace BotSharp.Core.SideCar.Services;
2024-10-29 19:59:46 +00:00
2024-11-04 22:44:41 +00:00
public class BotSharpConversationSideCar : IConversationSideCar
2024-10-29 19:59:46 +00:00
{
private readonly IServiceProvider _services;
2024-11-04 22:44:41 +00:00
private readonly ILogger<BotSharpConversationSideCar> _logger;
2024-10-29 19:59:46 +00:00
private Stack<ConversationContext> contextStack = new();
private bool enabled = false;
2024-11-04 22:44:41 +00:00
public string Provider => "botsharp";
public BotSharpConversationSideCar(
2024-10-29 19:59:46 +00:00
IServiceProvider services,
2024-11-04 22:44:41 +00:00
ILogger<BotSharpConversationSideCar> logger)
2024-10-29 19:59:46 +00:00
{
_services = services;
_logger = logger;
}
public bool IsEnabled()
{
return enabled;
}
public void AppendConversationDialogs(string conversationId, List<DialogElement> messages)
{
2024-11-04 22:44:41 +00:00
if (contextStack.IsNullOrEmpty()) return;
var top = contextStack.Peek();
top.Dialogs.AddRange(messages);
2024-10-29 19:59:46 +00:00
}
public List<DialogElement> GetConversationDialogs(string conversationId)
{
2024-11-04 22:44:41 +00:00
if (contextStack.IsNullOrEmpty())
2024-10-29 19:59:46 +00:00
{
2024-11-04 22:44:41 +00:00
return new List<DialogElement>();
2024-10-29 19:59:46 +00:00
}
2024-11-04 22:44:41 +00:00
return contextStack.Peek().Dialogs;
2024-10-29 19:59:46 +00:00
}
public void UpdateConversationBreakpoint(string conversationId, ConversationBreakpoint breakpoint)
{
2024-11-04 22:44:41 +00:00
if (contextStack.IsNullOrEmpty()) return;
var top = contextStack.Peek().Breakpoints;
top.Add(breakpoint);
2024-10-29 19:59:46 +00:00
}
public ConversationBreakpoint? GetConversationBreakpoint(string conversationId)
{
2024-11-04 22:44:41 +00:00
if (contextStack.IsNullOrEmpty())
2024-10-29 19:59:46 +00:00
{
2024-11-04 22:44:41 +00:00
return null;
2024-10-29 19:59:46 +00:00
}
2024-11-04 22:44:41 +00:00
var top = contextStack.Peek().Breakpoints;
return top.LastOrDefault();
2024-10-29 19:59:46 +00:00
}
2024-11-04 22:44:41 +00:00
public async Task<RoleDialogModel> SendMessage(string agentId, string text,
2024-10-29 19:59:46 +00:00
PostbackMessageModel? postback = null, List<MessageState>? states = null)
{
BeforeExecute();
var response = await InnerExecute(agentId, text, postback, states);
AfterExecute();
return response;
}
private async Task<RoleDialogModel> InnerExecute(string agentId, string text,
PostbackMessageModel? postback = null, List<MessageState>? states = null)
{
var conv = _services.GetRequiredService<IConversationService>();
var routing = _services.GetRequiredService<IRoutingService>();
var state = _services.GetRequiredService<IConversationStateService>();
var inputMsg = new RoleDialogModel(AgentRole.User, text);
routing.Context.SetMessageId(conv.ConversationId, inputMsg.MessageId);
states?.ForEach(x => state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External));
var response = new RoleDialogModel(AgentRole.Assistant, string.Empty);
await conv.SendMessage(agentId, inputMsg,
replyMessage: postback,
async msg =>
{
response.Content = !string.IsNullOrEmpty(msg.SecondaryContent) ? msg.SecondaryContent : msg.Content;
response.FunctionName = msg.FunctionName;
response.RichContent = msg.SecondaryRichContent ?? msg.RichContent;
response.Instruction = msg.Instruction;
response.Data = msg.Data;
});
return response;
}
private void BeforeExecute()
{
enabled = true;
var state = _services.GetRequiredService<IConversationStateService>();
var routing = _services.GetRequiredService<IRoutingService>();
var node = new ConversationContext
{
State = state.GetCurrentState(),
Dialogs = new(),
Breakpoints = new(),
RecursiveCounter = routing.Context.GetRecursiveCounter(),
RoutingStack = routing.Context.GetAgentStack()
};
contextStack.Push(node);
// Reset
state.ResetCurrentState();
routing.Context.ResetRecursiveCounter();
routing.Context.ResetAgentStack();
2024-11-22 02:33:55 +00:00
Utilities.ClearCache();
2024-10-29 19:59:46 +00:00
}
private void AfterExecute()
{
var state = _services.GetRequiredService<IConversationStateService>();
var routing = _services.GetRequiredService<IRoutingService>();
var node = contextStack.Pop();
// Recover
state.SetCurrentState(node.State);
routing.Context.SetRecursiveCounter(node.RecursiveCounter);
routing.Context.SetAgentStack(node.RoutingStack);
2024-11-22 02:33:55 +00:00
Utilities.ClearCache();
2024-10-29 19:59:46 +00:00
enabled = false;
}
}