This commit is contained in:
nick.yi 2025-07-08 09:23:48 +08:00
commit 1e4c06e406
7 changed files with 72 additions and 10 deletions

View file

@ -1,3 +1,5 @@
using BotSharp.Abstraction.SideCar.Models;
namespace BotSharp.Abstraction.SideCar; namespace BotSharp.Abstraction.SideCar;
public interface IConversationSideCar public interface IConversationSideCar
@ -11,5 +13,8 @@ public interface IConversationSideCar
ConversationBreakpoint? GetConversationBreakpoint(string conversationId); ConversationBreakpoint? GetConversationBreakpoint(string conversationId);
void UpdateConversationStates(string conversationId, List<StateKeyValue> states); void UpdateConversationStates(string conversationId, List<StateKeyValue> states);
Task<RoleDialogModel> SendMessage(string agentId, string text, Task<RoleDialogModel> SendMessage(string agentId, string text,
PostbackMessageModel? postback = null, List<MessageState>? states = null, List<DialogElement>? dialogs = null); PostbackMessageModel? postback = null,
List<MessageState>? states = null,
List<DialogElement>? dialogs = null,
SideCarOptions? options = null);
} }

View file

@ -0,0 +1,12 @@
namespace BotSharp.Abstraction.SideCar.Models;
public class SideCarOptions
{
public bool IsInheritStates { get; set; }
public IEnumerable<string>? InheritStateKeys { get; set; }
public static SideCarOptions Empty()
{
return new SideCarOptions();
}
}

View file

@ -14,6 +14,7 @@
limitations under the License. limitations under the License.
******************************************************************************/ ******************************************************************************/
using BotSharp.Abstraction.SideCar.Models;
using BotSharp.Core.Infrastructures; using BotSharp.Core.Infrastructures;
namespace BotSharp.Core.SideCar.Services; namespace BotSharp.Core.SideCar.Services;
@ -24,6 +25,7 @@ public class BotSharpConversationSideCar : IConversationSideCar
private readonly ILogger<BotSharpConversationSideCar> _logger; private readonly ILogger<BotSharpConversationSideCar> _logger;
private Stack<ConversationContext> _contextStack = new(); private Stack<ConversationContext> _contextStack = new();
private SideCarOptions? _sideCarOptions;
private bool _enabled = false; private bool _enabled = false;
private string _conversationId = string.Empty; private string _conversationId = string.Empty;
@ -98,8 +100,13 @@ public class BotSharpConversationSideCar : IConversationSideCar
} }
public async Task<RoleDialogModel> SendMessage(string agentId, string text, public async Task<RoleDialogModel> SendMessage(string agentId, string text,
PostbackMessageModel? postback = null, List<MessageState>? states = null, List<DialogElement>? dialogs = null) PostbackMessageModel? postback = null,
List<MessageState>? states = null,
List<DialogElement>? dialogs = null,
SideCarOptions? options = null)
{ {
_sideCarOptions = options;
BeforeExecute(dialogs); BeforeExecute(dialogs);
var response = await InnerExecute(agentId, text, postback, states); var response = await InnerExecute(agentId, text, postback, states);
AfterExecute(); AfterExecute();
@ -160,13 +167,11 @@ public class BotSharpConversationSideCar : IConversationSideCar
private void AfterExecute() private void AfterExecute()
{ {
var state = _services.GetRequiredService<IConversationStateService>();
var routing = _services.GetRequiredService<IRoutingService>(); var routing = _services.GetRequiredService<IRoutingService>();
var node = _contextStack.Pop(); var node = _contextStack.Pop();
// Recover // Recover
state.SetCurrentState(node.State); RestoreStates(node.State);
routing.Context.SetRecursiveCounter(node.RecursiveCounter); routing.Context.SetRecursiveCounter(node.RecursiveCounter);
routing.Context.SetAgentStack(node.RoutingStack); routing.Context.SetAgentStack(node.RoutingStack);
routing.Context.SetDialogs(node.RoutingDialogs); routing.Context.SetDialogs(node.RoutingDialogs);
@ -181,4 +186,43 @@ public class BotSharpConversationSideCar : IConversationSideCar
&& !string.IsNullOrEmpty(conversationId) && !string.IsNullOrEmpty(conversationId)
&& !string.IsNullOrEmpty(_conversationId); && !string.IsNullOrEmpty(_conversationId);
} }
private void RestoreStates(ConversationState prevStates)
{
var innerStates = prevStates;
var state = _services.GetRequiredService<IConversationStateService>();
if (_sideCarOptions?.IsInheritStates == true)
{
var curStates = state.GetCurrentState();
foreach (var pair in curStates)
{
var endNode = pair.Value.Values.LastOrDefault();
if (endNode == null) continue;
if (_sideCarOptions?.InheritStateKeys?.Any() == true
&& !_sideCarOptions.InheritStateKeys.Contains(pair.Key))
{
continue;
}
if (innerStates.ContainsKey(pair.Key))
{
innerStates[pair.Key].Values.Add(endNode);
}
else
{
innerStates[pair.Key] = new StateKeyValue
{
Key = pair.Key,
Versioning = pair.Value.Versioning,
Readonly = pair.Value.Readonly,
Values = [endNode]
};
}
}
}
state.SetCurrentState(innerStates);
}
} }

View file

@ -16,5 +16,6 @@ global using BotSharp.Abstraction.Conversations.Models;
global using BotSharp.Abstraction.Models; global using BotSharp.Abstraction.Models;
global using BotSharp.Abstraction.Routing; global using BotSharp.Abstraction.Routing;
global using BotSharp.Abstraction.SideCar; global using BotSharp.Abstraction.SideCar;
global using BotSharp.Abstraction.SideCar.Models;
global using BotSharp.Abstraction.Utilities; global using BotSharp.Abstraction.Utilities;
global using BotSharp.Core.SideCar.Settings; global using BotSharp.Core.SideCar.Settings;

View file

@ -443,7 +443,7 @@ public class ConversationStateService : IConversationStateService
public void SetCurrentState(ConversationState state) public void SetCurrentState(ConversationState state)
{ {
var values = _curStates.Values.ToList(); var values = state.Values.ToList();
var copy = JsonSerializer.Deserialize<List<StateKeyValue>>(JsonSerializer.Serialize(values)); var copy = JsonSerializer.Deserialize<List<StateKeyValue>>(JsonSerializer.Serialize(values));
_curStates = new ConversationState(copy ?? []); _curStates = new ConversationState(copy ?? []);
} }

View file

@ -270,7 +270,7 @@ public class ChatCompletionProvider : IChatCompletion
{ {
messages.Add(new AssistantChatMessage(new List<ChatToolCall> messages.Add(new AssistantChatMessage(new List<ChatToolCall>
{ {
ChatToolCall.CreateFunctionToolCall(message.ToolCallId.IfNullOrEmptyAs(message.FunctionName), message.FunctionName, BinaryData.FromString(message.FunctionArgs ?? string.Empty)) ChatToolCall.CreateFunctionToolCall(message.ToolCallId.IfNullOrEmptyAs(message.FunctionName), message.FunctionName, BinaryData.FromString(message.FunctionArgs ?? "{}"))
})); }));
messages.Add(new ToolChatMessage(message.ToolCallId.IfNullOrEmptyAs(message.FunctionName), message.Content)); messages.Add(new ToolChatMessage(message.ToolCallId.IfNullOrEmptyAs(message.FunctionName), message.Content));

View file

@ -615,10 +615,10 @@ public class RealTimeCompletionProvider : IRealTimeCompletion
{ {
messages.Add(new AssistantChatMessage(new List<ChatToolCall> messages.Add(new AssistantChatMessage(new List<ChatToolCall>
{ {
ChatToolCall.CreateFunctionToolCall(message.ToolCallId, message.FunctionName, BinaryData.FromString(message.FunctionArgs ?? string.Empty)) ChatToolCall.CreateFunctionToolCall(message.ToolCallId.IfNullOrEmptyAs(message.FunctionName), message.FunctionName, BinaryData.FromString(message.FunctionArgs ?? "{}"))
})); }));
messages.Add(new ToolChatMessage(message.ToolCallId, message.Content)); messages.Add(new ToolChatMessage(message.ToolCallId.IfNullOrEmptyAs(message.FunctionName), message.Content));
} }
else if (message.Role == AgentRole.User) else if (message.Role == AgentRole.User)
{ {