PostbackFunctionName

This commit is contained in:
Haiping Chen 2024-04-06 18:33:49 -05:00
parent 054b898e8f
commit 3c968bd068
5 changed files with 70 additions and 31 deletions

View file

@ -35,6 +35,9 @@ public class RoleDialogModel : ITrackableMessage
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? FunctionName { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? PostbackFunctionName { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? FunctionArgs { get; set; }
@ -95,6 +98,7 @@ public class RoleDialogModel : ITrackableMessage
MessageId = source.MessageId,
FunctionArgs = source.FunctionArgs,
FunctionName = source.FunctionName,
PostbackFunctionName = source.PostbackFunctionName,
RichContent = source.RichContent,
StopCompletion = source.StopCompletion,
Instruction = source.Instruction,

View file

@ -72,10 +72,13 @@ public partial class ConversationService
}
// Persist to storage
_storage.Append(_conversationId, message);
if (!message.StopCompletion)
{
_storage.Append(_conversationId, message);
// Add to thread
dialogs.Add(RoleDialogModel.From(message));
// Add to thread
dialogs.Add(RoleDialogModel.From(message));
}
if (!stopCompletion)
{
@ -147,6 +150,12 @@ public partial class ConversationService
Message = new TextMessage(response.Content)
};
// Patch return function name
if (response.PostbackFunctionName != null)
{
response.FunctionName = response.PostbackFunctionName;
}
var hooks = _services.GetServices<IConversationHook>().ToList();
if (response.Instruction != null)

View file

@ -28,11 +28,11 @@ public class ConversationStorage : IConversationStorage
var dialogElements = new List<DialogElement>();
// Prevent duplicate record to be inserted
var dialogs = db.GetConversationDialogs(conversationId);
/*var dialogs = db.GetConversationDialogs(conversationId);
if (dialogs.Any(x => x.MetaData.MessageId == dialog.MessageId && x.Content == dialog.Content))
{
return;
}
}*/
if (dialog.Role == AgentRole.Function)
{

View file

@ -5,6 +5,8 @@ namespace BotSharp.Core.Routing;
public partial class RoutingService
{
private List<FunctionCallingResponse> _functionCallStack = new List<FunctionCallingResponse>();
public List<FunctionCallingResponse> FunctionCallStack => _functionCallStack;
public async Task<bool> InvokeFunction(string name, RoleDialogModel message)
{
var function = _services.GetServices<IFunctionCallback>().FirstOrDefault(x => x.Name == name);
@ -16,10 +18,9 @@ public partial class RoutingService
return false;
}
var originalFunctionName = message.FunctionName;
message.FunctionName = name;
message.Role = AgentRole.Function;
message.FunctionArgs = message.FunctionArgs;
// Clone message
var clonedMessage = RoleDialogModel.From(message);
clonedMessage.FunctionName = name;
var hooks = _services.GetServices<IConversationHook>()
.OrderBy(x => x.Priority)
@ -28,21 +29,36 @@ public partial class RoutingService
// Before executing functions
foreach (var hook in hooks)
{
await hook.OnFunctionExecuting(message);
await hook.OnFunctionExecuting(clonedMessage);
}
bool result = false;
try
{
result = await function.Execute(message);
result = await function.Execute(clonedMessage);
_functionCallStack.Add(new FunctionCallingResponse
{
Role = AgentRole.Function,
FunctionName = message.FunctionName,
Args = JsonDocument.Parse(message.FunctionArgs ?? "{}"),
Content = message.Content
FunctionName = clonedMessage.FunctionName,
Args = JsonDocument.Parse(clonedMessage.FunctionArgs ?? "{}"),
Content = clonedMessage.Content
});
// After functions have been executed
foreach (var hook in hooks)
{
await hook.OnFunctionExecuted(clonedMessage);
}
// Set result to original message
message.PostbackFunctionName = clonedMessage.PostbackFunctionName;
message.CurrentAgentId = clonedMessage.CurrentAgentId;
message.Content = clonedMessage.Content;
message.StopCompletion = clonedMessage.StopCompletion;
message.RichContent = clonedMessage.RichContent;
message.Data = clonedMessage.Data;
}
catch (JsonException ex)
{
@ -63,25 +79,12 @@ public partial class RoutingService
message.Content = JsonSerializer.Serialize(message.Data);
}
// After functions have been executed
foreach (var hook in hooks)
{
await hook.OnFunctionExecuted(message);
}
// restore original function name
if (!message.StopCompletion &&
message.FunctionName != originalFunctionName)
{
message.FunctionName = originalFunctionName;
}
// Save to Storage as well
if (!message.StopCompletion && message.FunctionName != "route_to_agent")
/*if (!message.StopCompletion && message.FunctionName != "route_to_agent")
{
var storage = _services.GetRequiredService<IConversationStorage>();
storage.Append(Context.ConversationId, message);
}
}*/
return result;
}

View file

@ -98,7 +98,7 @@ public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook, IR
if (!_convSettings.ShowVerboseLog) return;
}
public override async Task OnFunctionExecuted(RoleDialogModel message)
public override async Task OnFunctionExecuting(RoleDialogModel message)
{
if (message.FunctionName == "route_to_agent")
{
@ -109,7 +109,30 @@ public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook, IR
var agent = await _agentService.LoadAgent(message.CurrentAgentId);
message.FunctionArgs = message.FunctionArgs ?? "{}";
var args = JsonSerializer.Serialize(JsonDocument.Parse(message.FunctionArgs), _options.JsonSerializerOptions);
var log = $"*{message.FunctionName}*\r\n```json\r\n{args}\r\n```\r\n=> {message.Content?.Trim()}";
var log = $"{message.FunctionName} <u>executing</u>\r\n```json\r\n{args}\r\n```";
var input = new ContentLogInputModel(conversationId, message)
{
Name = agent?.Name,
AgentId = agent?.Id,
Source = ContentLogSource.FunctionCall,
Log = log
};
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", BuildContentLog(input));
}
public override async Task OnFunctionExecuted(RoleDialogModel message)
{
if (message.FunctionName == "route_to_agent")
{
return;
}
var conversationId = _state.GetConversationId();
var agent = await _agentService.LoadAgent(message.CurrentAgentId);
message.FunctionArgs = message.FunctionArgs ?? "{}";
// var args = JsonSerializer.Serialize(JsonDocument.Parse(message.FunctionArgs), _options.JsonSerializerOptions);
var log = $"{message.FunctionName} =>\r\n*{message.Content?.Trim()}*";
var input = new ContentLogInputModel(conversationId, message)
{