Add user_goal_description to router.
Improve stream log.
This commit is contained in:
parent
2c4af439f4
commit
96bf9d2fa0
|
|
@ -6,6 +6,7 @@ namespace BotSharp.Abstraction.Functions.Models;
|
|||
public class FunctionCallFromLlm : RoutingArgs
|
||||
{
|
||||
[JsonPropertyName("question")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string? Question { get; set; }
|
||||
|
||||
[JsonPropertyName("args")]
|
||||
|
|
@ -29,6 +30,7 @@ public class FunctionCallFromLlm : RoutingArgs
|
|||
/// Conversation summary
|
||||
/// </summary>
|
||||
[JsonPropertyName("summary")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string? Summary { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
|
|
|
|||
|
|
@ -10,13 +10,21 @@ public interface IRoutingHook
|
|||
/// <param name="instruct">routing instruction</param>
|
||||
/// <param name="message">message</param>
|
||||
/// <returns></returns>
|
||||
Task OnRoutingInstructionReceived(FunctionCallFromLlm instruct, RoleDialogModel message);
|
||||
Task OnRoutingInstructionReceived(FunctionCallFromLlm instruct, RoleDialogModel message)
|
||||
=> Task.CompletedTask;
|
||||
|
||||
Task OnAgentEnqueued(string agentId, string preAgentId, string? reason = null);
|
||||
Task OnRoutingInstructionRevised(FunctionCallFromLlm instruct, RoleDialogModel message)
|
||||
=> Task.CompletedTask;
|
||||
|
||||
Task OnAgentDequeued(string agentId, string currentAgentId, string? reason = null);
|
||||
Task OnAgentEnqueued(string agentId, string preAgentId, string? reason = null)
|
||||
=> Task.CompletedTask;
|
||||
|
||||
Task OnAgentReplaced(string fromAgentId, string toAgentId, string? reason = null);
|
||||
Task OnAgentDequeued(string agentId, string currentAgentId, string? reason = null)
|
||||
=> Task.CompletedTask;
|
||||
|
||||
Task OnAgentQueueEmptied(string agentId, string? reason = null);
|
||||
Task OnAgentReplaced(string fromAgentId, string toAgentId, string? reason = null)
|
||||
=> Task.CompletedTask;
|
||||
|
||||
Task OnAgentQueueEmptied(string agentId, string? reason = null)
|
||||
=> Task.CompletedTask;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,13 +8,15 @@ public class RoutingArgs
|
|||
/// <summary>
|
||||
/// The reason why you select this function or agent
|
||||
/// </summary>
|
||||
[JsonPropertyName("reason")]
|
||||
[JsonPropertyName("next_action_reason")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string Reason { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The content of replying to user
|
||||
/// </summary>
|
||||
[JsonPropertyName("response")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string Response { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -31,6 +33,10 @@ public class RoutingArgs
|
|||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string OriginalAgent { get; set; }
|
||||
|
||||
[JsonPropertyName("user_goal_description")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string UserGoal { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var route = string.IsNullOrEmpty(AgentName) ? "" : $"<Route to {AgentName.ToUpper()} because {Reason}>";
|
||||
|
|
|
|||
|
|
@ -58,15 +58,8 @@ public class RouteToAgentFn : IFunctionCallback
|
|||
// Push next action agent
|
||||
if (!string.IsNullOrEmpty(args.AgentName) && args.AgentName.Length < 32)
|
||||
{
|
||||
var db = _services.GetRequiredService<IBotSharpRepository>();
|
||||
var filter = new AgentFilter { AgentName = args.AgentName };
|
||||
var actionAgent = db.GetAgents(filter).FirstOrDefault();
|
||||
if (actionAgent != null)
|
||||
{
|
||||
_context.Push(actionAgent.Id, args.Reason);
|
||||
}
|
||||
|
||||
states.SetState("last_action_agent", args.AgentName, isNeedVersion: true);
|
||||
_context.Push(args.AgentName, args.Reason);
|
||||
states.SetState("next_action_agent", args.AgentName, isNeedVersion: true);
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(args.AgentName))
|
||||
|
|
@ -93,7 +86,7 @@ public class RouteToAgentFn : IFunctionCallback
|
|||
if (missingfield && message.CurrentAgentId != agentId)
|
||||
{
|
||||
// Stack redirection agent
|
||||
_context.Push(agentId, reason: $"redirection: {message.Content}");
|
||||
_context.Push(agentId, reason: $"REDIRECTION {message.Content}");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -155,7 +148,7 @@ public class RouteToAgentFn : IFunctionCallback
|
|||
{
|
||||
// Add field to args
|
||||
message.FunctionArgs = AppendPropertyToArgs(message.FunctionArgs, "missing_fields", missingFields);
|
||||
message.Content = $"missing some information: {string.Join(',', missingFields)}";
|
||||
message.Content = $"missing some information: {string.Join(", ", missingFields)}";
|
||||
|
||||
// Handle redirect
|
||||
var routingRule = routingRules.FirstOrDefault(x => missingFields.Contains(x.Field));
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ public class RouteToAgentRoutingHandler : RoutingHandlerBase, IRoutingHandler
|
|||
|
||||
public List<ParameterPropertyDef> Parameters => new List<ParameterPropertyDef>
|
||||
{
|
||||
new ParameterPropertyDef("reason", "why route to agent")
|
||||
new ParameterPropertyDef("next_action_reason", "the reason why route to this agent")
|
||||
{
|
||||
Required = true
|
||||
},
|
||||
|
|
@ -18,6 +18,10 @@ public class RouteToAgentRoutingHandler : RoutingHandlerBase, IRoutingHandler
|
|||
{
|
||||
Required = true
|
||||
},
|
||||
new ParameterPropertyDef("user_goal_description", "user original goal")
|
||||
{
|
||||
Required = true
|
||||
},
|
||||
new ParameterPropertyDef("user_goal_agent", "agent who can achieve user original goal")
|
||||
{
|
||||
Required = true
|
||||
|
|
@ -38,6 +42,16 @@ public class RouteToAgentRoutingHandler : RoutingHandlerBase, IRoutingHandler
|
|||
message.FunctionArgs = JsonSerializer.Serialize(inst);
|
||||
var ret = await routing.InvokeFunction(message.FunctionName, message);
|
||||
|
||||
var states = _services.GetRequiredService<IConversationStateService>();
|
||||
var goalAgent = states.GetState("user_goal_agent");
|
||||
if (!string.IsNullOrEmpty(goalAgent))
|
||||
{
|
||||
inst.OriginalAgent = goalAgent;
|
||||
}
|
||||
await HookEmitter.Emit<IRoutingHook>(_services, async hook =>
|
||||
await hook.OnRoutingInstructionRevised(inst, message)
|
||||
);
|
||||
|
||||
var agentId = routing.Context.GetCurrentAgentId();
|
||||
|
||||
// Update next action agent's name
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ public class NaivePlanner : IPlaner
|
|||
else
|
||||
{
|
||||
context.Empty(reason: $"Agent queue is cleared by {nameof(NaivePlanner)}");
|
||||
// context.Push(inst.OriginalAgent, "Push user goal agent");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,8 +61,23 @@ public class RoutingContext : IRoutingContext
|
|||
return _stack.Peek();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Push agent
|
||||
/// </summary>
|
||||
/// <param name="agentId">Id or Name</param>
|
||||
/// <param name="reason"></param>
|
||||
public void Push(string agentId, string? reason = null)
|
||||
{
|
||||
// Convert id to name
|
||||
if (!Guid.TryParse(agentId, out _))
|
||||
{
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
agentId = agentService.GetAgents(new AgentFilter
|
||||
{
|
||||
AgentName = agentId
|
||||
}).Result.Items.First().Id;
|
||||
}
|
||||
|
||||
if (_stack.Count == 0 || _stack.Peek() != agentId)
|
||||
{
|
||||
var preAgentId = _stack.Count == 0 ? agentId : _stack.Peek();
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook, IR
|
|||
PropertyNameCaseInsensitive = true,
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
AllowTrailingCommas = true,
|
||||
WriteIndented = true
|
||||
WriteIndented = true,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -66,6 +66,11 @@ public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook, IR
|
|||
|
||||
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 ?? "{}";
|
||||
|
|
@ -128,6 +133,11 @@ public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook, IR
|
|||
log += $"\r\n```json\r\n{richContent}\r\n```";
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(message.FunctionName))
|
||||
{
|
||||
log += $"\r\n\r\n**{message.FunctionName}**";
|
||||
}
|
||||
|
||||
var input = new ContentLogInputModel(conv.ConversationId, message)
|
||||
{
|
||||
Name = agent?.Name,
|
||||
|
|
@ -223,7 +233,7 @@ public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook, IR
|
|||
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", BuildContentLog(input));
|
||||
}
|
||||
|
||||
public async Task OnRoutingInstructionReceived(FunctionCallFromLlm instruct, RoleDialogModel message)
|
||||
public async Task OnRoutingInstructionRevised(FunctionCallFromLlm instruct, RoleDialogModel message)
|
||||
{
|
||||
var conversationId = _state.GetConversationId();
|
||||
var agent = await _agentService.LoadAgent(message.CurrentAgentId);
|
||||
|
|
|
|||
Loading…
Reference in a new issue