2023-09-27 12:51:15 +00:00
using BotSharp.Abstraction.Functions.Models ;
using BotSharp.Abstraction.Routing.Models ;
using System.Drawing ;
using System.Text.RegularExpressions ;
namespace BotSharp.Core.Routing ;
public partial class RoutingService
{
public async Task < FunctionCallFromLlm > GetNextInstruction ( string prompt )
{
2023-10-12 00:59:09 +00:00
var responseRouteToAgent = _settings . EnableReasoning ?
2023-09-27 12:51:15 +00:00
JsonSerializer . Serialize ( new FunctionCallFromLlm ( ) ) :
JsonSerializer . Serialize ( new RoutingArgs
{
2023-10-12 00:59:09 +00:00
Function = "route_to_agent" ,
AgentName = ""
2023-09-27 12:51:15 +00:00
} ) ;
2023-10-12 00:59:09 +00:00
var responseResponseToUser = _settings . EnableReasoning ?
JsonSerializer . Serialize ( new FunctionCallFromLlm ( ) ) :
JsonSerializer . Serialize ( new RoutingArgs
{
Function = "response_to_user" ,
Answer = ""
} ) ;
var content = $"{prompt}\r\nIf need to route to specific agent, output in JSON {responseRouteToAgent}.\r\nIf you can handle the request directly, output in JSON {responseResponseToUser}." ;
2023-09-27 12:51:15 +00:00
2023-10-08 20:46:42 +00:00
var state = _services . GetRequiredService < IConversationStateService > ( ) ;
2023-09-27 12:51:15 +00:00
2023-10-09 22:28:17 +00:00
RoleDialogModel response = default ;
2023-10-10 21:53:04 +00:00
var args = new FunctionCallFromLlm ( ) ;
2023-10-09 22:28:17 +00:00
if ( _settings . UseTextCompletion )
{
var completion = CompletionProvider . GetTextCompletion ( _services ,
provider : _settings . Provider ,
model : _settings . Model ) ;
content = _routerInstance . Router . Instruction + "\r\n\r\n" + content + "\r\nResponse: " ;
2023-10-12 00:59:09 +00:00
int retryCount = 0 ;
while ( retryCount < 3 )
{
try
{
var text = await completion . GetCompletion ( content ) ;
response = new RoleDialogModel ( AgentRole . Assistant , text ) ;
var pattern = @"\{(?:[^{}]|(?<open>\{)|(?<-open>\}))+(?(open)(?!))\}" ;
response . Content = Regex . Match ( response . Content , pattern ) . Value ;
args = JsonSerializer . Deserialize < FunctionCallFromLlm > ( response . Content ) ;
break ;
}
catch ( Exception ex )
{
_logger . LogError ( $"{ex.Message}: {response.Content}" ) ;
args . Function = "response_to_user" ;
args . Answer = ex . Message ;
args . AgentName = _settings . RouterName ;
content + = "\r\nPlease response in JSON format." ;
}
finally
{
retryCount + + ;
}
}
2023-10-09 22:28:17 +00:00
}
else
{
var completion = CompletionProvider . GetChatCompletion ( _services ,
provider : _settings . Provider ,
model : _settings . Model ) ;
2023-10-10 21:53:04 +00:00
int retryCount = 0 ;
while ( retryCount < 3 )
2023-09-27 12:51:15 +00:00
{
2023-10-10 21:53:04 +00:00
try
{
response = completion . GetChatCompletions ( _routerInstance . Router , new List < RoleDialogModel >
{
new RoleDialogModel ( AgentRole . User , content )
} ) ;
var pattern = @"\{(?:[^{}]|(?<open>\{)|(?<-open>\}))+(?(open)(?!))\}" ;
response . Content = Regex . Match ( response . Content , pattern ) . Value ;
args = JsonSerializer . Deserialize < FunctionCallFromLlm > ( response . Content ) ;
break ;
}
catch ( Exception ex )
{
_logger . LogError ( $"{ex.Message}: {response.Content}" ) ;
args . Function = "response_to_user" ;
args . Answer = ex . Message ;
args . AgentName = _settings . RouterName ;
content + = "\r\nPlease response in JSON format." ;
}
finally
{
retryCount + + ;
}
}
2023-10-09 22:28:17 +00:00
}
2023-09-27 12:51:15 +00:00
#if DEBUG
2023-10-10 21:53:04 +00:00
Console . WriteLine ( response . Content , Color . Gray ) ;
2023-09-27 12:51:15 +00:00
#else
2023-10-10 21:53:04 +00:00
_logger . LogInformation ( response . Content ) ;
2023-09-27 12:51:15 +00:00
#endif
2023-10-10 21:53:04 +00:00
// Sometimes it populate malformed Function in Agent name
if ( ! string . IsNullOrEmpty ( args . Function ) & & args . Function = = args . AgentName )
{
args . Function = "route_to_agent" ;
_logger . LogWarning ( $"Captured LLM malformed response" ) ;
2023-09-27 12:51:15 +00:00
}
2023-10-10 21:53:04 +00:00
// Another case of malformed response
var agentService = _services . GetRequiredService < IAgentService > ( ) ;
var agents = await agentService . GetAgents ( ) ;
if ( string . IsNullOrEmpty ( args . AgentName ) & & agents . Select ( x = > x . Name ) . Contains ( args . Function ) )
2023-09-27 12:51:15 +00:00
{
2023-10-10 21:53:04 +00:00
args . AgentName = args . Function ;
args . Function = "route_to_agent" ;
_logger . LogWarning ( $"Captured LLM malformed response" ) ;
2023-09-27 12:51:15 +00:00
}
if ( args . Arguments ! = null )
{
SaveStateByArgs ( args . Arguments ) ;
}
args . Function = args . Function . Split ( '.' ) . Last ( ) ;
#if DEBUG
Console . WriteLine ( $"*** Next Instruction *** {args}" , Color . Green ) ;
#else
_logger . LogInformation ( $"*** Next Instruction *** {args}" ) ;
#endif
return args ;
}
}