commit
dec1fba4b5
|
|
@ -59,6 +59,9 @@ public abstract class ConversationHookBase : IConversationHook
|
||||||
public virtual Task OnMessageReceived(RoleDialogModel message)
|
public virtual Task OnMessageReceived(RoleDialogModel message)
|
||||||
=> Task.CompletedTask;
|
=> Task.CompletedTask;
|
||||||
|
|
||||||
|
public virtual Task OnPostbackMessageReceived(RoleDialogModel message, PostbackMessageModel replyMsg)
|
||||||
|
=> Task.CompletedTask;
|
||||||
|
|
||||||
public virtual Task OnResponseGenerated(RoleDialogModel message)
|
public virtual Task OnResponseGenerated(RoleDialogModel message)
|
||||||
=> Task.CompletedTask;
|
=> Task.CompletedTask;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ public interface IConversationHook
|
||||||
Task OnStateChanged(string name, string preValue, string currentValue);
|
Task OnStateChanged(string name, string preValue, string currentValue);
|
||||||
|
|
||||||
Task OnMessageReceived(RoleDialogModel message);
|
Task OnMessageReceived(RoleDialogModel message);
|
||||||
|
Task OnPostbackMessageReceived(RoleDialogModel message, PostbackMessageModel replyMsg);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Triggered before LLM calls function.
|
/// Triggered before LLM calls function.
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ public interface IConversationService
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<bool> SendMessage(string agentId,
|
Task<bool> SendMessage(string agentId,
|
||||||
RoleDialogModel lastDalog,
|
RoleDialogModel lastDalog,
|
||||||
|
PostbackMessageModel? replyMessage,
|
||||||
Func<RoleDialogModel, Task> onResponseReceived,
|
Func<RoleDialogModel, Task> onResponseReceived,
|
||||||
Func<RoleDialogModel, Task> onFunctionExecuting,
|
Func<RoleDialogModel, Task> onFunctionExecuting,
|
||||||
Func<RoleDialogModel, Task> onFunctionExecuted);
|
Func<RoleDialogModel, Task> onFunctionExecuted);
|
||||||
|
|
|
||||||
|
|
@ -4,4 +4,9 @@ public class IncomingMessageModel : MessageConfig
|
||||||
{
|
{
|
||||||
public string Text { get; set; } = string.Empty;
|
public string Text { get; set; } = string.Empty;
|
||||||
public virtual string Channel { get; set; } = string.Empty;
|
public virtual string Channel { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Postback message
|
||||||
|
/// </summary>
|
||||||
|
public PostbackMessageModel? Postback { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
namespace BotSharp.Abstraction.Conversations.Models;
|
||||||
|
|
||||||
|
public class PostbackMessageModel
|
||||||
|
{
|
||||||
|
public string FunctionName { get; set; } = string.Empty;
|
||||||
|
public string Payload { get; set; } = string.Empty;
|
||||||
|
/// <summary>
|
||||||
|
/// Parent message id
|
||||||
|
/// </summary>
|
||||||
|
public string ParentId { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
|
@ -31,7 +31,7 @@ public interface IRoutingService
|
||||||
List<RoutingHandlerDef> GetHandlers(Agent router);
|
List<RoutingHandlerDef> GetHandlers(Agent router);
|
||||||
void ResetRecursiveCounter();
|
void ResetRecursiveCounter();
|
||||||
Task<bool> InvokeAgent(string agentId, List<RoleDialogModel> dialogs);
|
Task<bool> InvokeAgent(string agentId, List<RoleDialogModel> dialogs);
|
||||||
Task<bool> InvokeFunction(string name, RoleDialogModel message, bool restoreOriginalFunctionName = true);
|
Task<bool> InvokeFunction(string name, RoleDialogModel message);
|
||||||
Task<RoleDialogModel> InstructLoop(RoleDialogModel message);
|
Task<RoleDialogModel> InstructLoop(RoleDialogModel message);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ public partial class ConversationService
|
||||||
{
|
{
|
||||||
public async Task<bool> SendMessage(string agentId,
|
public async Task<bool> SendMessage(string agentId,
|
||||||
RoleDialogModel message,
|
RoleDialogModel message,
|
||||||
|
PostbackMessageModel? replyMessage,
|
||||||
Func<RoleDialogModel, Task> onMessageReceived,
|
Func<RoleDialogModel, Task> onMessageReceived,
|
||||||
Func<RoleDialogModel, Task> onFunctionExecuting,
|
Func<RoleDialogModel, Task> onFunctionExecuting,
|
||||||
Func<RoleDialogModel, Task> onFunctionExecuted)
|
Func<RoleDialogModel, Task> onFunctionExecuted)
|
||||||
|
|
@ -51,7 +52,14 @@ public partial class ConversationService
|
||||||
hook.SetAgent(agent)
|
hook.SetAgent(agent)
|
||||||
.SetConversation(conversation);
|
.SetConversation(conversation);
|
||||||
|
|
||||||
await hook.OnMessageReceived(message);
|
if (replyMessage == null)
|
||||||
|
{
|
||||||
|
await hook.OnMessageReceived(message);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await hook.OnPostbackMessageReceived(message, replyMessage);
|
||||||
|
}
|
||||||
|
|
||||||
// Interrupted by hook
|
// Interrupted by hook
|
||||||
if (message.StopCompletion)
|
if (message.StopCompletion)
|
||||||
|
|
|
||||||
|
|
@ -97,9 +97,10 @@ public class EvaluatingService : IEvaluatingService
|
||||||
|
|
||||||
await conv.SendMessage(agentId,
|
await conv.SendMessage(agentId,
|
||||||
new RoleDialogModel(AgentRole.User, text),
|
new RoleDialogModel(AgentRole.User, text),
|
||||||
|
replyMessage: null,
|
||||||
async msg => response = msg,
|
async msg => response = msg,
|
||||||
fnExecuting => Task.CompletedTask,
|
_ => Task.CompletedTask,
|
||||||
fnExecuted => Task.CompletedTask);
|
_ => Task.CompletedTask);
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,11 @@ public class RouteToAgentRoutingHandler : RoutingHandlerBase, IRoutingHandler
|
||||||
|
|
||||||
public List<ParameterPropertyDef> Parameters => new List<ParameterPropertyDef>
|
public List<ParameterPropertyDef> Parameters => new List<ParameterPropertyDef>
|
||||||
{
|
{
|
||||||
new ParameterPropertyDef("next_action_reason", "the reason why route to this agent")
|
new ParameterPropertyDef("next_action_reason", "the reason why route to this agent, if user is replying last agent's question, you must route to this agent")
|
||||||
{
|
{
|
||||||
Required = true
|
Required = true
|
||||||
},
|
},
|
||||||
new ParameterPropertyDef("next_action_agent", "agent for next action based on user latest response")
|
new ParameterPropertyDef("next_action_agent", "agent for next action based on user latest response, if user is replying last agent's question, you must route to this agent")
|
||||||
{
|
{
|
||||||
Required = true
|
Required = true
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
using Amazon.Runtime.Internal.Transform;
|
||||||
using BotSharp.Abstraction.Agents.Models;
|
using BotSharp.Abstraction.Agents.Models;
|
||||||
using BotSharp.Abstraction.Functions.Models;
|
using BotSharp.Abstraction.Functions.Models;
|
||||||
using BotSharp.Abstraction.Repositories.Filters;
|
using BotSharp.Abstraction.Repositories.Filters;
|
||||||
|
|
@ -111,9 +112,11 @@ public class NaivePlanner : IPlaner
|
||||||
{
|
{
|
||||||
var template = router.Templates.First(x => x.Name == "planner_prompt.naive").Content;
|
var template = router.Templates.First(x => x.Name == "planner_prompt.naive").Content;
|
||||||
|
|
||||||
|
var states = _services.GetRequiredService<IConversationStateService>();
|
||||||
var render = _services.GetRequiredService<ITemplateRender>();
|
var render = _services.GetRequiredService<ITemplateRender>();
|
||||||
return render.Render(template, new Dictionary<string, object>
|
return render.Render(template, new Dictionary<string, object>
|
||||||
{
|
{
|
||||||
|
{ "expected_next_action_agent", states.GetState("expected_next_action_agent")}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ namespace BotSharp.Core.Routing;
|
||||||
|
|
||||||
public partial class RoutingService
|
public partial class RoutingService
|
||||||
{
|
{
|
||||||
public async Task<bool> InvokeFunction(string name, RoleDialogModel message, bool restoreOriginalFunctionName = true)
|
public async Task<bool> InvokeFunction(string name, RoleDialogModel message)
|
||||||
{
|
{
|
||||||
var function = _services.GetServices<IFunctionCallback>().FirstOrDefault(x => x.Name == name);
|
var function = _services.GetServices<IFunctionCallback>().FirstOrDefault(x => x.Name == name);
|
||||||
if (function == null)
|
if (function == null)
|
||||||
|
|
@ -57,8 +57,7 @@ public partial class RoutingService
|
||||||
|
|
||||||
// restore original function name
|
// restore original function name
|
||||||
if (!message.StopCompletion &&
|
if (!message.StopCompletion &&
|
||||||
message.FunctionName != originalFunctionName &&
|
message.FunctionName != originalFunctionName)
|
||||||
restoreOriginalFunctionName)
|
|
||||||
{
|
{
|
||||||
message.FunctionName = originalFunctionName;
|
message.FunctionName = originalFunctionName;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,7 @@
|
||||||
What is the next step based on the CONVERSATION?
|
What is the next step based on the CONVERSATION?
|
||||||
Route to the Agent that last handled the conversation if necessary.
|
Route to the appropriate agent last handled agent based on the context.
|
||||||
|
{% if expected_next_action_agent != empty -%}
|
||||||
|
Expected next action agent is {{ expected_next_action_agent }}.
|
||||||
|
{%- endif %}
|
||||||
|
Try to keep the User Goal Agent be consistent as previous goal agent.
|
||||||
If user wants to speak to customer service, use function human_intervention_needed.
|
If user wants to speak to customer service, use function human_intervention_needed.
|
||||||
|
|
@ -171,6 +171,7 @@ public class ConversationController : ControllerBase
|
||||||
var response = new ChatResponseModel();
|
var response = new ChatResponseModel();
|
||||||
|
|
||||||
await conv.SendMessage(agentId, inputMsg,
|
await conv.SendMessage(agentId, inputMsg,
|
||||||
|
replyMessage: input.Postback,
|
||||||
async msg =>
|
async msg =>
|
||||||
{
|
{
|
||||||
response.Text = msg.Content;
|
response.Text = msg.Content;
|
||||||
|
|
@ -179,14 +180,8 @@ public class ConversationController : ControllerBase
|
||||||
response.Instruction = msg.Instruction;
|
response.Instruction = msg.Instruction;
|
||||||
response.Data = msg.Data;
|
response.Data = msg.Data;
|
||||||
},
|
},
|
||||||
async fnExecuting =>
|
_ => Task.CompletedTask,
|
||||||
{
|
_ => Task.CompletedTask);
|
||||||
|
|
||||||
},
|
|
||||||
async fnExecuted =>
|
|
||||||
{
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
var state = _services.GetRequiredService<IConversationStateService>();
|
var state = _services.GetRequiredService<IConversationStateService>();
|
||||||
response.States = state.GetStates();
|
response.States = state.GetStates();
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,22 @@ public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook, IR
|
||||||
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", BuildContentLog(input));
|
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", BuildContentLog(input));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override async Task OnPostbackMessageReceived(RoleDialogModel message, PostbackMessageModel replyMsg)
|
||||||
|
{
|
||||||
|
var conversationId = _state.GetConversationId();
|
||||||
|
var log = $"{message.Content}";
|
||||||
|
var replyContent = JsonSerializer.Serialize(replyMsg, _serializerOptions);
|
||||||
|
log += $"\r\n```json\r\n{replyContent}\r\n```";
|
||||||
|
|
||||||
|
var input = new ContentLogInputModel(conversationId, message)
|
||||||
|
{
|
||||||
|
Name = _user.UserName,
|
||||||
|
Source = ContentLogSource.UserInput,
|
||||||
|
Log = log
|
||||||
|
};
|
||||||
|
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", BuildContentLog(input));
|
||||||
|
}
|
||||||
|
|
||||||
public async Task BeforeGenerating(Agent agent, List<RoleDialogModel> conversations)
|
public async Task BeforeGenerating(Agent agent, List<RoleDialogModel> conversations)
|
||||||
{
|
{
|
||||||
if (!_convSettings.ShowVerboseLog) return;
|
if (!_convSettings.ShowVerboseLog) return;
|
||||||
|
|
|
||||||
|
|
@ -80,13 +80,12 @@ public class ChatbotUiController : ControllerBase
|
||||||
.SetState("sampling_factor", input.SamplingFactor);
|
.SetState("sampling_factor", input.SamplingFactor);
|
||||||
|
|
||||||
var result = await conv.SendMessage(input.AgentId,
|
var result = await conv.SendMessage(input.AgentId,
|
||||||
message,
|
message,
|
||||||
|
replyMessage: null,
|
||||||
async msg =>
|
async msg =>
|
||||||
await OnChunkReceived(outputStream, msg),
|
await OnChunkReceived(outputStream, msg),
|
||||||
async fn
|
_ => Task.CompletedTask,
|
||||||
=> await Task.CompletedTask,
|
_ => Task.CompletedTask);
|
||||||
async fn
|
|
||||||
=> await Task.CompletedTask);
|
|
||||||
|
|
||||||
await OnEventCompleted(outputStream);
|
await OnEventCompleted(outputStream);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,9 @@ public class MessageHandleService
|
||||||
|
|
||||||
var replies = new List<IRichMessage>();
|
var replies = new List<IRichMessage>();
|
||||||
var result = await conv.SendMessage(agentId,
|
var result = await conv.SendMessage(agentId,
|
||||||
new RoleDialogModel(AgentRole.User, message), async msg =>
|
new RoleDialogModel(AgentRole.User, message),
|
||||||
|
replyMessage: null,
|
||||||
|
async msg =>
|
||||||
{
|
{
|
||||||
if (msg.RichContent != null)
|
if (msg.RichContent != null)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@ public class TwilioVoiceController : TwilioController
|
||||||
|
|
||||||
var result = await conv.SendMessage(agentId,
|
var result = await conv.SendMessage(agentId,
|
||||||
new RoleDialogModel(AgentRole.User, input.SpeechResult),
|
new RoleDialogModel(AgentRole.User, input.SpeechResult),
|
||||||
|
replyMessage: null,
|
||||||
async msg =>
|
async msg =>
|
||||||
{
|
{
|
||||||
response = twilio.ReturnInstructions(msg.Content);
|
response = twilio.ReturnInstructions(msg.Content);
|
||||||
|
|
|
||||||
|
|
@ -61,16 +61,15 @@ namespace BotSharp.Plugin.WeChat
|
||||||
AgentId = AgentId
|
AgentId = AgentId
|
||||||
}))?.Id;
|
}))?.Id;
|
||||||
|
|
||||||
var result = await conversationService.SendMessage(AgentId, new RoleDialogModel("user", message), async msg =>
|
var result = await conversationService.SendMessage(AgentId,
|
||||||
{
|
new RoleDialogModel("user", message),
|
||||||
await ReplyTextMessageAsync(openid, msg.Content);
|
replyMessage: null,
|
||||||
}, async functionExecuting =>
|
async msg =>
|
||||||
{
|
{
|
||||||
|
await ReplyTextMessageAsync(openid, msg.Content);
|
||||||
}, async functionExecuted =>
|
},
|
||||||
{
|
_ => Task.CompletedTask,
|
||||||
|
_ => Task.CompletedTask);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<User> GetWeChatAccountUserAsync(string openId, IServiceProvider service)
|
private async Task<User> GetWeChatAccountUserAsync(string openId, IServiceProvider service)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
using BotSharp.Abstraction.Conversations;
|
||||||
|
using BotSharp.Abstraction.Conversations.Models;
|
||||||
|
|
||||||
|
namespace BotSharp.Plugin.PizzaBot.Hooks;
|
||||||
|
|
||||||
|
public class PizzaTypeConversationHook : ConversationHookBase
|
||||||
|
{
|
||||||
|
public override async Task OnPostbackMessageReceived(RoleDialogModel message, PostbackMessageModel replyMsg)
|
||||||
|
{
|
||||||
|
if (replyMsg.FunctionName == "get_pizza_types")
|
||||||
|
{
|
||||||
|
// message.StopCompletion = true;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue