Skip to content

Move next step prompt to liquid template. #169

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ public override string ToString()
{
var route = string.IsNullOrEmpty(AgentName) ? "" : $"<Route to {AgentName.ToUpper()} because {Reason}>";

if (string.IsNullOrEmpty(Answer))
if (string.IsNullOrEmpty(Response))
{
return $"[{Function} {route} {JsonSerializer.Serialize(Arguments)}]: {Question}";
}
else
{
return $"[{Function} {route} {JsonSerializer.Serialize(Arguments)}]: {Question} => {Answer}";
return $"[{Function} {route} {JsonSerializer.Serialize(Arguments)}]: {Question} => {Response}";
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,41 @@ public class RoutingArgs
[JsonPropertyName("function")]
public string Function { get; set; }

/// <summary>
/// The reason why you select this function or agent
/// </summary>
[JsonPropertyName("reason")]
public string Reason { get; set; } = "the reason why you select this function or agent";
public string Reason { get; set; } = string.Empty;

[JsonPropertyName("answer")]
public string Answer { get; set; } = "the content of response to user";
/// <summary>
/// The content of replying to user
/// </summary>
[JsonPropertyName("response")]
public string Response { get; set; }

/// <summary>
/// Agent for next action based on user latest response
/// </summary>
[JsonPropertyName("next_action_agent")]
public string AgentName { get; set; } = "agent for next action based on user latest response";
public string AgentName { get; set; }

/// <summary>
/// Agent who can achieve user original goal
/// </summary>
[JsonPropertyName("user_goal_agent")]
public string OriginalAgent { get; set; } = "agent who can achieve user original goal";
public string OriginalAgent { get; set; }

public override string ToString()
{
var route = string.IsNullOrEmpty(AgentName) ? "" : $"<Route to {AgentName.ToUpper()} because {Reason}>";

if (string.IsNullOrEmpty(Answer))
if (string.IsNullOrEmpty(Response))
{
return $"[{Function} {route}]";
}
else
{
return $"[{Function} {route}] => {Answer}";
return $"[{Function} {route}] => {Response}";
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public class ConversationEndRoutingHandler : RoutingHandlerBase, IRoutingHandler
{
public string Name => "conversation_end";

public string Description => "User wants to end the conversation.";
public string Description => "User completed his task and wants to end the conversation.";

public bool IsReasoning => false;

Expand All @@ -19,11 +19,11 @@ public ConversationEndRoutingHandler(IServiceProvider services, ILogger<Conversa

public async Task<RoleDialogModel> Handle(IRoutingService routing, FunctionCallFromLlm inst)
{
var result = new RoleDialogModel(AgentRole.Assistant, inst.Answer)
var result = new RoleDialogModel(AgentRole.Assistant, inst.Response)
{
CurrentAgentId = _settings.RouterId,
FunctionName = inst.Function,
StopCompletion = true
ExecutionData = inst
};
return result;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ public ResponseToUserRoutingHandler(IServiceProvider services, ILogger<ResponseT

public async Task<RoleDialogModel> Handle(IRoutingService routing, FunctionCallFromLlm inst)
{
var result = new RoleDialogModel(AgentRole.Assistant, inst.Answer)
var result = new RoleDialogModel(AgentRole.Assistant, inst.Response)
{
CurrentAgentId = _settings.RouterId,
FunctionName = inst.Function,
ExecutionData = inst,
StopCompletion = true
};
return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public async Task<RoleDialogModel> Handle(IRoutingService routing, FunctionCallF
var record = db.Agents.First(x => x.Name.ToLower() == inst.AgentName.ToLower());
var response = await routing.InvokeAgent(record.Id);

inst.Answer = response.Content;
inst.Response = response.Content;

/*_dialogs.Add(new RoleDialogModel(AgentRole.Assistant, inst.Parameters.Question)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using BotSharp.Abstraction.Functions.Models;
using BotSharp.Abstraction.Routing.Models;
using BotSharp.Abstraction.Templating;
using System.Drawing;
using System.IO;
using System.Text.RegularExpressions;

namespace BotSharp.Core.Routing;
Expand All @@ -9,17 +11,7 @@ public partial class RoutingService
{
public async Task<FunctionCallFromLlm> GetNextInstruction()
{
var prompt = "Which is the next step based on the CONVERSATION? Or you can handle without asking specific agent.";
var responseFormat = _settings.EnableReasoning ?
JsonSerializer.Serialize(new FunctionCallFromLlm()) :
JsonSerializer.Serialize(new RoutingArgs
{
Function = "route_to_agent"
});
var content = $"{prompt} Response must be in JSON format {responseFormat}.";
content += " Set function as conversation_end with courtesy greeting if user is willing to end conversation";

var state = _services.GetRequiredService<IConversationStateService>();
var content = GetNextStepPrompt();

RoleDialogModel response = default;
var args = new FunctionCallFromLlm();
Expand Down Expand Up @@ -50,7 +42,7 @@ public async Task<FunctionCallFromLlm> GetNextInstruction()
{
_logger.LogError($"{ex.Message}: {response.Content}");
args.Function = "response_to_user";
args.Answer = ex.Message;
args.Response = ex.Message;
args.AgentName = "Router";
content += "\r\nPlease response in JSON format.";
}
Expand Down Expand Up @@ -86,7 +78,7 @@ public async Task<FunctionCallFromLlm> GetNextInstruction()
{
_logger.LogError($"{ex.Message}: {response.Content}");
args.Function = "response_to_user";
args.Answer = ex.Message;
args.Response = ex.Message;
args.AgentName = "Router";
content += "\r\nPlease response in JSON format.";
}
Expand Down Expand Up @@ -135,4 +127,24 @@ public async Task<FunctionCallFromLlm> GetNextInstruction()

return args;
}

#if !DEBUG
[MemoryCache(60 * 60)]
#endif
private string GetNextStepPrompt()
{
var agentService = _services.GetRequiredService<IAgentService>();
var agentSettings = _services.GetRequiredService<AgentSettings>();
var filePath = Path.Combine(agentService.GetAgentDataDir(_routerInstance.AgentId), $"next_step_prompt.{agentSettings.TemplateFormat}");
var template = File.ReadAllText(filePath);

// If enabled reasoning
// JsonSerializer.Serialize(new FunctionCallFromLlm());

var render = _services.GetRequiredService<ITemplateRender>();
return render.Render(template, new Dictionary<string, object>
{
{ "enabled_reasoning", false }
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
What is the next step based on the CONVERSATION? Or you can handle without asking specific agent.

Response must be in JSON format
{% if enabled_reasoning -%}
{"function":"route_to_agent"}
{%- else -%}
{"function":"route_to_agent","reason":"the reason why you select this function or agent","response":"content of replying to user","next_action_agent":"agent for next action based on user latest response","user_goal_agent":"agent who can achieve user original goal"}
{%- endif %}

If the user has no other tasks need help with, set function as conversation_end with reason and reply user courteously.