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;
|
|
|
|
|
}
|
|
|
|
|
}
|