Merge from master into add_richCoontent Branch
This commit is contained in:
commit
eb4e0b0187
|
|
@ -1,6 +1,6 @@
|
|||
# Messaging Components
|
||||
|
||||
Conversations are a lot more than simple text messages when you are building a AI chatbot. In addition to text, the `BotSharp`` allows you to send rich-media, like audio, video, and images, and provides a set of structured messaging options in the form of message templates, quick replies, buttons and more. The UI rendering program can render components according to the returned data format.
|
||||
Conversations are a lot more than simple text messages when you are building a AI chatbot. In addition to text, the `BotSharp` allows you to send rich-media, like audio, video, and images, and provides a set of structured messaging options in the form of message templates, quick replies, buttons and more. The UI rendering program can render components according to the returned data format.
|
||||
|
||||
|
||||
## Text Messages
|
||||
|
|
@ -75,7 +75,7 @@ Message templates are structured message formats used for various purposes to pr
|
|||
...
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,36 +1,9 @@
|
|||
using BotSharp.Abstraction.Models;
|
||||
|
||||
namespace BotSharp.Abstraction.Conversations.Models;
|
||||
|
||||
public class IncomingMessageModel
|
||||
public class IncomingMessageModel : MessageConfig
|
||||
{
|
||||
public string Text { get; set; } = string.Empty;
|
||||
|
||||
public virtual string Channel { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Completion Provider
|
||||
/// </summary>
|
||||
[JsonPropertyName("provider")]
|
||||
public virtual string? Provider { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Model name
|
||||
/// </summary>
|
||||
[JsonPropertyName("model")]
|
||||
public virtual string? Model { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// The sampling temperature to use that controls the apparent creativity of generated completions.
|
||||
/// </summary>
|
||||
public float Temperature { get; set; } = 0.5f;
|
||||
|
||||
/// <summary>
|
||||
/// An alternative value to Temperature, called nucleus sampling, that causes
|
||||
/// the model to consider the results of the tokens with probability mass.
|
||||
/// </summary>
|
||||
public float SamplingFactor { get; set; } = 0.5f;
|
||||
|
||||
/// <summary>
|
||||
/// Conversation states from input
|
||||
/// </summary>
|
||||
public List<string> States { get; set; } = new List<string>();
|
||||
public virtual string Channel { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,12 @@
|
|||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Abstraction.Models;
|
||||
|
||||
namespace BotSharp.Abstraction.Conversations.Models;
|
||||
|
||||
public class RoleDialogModel
|
||||
public class RoleDialogModel : ITrackableMessage
|
||||
{
|
||||
public string MessageId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// user, system, assistant, function
|
||||
/// </summary>
|
||||
|
|
@ -36,10 +41,17 @@ public class RoleDialogModel
|
|||
[JsonIgnore(Condition = JsonIgnoreCondition.Always)]
|
||||
public bool StopCompletion { get; set; }
|
||||
|
||||
public FunctionCallFromLlm Instruction { get; set; }
|
||||
|
||||
private RoleDialogModel()
|
||||
{
|
||||
}
|
||||
|
||||
public RoleDialogModel(string role, string text)
|
||||
{
|
||||
Role = role;
|
||||
Content = text;
|
||||
MessageId = Guid.NewGuid().ToString();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ public class FunctionDef
|
|||
{
|
||||
public string Name { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string? Impact { get; set; }
|
||||
public FunctionParametersDef Parameters { get; set; } = new FunctionParametersDef();
|
||||
|
||||
public override string ToString()
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
using BotSharp.Abstraction.Models;
|
||||
|
||||
namespace BotSharp.Abstraction.Instructs.Models;
|
||||
|
||||
public class InstructResult
|
||||
public class InstructResult : ITrackableMessage
|
||||
{
|
||||
public string MessageId { get; set; }
|
||||
public string Text { get; set; }
|
||||
public object Data { get; set; }
|
||||
public ConversationState States { get; set; }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
namespace BotSharp.Abstraction.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Define a message ID to extend message-level applications, such as model fees, token usage, and data collection
|
||||
/// </summary>
|
||||
public interface ITrackableMessage
|
||||
{
|
||||
string MessageId { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
namespace BotSharp.Abstraction.Models;
|
||||
|
||||
public class MessageConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// Completion Provider
|
||||
/// </summary>
|
||||
[JsonPropertyName("provider")]
|
||||
public virtual string? Provider { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Model name
|
||||
/// </summary>
|
||||
[JsonPropertyName("model")]
|
||||
public virtual string? Model { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// The sampling temperature to use that controls the apparent creativity of generated completions.
|
||||
/// </summary>
|
||||
public float Temperature { get; set; } = 0.5f;
|
||||
|
||||
/// <summary>
|
||||
/// An alternative value to Temperature, called nucleus sampling, that causes
|
||||
/// the model to consider the results of the tokens with probability mass.
|
||||
/// </summary>
|
||||
public float SamplingFactor { get; set; } = 0.5f;
|
||||
|
||||
/// <summary>
|
||||
/// Conversation states from input
|
||||
/// </summary>
|
||||
public List<string> States { get; set; } = new List<string>();
|
||||
}
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Abstraction.Models;
|
||||
|
||||
namespace BotSharp.Abstraction.Routing;
|
||||
|
||||
|
|
@ -19,5 +18,5 @@ public interface IRoutingHandler
|
|||
|
||||
void SetDialogs(List<RoleDialogModel> dialogs) { }
|
||||
|
||||
Task<RoleDialogModel> Handle(IRoutingService routing, FunctionCallFromLlm inst);
|
||||
Task<bool> Handle(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ public interface IRoutingService
|
|||
void ResetRecursiveCounter();
|
||||
void RefreshDialogs();
|
||||
Task<FunctionCallFromLlm> GetNextInstruction();
|
||||
Task<RoleDialogModel> InvokeAgent(string agentId);
|
||||
Task<RoleDialogModel> InstructLoop();
|
||||
Task<RoleDialogModel> ExecuteOnce(Agent agent);
|
||||
Task<bool> InvokeAgent(string agentId, RoleDialogModel message);
|
||||
Task<bool> InstructLoop(RoleDialogModel message);
|
||||
Task<bool> ExecuteOnce(Agent agent, RoleDialogModel message);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,11 @@ public class RoutingContext
|
|||
/// </summary>
|
||||
public string IntentName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Agent that can handl user original goal.
|
||||
/// </summary>
|
||||
public string OriginAgentId
|
||||
=> _stack.Last();
|
||||
=> _stack.Where(x => x != _setting.RouterId).Last();
|
||||
|
||||
public string GetCurrentAgentId()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,4 +7,5 @@ global using System.ComponentModel.DataAnnotations;
|
|||
global using System.Text.Json.Serialization;
|
||||
global using BotSharp.Abstraction.Agents.Models;
|
||||
global using BotSharp.Abstraction.Conversations.Models;
|
||||
global using BotSharp.Abstraction.Agents.Enums;
|
||||
global using BotSharp.Abstraction.Agents.Enums;
|
||||
global using BotSharp.Abstraction.Models;
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace BotSharp.Abstraction.Utilities;
|
||||
|
|
@ -27,4 +28,16 @@ public static class StringExtensions
|
|||
{
|
||||
return str1.Equals(str2, option);
|
||||
}
|
||||
|
||||
public static string JsonContent(this string text)
|
||||
{
|
||||
var m = Regex.Match(text, @"\{(?:[^{}]|(?<open>\{)|(?<-open>\}))+(?(open)(?!))\}");
|
||||
return m.Success ? m.Value : "{}";
|
||||
}
|
||||
|
||||
public static T? JsonContent<T>(this string text)
|
||||
{
|
||||
text = JsonContent(text);
|
||||
return JsonSerializer.Deserialize<T>(text);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,18 +4,14 @@ namespace BotSharp.Core.Agents.Services;
|
|||
|
||||
public partial class AgentService
|
||||
{
|
||||
#if !DEBUG
|
||||
[MemoryCache(10 * 60)]
|
||||
#endif
|
||||
[MemoryCache(10 * 60, PerInstanceCache = true)]
|
||||
public async Task<List<Agent>> GetAgents(bool? allowRouting = null)
|
||||
{
|
||||
var agents = _db.GetAgents(allowRouting: allowRouting);
|
||||
return await Task.FromResult(agents);
|
||||
}
|
||||
|
||||
#if !DEBUG
|
||||
[MemoryCache(10 * 60)]
|
||||
#endif
|
||||
[MemoryCache(10 * 60, PerInstanceCache = true)]
|
||||
public async Task<Agent> GetAgent(string id)
|
||||
{
|
||||
var profile = _db.GetAgent(id);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ namespace BotSharp.Core.Conversations.Services;
|
|||
public partial class ConversationService
|
||||
{
|
||||
public async Task<bool> SendMessage(string agentId,
|
||||
RoleDialogModel incoming,
|
||||
RoleDialogModel message,
|
||||
Func<RoleDialogModel, Task> onMessageReceived,
|
||||
Func<RoleDialogModel, Task> onFunctionExecuting,
|
||||
Func<RoleDialogModel, Task> onFunctionExecuted)
|
||||
|
|
@ -18,16 +18,16 @@ public partial class ConversationService
|
|||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
Agent agent = await agentService.LoadAgent(agentId);
|
||||
|
||||
var message = $"Received [{agent.Name}] {incoming.Role}: {incoming.Content}";
|
||||
var content = $"Received [{agent.Name}] {message.Role}: {message.Content}";
|
||||
#if DEBUG
|
||||
Console.WriteLine(message, Color.OrangeRed);
|
||||
Console.WriteLine(content, Color.OrangeRed);
|
||||
#else
|
||||
_logger.LogInformation(message);
|
||||
_logger.LogInformation(content);
|
||||
#endif
|
||||
|
||||
incoming.CurrentAgentId = agent.Id;
|
||||
message.CurrentAgentId = agent.Id;
|
||||
|
||||
_storage.Append(_conversationId, incoming);
|
||||
_storage.Append(_conversationId, message);
|
||||
|
||||
var hooks = _services.GetServices<IConversationHook>().ToList();
|
||||
|
||||
|
|
@ -37,13 +37,13 @@ public partial class ConversationService
|
|||
hook.SetAgent(agent)
|
||||
.SetConversation(conversation);
|
||||
|
||||
await hook.OnMessageReceived(incoming);
|
||||
await hook.OnMessageReceived(message);
|
||||
|
||||
// Interrupted by hook
|
||||
if (incoming.StopCompletion)
|
||||
if (message.StopCompletion)
|
||||
{
|
||||
await onMessageReceived(incoming);
|
||||
_storage.Append(_conversationId, incoming);
|
||||
await onMessageReceived(message);
|
||||
_storage.Append(_conversationId, message);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -52,11 +52,11 @@ public partial class ConversationService
|
|||
var routing = _services.GetRequiredService<IRoutingService>();
|
||||
var settings = _services.GetRequiredService<RoutingSettings>();
|
||||
|
||||
var response = agentId == settings.RouterId ?
|
||||
await routing.InstructLoop() :
|
||||
await routing.ExecuteOnce(agent);
|
||||
var ret = agentId == settings.RouterId ?
|
||||
await routing.InstructLoop(message) :
|
||||
await routing.ExecuteOnce(agent, message);
|
||||
|
||||
await HandleAssistantMessage(response, onMessageReceived);
|
||||
await HandleAssistantMessage(message, onMessageReceived);
|
||||
|
||||
var statistics = _services.GetRequiredService<ITokenStatistics>();
|
||||
statistics.PrintStatistics();
|
||||
|
|
@ -64,7 +64,7 @@ public partial class ConversationService
|
|||
routing.ResetRecursiveCounter();
|
||||
routing.RefreshDialogs();
|
||||
|
||||
return true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
private async Task<Conversation> GetConversationRecord(string agentId)
|
||||
|
|
|
|||
|
|
@ -54,8 +54,6 @@ public partial class ConversationService : IConversationService
|
|||
public async Task<Conversation> NewConversation(Conversation sess)
|
||||
{
|
||||
var db = _services.GetRequiredService<IBotSharpRepository>();
|
||||
var dbSettings = _services.GetRequiredService<BotSharpDatabaseSettings>();
|
||||
var conversationSettings = _services.GetRequiredService<ConversationSetting>();
|
||||
var user = db.GetUserByExternalId(_user.Id);
|
||||
var foundUserId = user?.Id ?? string.Empty;
|
||||
|
||||
|
|
@ -80,11 +78,11 @@ public partial class ConversationService : IConversationService
|
|||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public List<RoleDialogModel> GetDialogHistory(int lastCount = 20)
|
||||
public List<RoleDialogModel> GetDialogHistory(int lastCount = 50)
|
||||
{
|
||||
var dialogs = _storage.GetDialogs(_conversationId);
|
||||
return dialogs
|
||||
.Where(x => x.CreatedAt > DateTime.UtcNow.AddHours(-8))
|
||||
.Where(x => x.CreatedAt > DateTime.UtcNow.AddHours(-24))
|
||||
.TakeLast(lastCount)
|
||||
.ToList();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,19 +6,13 @@ namespace BotSharp.Core.Conversations.Services;
|
|||
public class ConversationStorage : IConversationStorage
|
||||
{
|
||||
private readonly BotSharpDatabaseSettings _dbSettings;
|
||||
private readonly AgentSettings _agentSettings;
|
||||
private readonly IServiceProvider _services;
|
||||
private readonly IUserIdentity _user;
|
||||
public ConversationStorage(
|
||||
BotSharpDatabaseSettings dbSettings,
|
||||
AgentSettings agentSettings,
|
||||
IServiceProvider services,
|
||||
IUserIdentity user)
|
||||
IServiceProvider services)
|
||||
{
|
||||
_dbSettings = dbSettings;
|
||||
_agentSettings = agentSettings;
|
||||
_services = services;
|
||||
_user = user;
|
||||
}
|
||||
|
||||
public void Append(string conversationId, RoleDialogModel dialog)
|
||||
|
|
@ -32,7 +26,7 @@ public class ConversationStorage : IConversationStorage
|
|||
{
|
||||
var args = dialog.FunctionArgs.Replace("\r", " ").Replace("\n", " ").Trim();
|
||||
|
||||
sb.AppendLine($"{dialog.CreatedAt}|{dialog.Role}|{agentId}|{dialog.FunctionName}|{args}");
|
||||
sb.AppendLine($"{dialog.CreatedAt}|{dialog.Role}|{agentId}|{dialog.MessageId}");
|
||||
|
||||
var content = dialog.Content;
|
||||
content = content.Replace("\r", " ").Replace("\n", " ").Trim();
|
||||
|
|
@ -44,9 +38,7 @@ public class ConversationStorage : IConversationStorage
|
|||
}
|
||||
else
|
||||
{
|
||||
var agentName = db.GetAgent(agentId)?.Name;
|
||||
|
||||
sb.AppendLine($"{dialog.CreatedAt}|{dialog.Role}|{agentId}|{agentName}|");
|
||||
sb.AppendLine($"{dialog.CreatedAt}|{dialog.Role}|{agentId}|{dialog.MessageId}");
|
||||
var content = dialog.Content.Replace("\r", " ").Replace("\n", " ").Trim();
|
||||
if (string.IsNullOrEmpty(content))
|
||||
{
|
||||
|
|
@ -73,15 +65,13 @@ public class ConversationStorage : IConversationStorage
|
|||
var createdAt = DateTime.Parse(meta.Split('|')[0]);
|
||||
var role = meta.Split('|')[1];
|
||||
var currentAgentId = meta.Split('|')[2];
|
||||
var funcName = meta.Split('|')[3];
|
||||
var funcArgs= meta.Split('|')[4];
|
||||
var messageId = meta.Split('|')[3];
|
||||
var text = dialog.Substring(4);
|
||||
|
||||
results.Add(new RoleDialogModel(role, text)
|
||||
{
|
||||
CurrentAgentId = currentAgentId,
|
||||
FunctionName = funcName,
|
||||
FunctionArgs = funcArgs,
|
||||
MessageId = messageId,
|
||||
Content = text,
|
||||
CreatedAt = createdAt
|
||||
});
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ public partial class InstructService : IInstructService
|
|||
{
|
||||
return new InstructResult
|
||||
{
|
||||
MessageId = message.MessageId,
|
||||
Text = message.Content
|
||||
};
|
||||
}
|
||||
|
|
@ -42,6 +43,7 @@ public partial class InstructService : IInstructService
|
|||
var result = await completer.GetCompletion(agent.Instruction);
|
||||
var response = new InstructResult
|
||||
{
|
||||
MessageId = message.MessageId,
|
||||
Text = result
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ using BotSharp.Abstraction.Users.Models;
|
|||
using BotSharp.Abstraction.Agents.Models;
|
||||
using MongoDB.Driver;
|
||||
using BotSharp.Abstraction.Routing.Models;
|
||||
using Amazon.Util;
|
||||
|
||||
namespace BotSharp.Core.Repository;
|
||||
|
||||
|
|
@ -373,13 +372,7 @@ public class FileRepository : IBotSharpRepository
|
|||
var functionFile = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir,
|
||||
agentId, "functions.json");
|
||||
|
||||
var functions = new List<string>();
|
||||
foreach (var function in inputFunctions)
|
||||
{
|
||||
functions.Add(JsonSerializer.Serialize(function, _options));
|
||||
}
|
||||
|
||||
var functionText = JsonSerializer.Serialize(functions, _options);
|
||||
var functionText = JsonSerializer.Serialize(inputFunctions, _options);
|
||||
File.WriteAllText(functionFile, functionText);
|
||||
}
|
||||
|
||||
|
|
@ -493,9 +486,6 @@ public class FileRepository : IBotSharpRepository
|
|||
return responses;
|
||||
}
|
||||
|
||||
#if !DEBUG
|
||||
[MemoryCache(10 * 60)]
|
||||
#endif
|
||||
public Agent? GetAgent(string agentId)
|
||||
{
|
||||
var agentDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir);
|
||||
|
|
|
|||
|
|
@ -66,14 +66,11 @@ public class RouteToAgentFn : IFunctionCallback
|
|||
else
|
||||
{
|
||||
message.CurrentAgentId = targetAgent.Id;
|
||||
message.Content = $"Routing to {args.AgentName}";
|
||||
}
|
||||
}
|
||||
|
||||
_context.Push(message.CurrentAgentId);
|
||||
|
||||
// Set default execution data
|
||||
message.Data = JsonSerializer.Deserialize<JsonElement>(message.FunctionArgs);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,18 +26,15 @@ public class ContinueExecuteTaskRoutingHandler : RoutingHandlerBase, IRoutingHan
|
|||
{
|
||||
}
|
||||
|
||||
public async Task<RoleDialogModel> Handle(IRoutingService routing, FunctionCallFromLlm inst)
|
||||
public async Task<bool> Handle(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message)
|
||||
{
|
||||
var db = _services.GetRequiredService<IBotSharpRepository>();
|
||||
var record = db.GetAgents(inst.AgentName).FirstOrDefault();
|
||||
|
||||
var result = new RoleDialogModel(AgentRole.Function, inst.Question)
|
||||
{
|
||||
FunctionName = inst.Function,
|
||||
FunctionArgs = JsonSerializer.Serialize(inst.Arguments),
|
||||
CurrentAgentId = record.Id
|
||||
};
|
||||
message.FunctionName = inst.Function;
|
||||
message.CurrentAgentId = record.Id;
|
||||
message.FunctionArgs = JsonSerializer.Serialize(inst.Arguments);
|
||||
|
||||
return result;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,14 +24,11 @@ public class ConversationEndRoutingHandler : RoutingHandlerBase, IRoutingHandler
|
|||
{
|
||||
}
|
||||
|
||||
public async Task<RoleDialogModel> Handle(IRoutingService routing, FunctionCallFromLlm inst)
|
||||
|
||||
public async Task<bool> Handle(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message)
|
||||
{
|
||||
var result = new RoleDialogModel(AgentRole.Assistant, inst.Response)
|
||||
{
|
||||
CurrentAgentId = _settings.RouterId,
|
||||
FunctionName = inst.Function,
|
||||
Data = inst
|
||||
};
|
||||
message.Content = inst.Response;
|
||||
message.FunctionName = inst.Function;
|
||||
|
||||
var hooks = _services.GetServices<IConversationHook>()
|
||||
.OrderBy(x => x.Priority)
|
||||
|
|
@ -39,9 +36,9 @@ public class ConversationEndRoutingHandler : RoutingHandlerBase, IRoutingHandler
|
|||
|
||||
foreach (var hook in hooks)
|
||||
{
|
||||
await hook.OnConversationEnding(result);
|
||||
await hook.OnConversationEnding(message);
|
||||
}
|
||||
|
||||
return result;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,30 +9,24 @@ public class HumanInterventionNeededHandler : RoutingHandlerBase, IRoutingHandle
|
|||
{
|
||||
public string Name => "human_intervention_needed";
|
||||
|
||||
public string Description => "Reach out to a real human or customer representative.";
|
||||
|
||||
private readonly RoutingSettings _settings;
|
||||
public string Description => "Reach out to human being, customer service or customer representative.";
|
||||
|
||||
public List<NameDesc> Parameters => new List<NameDesc>
|
||||
{
|
||||
new NameDesc("reason", "why need customer service representative (human being)"),
|
||||
new NameDesc("reason", "why need customer service"),
|
||||
new NameDesc("response", "response content to user")
|
||||
};
|
||||
|
||||
public HumanInterventionNeededHandler(IServiceProvider services, ILogger<HumanInterventionNeededHandler> logger, RoutingSettings settings)
|
||||
: base(services, logger, settings)
|
||||
{
|
||||
_settings = settings;
|
||||
|
||||
}
|
||||
|
||||
public async Task<RoleDialogModel> Handle(IRoutingService routing, FunctionCallFromLlm inst)
|
||||
public async Task<bool> Handle(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message)
|
||||
{
|
||||
var result = new RoleDialogModel(AgentRole.Assistant, inst.Response)
|
||||
{
|
||||
CurrentAgentId = _settings.RouterId,
|
||||
FunctionName = inst.Function,
|
||||
Data = inst
|
||||
};
|
||||
message.Role = AgentRole.Assistant;
|
||||
message.Content = inst.Response;
|
||||
|
||||
var hooks = _services.GetServices<IConversationHook>()
|
||||
.OrderBy(x => x.Priority)
|
||||
|
|
@ -40,9 +34,9 @@ public class HumanInterventionNeededHandler : RoutingHandlerBase, IRoutingHandle
|
|||
|
||||
foreach (var hook in hooks)
|
||||
{
|
||||
await hook.OnHumanInterventionNeeded(result);
|
||||
await hook.OnHumanInterventionNeeded(message);
|
||||
}
|
||||
|
||||
return result;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,14 +24,11 @@ public class InterruptTaskExecutionRoutingHandler : RoutingHandlerBase, IRouting
|
|||
{
|
||||
}
|
||||
|
||||
public async Task<RoleDialogModel> Handle(IRoutingService routing, FunctionCallFromLlm inst)
|
||||
public async Task<bool> Handle(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message)
|
||||
{
|
||||
var result = new RoleDialogModel(AgentRole.User, inst.Reason)
|
||||
{
|
||||
FunctionName = inst.Function,
|
||||
StopCompletion = true
|
||||
};
|
||||
message.FunctionName = inst.Function;
|
||||
message.StopCompletion = true;
|
||||
|
||||
return result;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,15 +24,11 @@ public class ResponseToUserRoutingHandler : RoutingHandlerBase, IRoutingHandler
|
|||
{
|
||||
}
|
||||
|
||||
public async Task<RoleDialogModel> Handle(IRoutingService routing, FunctionCallFromLlm inst)
|
||||
public async Task<bool> Handle(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message)
|
||||
{
|
||||
var result = new RoleDialogModel(AgentRole.Assistant, inst.Response)
|
||||
{
|
||||
CurrentAgentId = _settings.RouterId,
|
||||
FunctionName = inst.Function,
|
||||
Data = inst,
|
||||
StopCompletion = true
|
||||
};
|
||||
return result;
|
||||
message.Content = inst.Response;
|
||||
message.StopCompletion = true;
|
||||
message.Role = AgentRole.Assistant;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,14 +27,12 @@ public class RetrieveDataFromAgentRoutingHandler : RoutingHandlerBase, IRoutingH
|
|||
{
|
||||
}
|
||||
|
||||
public async Task<RoleDialogModel> Handle(IRoutingService routing, FunctionCallFromLlm inst)
|
||||
public async Task<bool> Handle(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message)
|
||||
{
|
||||
// Retrieve information from specific agent
|
||||
var db = _services.GetRequiredService<IBotSharpRepository>();
|
||||
var record = db.GetAgents(inst.AgentName).FirstOrDefault();
|
||||
var response = await routing.InvokeAgent(record.Id);
|
||||
|
||||
inst.Response = response.Content;
|
||||
var ret = await routing.InvokeAgent(record.Id, message);
|
||||
|
||||
/*_dialogs.Add(new RoleDialogModel(AgentRole.Assistant, inst.Parameters.Question)
|
||||
{
|
||||
|
|
@ -45,6 +43,7 @@ public class RetrieveDataFromAgentRoutingHandler : RoutingHandlerBase, IRoutingH
|
|||
|
||||
/*_dialogs.Add(new RoleDialogModel(AgentRole.Function, inst.Parameters.Answer)
|
||||
{
|
||||
MessageId = inst.MessageId,
|
||||
FunctionName = inst.Function,
|
||||
FunctionArgs = JsonSerializer.Serialize(inst.Parameters.Arguments),
|
||||
ExecutionResult = inst.Parameters.Answer,
|
||||
|
|
@ -52,11 +51,11 @@ public class RetrieveDataFromAgentRoutingHandler : RoutingHandlerBase, IRoutingH
|
|||
CurrentAgentId = record.Id
|
||||
});*/
|
||||
|
||||
_router.Instruction += $"\r\n{AgentRole.Function}: {response.Content}";
|
||||
_router.Instruction += $"\r\n{AgentRole.Function}: {message.Content}";
|
||||
|
||||
// Got the response from agent, then send to reasoner again to make the decision
|
||||
// inst = await GetNextInstructionFromReasoner($"What's the next step based on user's original goal and function result?");
|
||||
|
||||
return null;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,24 +28,15 @@ public class RouteToAgentRoutingHandler : RoutingHandlerBase, IRoutingHandler
|
|||
{
|
||||
}
|
||||
|
||||
public async Task<RoleDialogModel> Handle(IRoutingService routing, FunctionCallFromLlm inst)
|
||||
public async Task<bool> Handle(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message)
|
||||
{
|
||||
var context = _services.GetRequiredService<RoutingContext>();
|
||||
|
||||
var function = _services.GetServices<IFunctionCallback>().FirstOrDefault(x => x.Name == inst.Function);
|
||||
var message = new RoleDialogModel(AgentRole.Function, inst.Question)
|
||||
{
|
||||
FunctionName = inst.Function,
|
||||
FunctionArgs = JsonSerializer.Serialize(inst),
|
||||
CurrentAgentId = context.GetCurrentAgentId(),
|
||||
};
|
||||
|
||||
message.FunctionArgs = JsonSerializer.Serialize(inst);
|
||||
var ret = await function.Execute(message);
|
||||
|
||||
var result = await routing.InvokeAgent(context.GetCurrentAgentId());
|
||||
// Keep last message data for debug
|
||||
result.Data = result.Data ?? message.Data;
|
||||
result.FunctionName = result.FunctionName ?? message.FunctionName;
|
||||
return result;
|
||||
ret = await routing.InvokeAgent(context.GetCurrentAgentId(), message);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,24 +23,17 @@ public class TaskEndRoutingHandler : RoutingHandlerBase, IRoutingHandler
|
|||
{
|
||||
}
|
||||
|
||||
public async Task<RoleDialogModel> Handle(IRoutingService routing, FunctionCallFromLlm inst)
|
||||
public async Task<bool> Handle(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message)
|
||||
{
|
||||
var result = new RoleDialogModel(AgentRole.Assistant, inst.Response)
|
||||
{
|
||||
CurrentAgentId = _settings.RouterId,
|
||||
FunctionName = inst.Function,
|
||||
Data = inst
|
||||
};
|
||||
|
||||
var hooks = _services.GetServices<IConversationHook>()
|
||||
.OrderBy(x => x.Priority)
|
||||
.ToList();
|
||||
|
||||
foreach (var hook in hooks)
|
||||
{
|
||||
await hook.OnCurrentTaskEnding(result);
|
||||
await hook.OnCurrentTaskEnding(message);
|
||||
}
|
||||
|
||||
return result;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,15 +56,25 @@ public partial class RoutingService
|
|||
model: _settings.Model);
|
||||
|
||||
int retryCount = 0;
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
var dialogs = Dialogs;
|
||||
|
||||
while (retryCount < 3)
|
||||
{
|
||||
try
|
||||
{
|
||||
var conversation = "";
|
||||
foreach (var dialog in _dialogs.TakeLast(20))
|
||||
|
||||
foreach (var dialog in dialogs.TakeLast(50))
|
||||
{
|
||||
conversation += $"{dialog.Role}: {dialog.Content}\r\n";
|
||||
var role = dialog.Role;
|
||||
if (role != AgentRole.User)
|
||||
{
|
||||
var agent = await agentService.GetAgent(dialog.CurrentAgentId);
|
||||
role = agent.Name;
|
||||
}
|
||||
|
||||
conversation += $"{role}: {dialog.Content}\r\n";
|
||||
}
|
||||
content = $"{conversation}\r\n###\r\n{content}";
|
||||
|
||||
|
|
@ -73,9 +83,7 @@ public partial class RoutingService
|
|||
new RoleDialogModel(AgentRole.User, content)
|
||||
});
|
||||
|
||||
var pattern = @"\{(?:[^{}]|(?<open>\{)|(?<-open>\}))+(?(open)(?!))\}";
|
||||
response.Content = Regex.Match(response.Content, pattern).Value;
|
||||
args = JsonSerializer.Deserialize<FunctionCallFromLlm>(response.Content);
|
||||
args = response.Content.JsonContent<FunctionCallFromLlm>();
|
||||
break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
@ -113,9 +121,6 @@ public partial class RoutingService
|
|||
return args;
|
||||
}
|
||||
|
||||
#if !DEBUG
|
||||
[MemoryCache(10 * 60)]
|
||||
#endif
|
||||
private string GetNextStepPrompt()
|
||||
{
|
||||
var template = _routerInstance.Router.Templates.First(x => x.Name == "next_step_prompt").Content;
|
||||
|
|
|
|||
|
|
@ -8,13 +8,13 @@ public partial class RoutingService
|
|||
{
|
||||
const int MAXIMUM_RECURSION_DEPTH = 3;
|
||||
private int _currentRecursionDepth = 0;
|
||||
public async Task<RoleDialogModel> InvokeAgent(string agentId)
|
||||
public async Task<bool> InvokeAgent(string agentId, RoleDialogModel message)
|
||||
{
|
||||
_currentRecursionDepth++;
|
||||
if (_currentRecursionDepth > MAXIMUM_RECURSION_DEPTH)
|
||||
{
|
||||
_logger.LogWarning($"Current recursive call depth greater than {MAXIMUM_RECURSION_DEPTH}, which will cause unexpected result.");
|
||||
return Dialogs.Last();
|
||||
return false;
|
||||
}
|
||||
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
|
|
@ -23,50 +23,56 @@ public partial class RoutingService
|
|||
var settings = _services.GetRequiredService<ChatCompletionSetting>();
|
||||
var chatCompletion = CompletionProvider.GetChatCompletion(_services, provider: settings.Provider, model: settings.Model);
|
||||
RoleDialogModel response = chatCompletion.GetChatCompletions(agent, Dialogs);
|
||||
message.Role = response.Role;
|
||||
|
||||
if (response.Role == AgentRole.Function)
|
||||
{
|
||||
return await InvokeFunction(agent, response);
|
||||
message.FunctionName = response.FunctionName;
|
||||
message.FunctionArgs = response.FunctionArgs;
|
||||
|
||||
await InvokeFunction(agent, message);
|
||||
}
|
||||
else
|
||||
{
|
||||
return response;
|
||||
message.Content = response.Content;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private async Task<RoleDialogModel> InvokeFunction(Agent agent, RoleDialogModel response)
|
||||
private async Task<RoleDialogModel> InvokeFunction(Agent agent, RoleDialogModel message)
|
||||
{
|
||||
// execute function
|
||||
// Save states
|
||||
SaveStateByArgs(JsonSerializer.Deserialize<JsonDocument>(response.FunctionArgs));
|
||||
SaveStateByArgs(JsonSerializer.Deserialize<JsonDocument>(message.FunctionArgs));
|
||||
|
||||
var conversationService = _services.GetRequiredService<IConversationService>();
|
||||
// Call functions
|
||||
await conversationService.CallFunctions(response);
|
||||
await conversationService.CallFunctions(message);
|
||||
|
||||
Dialogs.Add(response);
|
||||
Dialogs.Add(message);
|
||||
|
||||
// Pass execution result to LLM to get response
|
||||
if (!response.StopCompletion)
|
||||
if (!message.StopCompletion)
|
||||
{
|
||||
// Find response template
|
||||
var templateService = _services.GetRequiredService<IResponseTemplateService>();
|
||||
var responseTemplate = await templateService.RenderFunctionResponse(agent.Id, response);
|
||||
var responseTemplate = await templateService.RenderFunctionResponse(agent.Id, message);
|
||||
if (!string.IsNullOrEmpty(responseTemplate))
|
||||
{
|
||||
response.Role = AgentRole.Assistant;
|
||||
response.Content = responseTemplate.Trim();
|
||||
message.Role = AgentRole.Assistant;
|
||||
message.Content = responseTemplate.Trim();
|
||||
}
|
||||
else
|
||||
{
|
||||
response = await InvokeAgent(response.CurrentAgentId);
|
||||
await InvokeAgent(message.CurrentAgentId, message);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
response.Role = AgentRole.Assistant;
|
||||
message.Role = AgentRole.Assistant;
|
||||
}
|
||||
|
||||
return response;
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,38 +46,29 @@ public partial class RoutingService : IRoutingService
|
|||
_routerInstance = routerInstance;
|
||||
}
|
||||
|
||||
|
||||
public async Task<RoleDialogModel> ExecuteOnce(Agent agent)
|
||||
public async Task<bool> ExecuteOnce(Agent agent, RoleDialogModel message)
|
||||
{
|
||||
var message = Dialogs.Last().Content;
|
||||
|
||||
var handlers = _services.GetServices<IRoutingHandler>();
|
||||
|
||||
var handler = handlers.FirstOrDefault(x => x.Name == "route_to_agent");
|
||||
handler.SetDialogs(Dialogs);
|
||||
|
||||
var result = await handler.Handle(this, new FunctionCallFromLlm
|
||||
{
|
||||
Function = "route_to_agent",
|
||||
Question = message,
|
||||
Reason = message,
|
||||
Question = message.Content,
|
||||
Reason = message.Content,
|
||||
AgentName = agent.Name
|
||||
});
|
||||
}, message);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<RoleDialogModel> InstructLoop()
|
||||
public async Task<bool> InstructLoop(RoleDialogModel message)
|
||||
{
|
||||
_routerInstance.Load();
|
||||
var router = _routerInstance.Router;
|
||||
|
||||
var result = new RoleDialogModel(AgentRole.Assistant, "Can you repeat your request again?")
|
||||
{
|
||||
CurrentAgentId = router.Id
|
||||
};
|
||||
|
||||
var message = Dialogs.Last().Content;
|
||||
|
||||
var handlers = _services.GetServices<IRoutingHandler>();
|
||||
|
||||
int loopCount = 0;
|
||||
|
|
@ -87,7 +78,8 @@ public partial class RoutingService : IRoutingService
|
|||
loopCount++;
|
||||
|
||||
var inst = await GetNextInstruction();
|
||||
inst.Question = inst.Question ?? message;
|
||||
message.Instruction = inst;
|
||||
inst.Question = message.Content;
|
||||
|
||||
var handler = handlers.FirstOrDefault(x => x.Name == inst.Function);
|
||||
if (handler == null)
|
||||
|
|
@ -98,12 +90,18 @@ public partial class RoutingService : IRoutingService
|
|||
handler.SetRouter(router);
|
||||
handler.SetDialogs(Dialogs);
|
||||
|
||||
result = await handler.Handle(this, inst);
|
||||
message.FunctionName = inst.Function;
|
||||
message.Role = AgentRole.Function;
|
||||
message.FunctionArgs = inst.Arguments == null ? "{}" : JsonSerializer.Serialize(inst.Arguments);
|
||||
|
||||
await handler.Handle(this, inst, message);
|
||||
|
||||
inst.Response = message.Content;
|
||||
|
||||
stop = !_settings.EnableReasoning;
|
||||
}
|
||||
|
||||
return result;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void SaveStateByArgs(JsonDocument args)
|
||||
|
|
|
|||
|
|
@ -35,6 +35,10 @@ public class ResponseTemplateService : IResponseTemplateService
|
|||
// Convert args and execute data to dictionary
|
||||
var dict = new Dictionary<string, object>();
|
||||
|
||||
// Populate states
|
||||
var state = _services.GetRequiredService<IConversationStateService>();
|
||||
state.GetStates().Select(x => dict[x.Key] = x.Value).ToList();
|
||||
|
||||
if (message.FunctionArgs != null)
|
||||
{
|
||||
ExtractArgs(JsonSerializer.Deserialize<JsonDocument>(message.FunctionArgs), dict);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using BotSharp.Abstraction.ApiAdapters;
|
||||
using BotSharp.Abstraction.Conversations.Models;
|
||||
using BotSharp.Abstraction.Models;
|
||||
using BotSharp.OpenAPI.ViewModels.Conversations;
|
||||
|
||||
namespace BotSharp.OpenAPI.Controllers;
|
||||
|
|
@ -19,15 +20,17 @@ public class ConversationController : ControllerBase, IApiAdapter
|
|||
}
|
||||
|
||||
[HttpPost("/conversation/{agentId}")]
|
||||
public async Task<ConversationViewModel> NewConversation([FromRoute] string agentId)
|
||||
public async Task<ConversationViewModel> NewConversation([FromRoute] string agentId, [FromBody] MessageConfig config)
|
||||
{
|
||||
var service = _services.GetRequiredService<IConversationService>();
|
||||
var sess = new Conversation
|
||||
var conv = new Conversation
|
||||
{
|
||||
AgentId = agentId
|
||||
};
|
||||
sess = await service.NewConversation(sess);
|
||||
return ConversationViewModel.FromSession(sess);
|
||||
conv = await service.NewConversation(conv);
|
||||
config.States.ForEach(x => conv.States[x.Split('=')[0]] = x.Split('=')[1]);
|
||||
|
||||
return ConversationViewModel.FromSession(conv);
|
||||
}
|
||||
|
||||
[HttpDelete("/conversation/{agentId}/{conversationId}")]
|
||||
|
|
@ -50,13 +53,11 @@ public class ConversationController : ControllerBase, IApiAdapter
|
|||
.SetState("sampling_factor", input.SamplingFactor);
|
||||
|
||||
var response = new MessageResponseModel();
|
||||
var stackMsg = new List<RoleDialogModel>();
|
||||
|
||||
await conv.SendMessage(agentId,
|
||||
new RoleDialogModel("user", input.Text),
|
||||
var inputMsg = new RoleDialogModel("user", input.Text);
|
||||
await conv.SendMessage(agentId, inputMsg,
|
||||
async msg =>
|
||||
{
|
||||
stackMsg.Add(msg);
|
||||
|
||||
},
|
||||
async fnExecuting =>
|
||||
{
|
||||
|
|
@ -64,15 +65,14 @@ public class ConversationController : ControllerBase, IApiAdapter
|
|||
},
|
||||
async fnExecuted =>
|
||||
{
|
||||
response.Function = fnExecuted.FunctionName;
|
||||
response.Data = fnExecuted.Data;
|
||||
response.RichContent = fnExecuted.RichContent;
|
||||
|
||||
});
|
||||
|
||||
response.Text = string.Join("\r\n", stackMsg.Select(x => x.Content));
|
||||
response.Data = response.Data ?? stackMsg.Last().Data;
|
||||
response.Function = stackMsg.Last().FunctionName;
|
||||
response.RichContent = response.RichContent ?? stackMsg.Last().RichContent;
|
||||
response.MessageId = inputMsg.MessageId;
|
||||
response.Text = inputMsg.Content;
|
||||
response.Data = inputMsg.Data;
|
||||
response.Function = inputMsg.FunctionName;
|
||||
response.Instruction = inputMsg.Instruction;
|
||||
|
||||
return response;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,14 @@
|
|||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Abstraction.Models;
|
||||
using BotSharp.Abstraction.Routing.Models;
|
||||
|
||||
namespace BotSharp.OpenAPI.ViewModels.Conversations;
|
||||
|
||||
public class MessageResponseModel
|
||||
public class MessageResponseModel : ITrackableMessage
|
||||
{
|
||||
public string MessageId { get; set; }
|
||||
public string Text { get; set; }
|
||||
public string Function { get; set; }
|
||||
public object Data { get; set; }
|
||||
public object? RichContent { get; set; }
|
||||
public FunctionCallFromLlm Instruction { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ using BotSharp.Abstraction.Agents.Models;
|
|||
|
||||
namespace BotSharp.Plugin.MongoStorage.Models;
|
||||
|
||||
[BsonIgnoreExtraElements]
|
||||
public class AgentResponseMongoElement
|
||||
{
|
||||
public string Prefix { get; set; }
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ using BotSharp.Abstraction.Agents.Models;
|
|||
|
||||
namespace BotSharp.Plugin.MongoStorage.Models;
|
||||
|
||||
[BsonIgnoreExtraElements]
|
||||
public class AgentTemplateMongoElement
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
|
|
|||
|
|
@ -3,10 +3,12 @@ using System.Text.Json;
|
|||
|
||||
namespace BotSharp.Plugin.MongoStorage.Models;
|
||||
|
||||
[BsonIgnoreExtraElements]
|
||||
public class FunctionDefMongoElement
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string? Impact { get; set; }
|
||||
public FunctionParametersDefMongoElement Parameters { get; set; } = new FunctionParametersDefMongoElement();
|
||||
|
||||
public FunctionDefMongoElement()
|
||||
|
|
@ -20,6 +22,7 @@ public class FunctionDefMongoElement
|
|||
{
|
||||
Name = function.Name,
|
||||
Description = function.Description,
|
||||
Impact = function.Impact,
|
||||
Parameters = new FunctionParametersDefMongoElement
|
||||
{
|
||||
Type = function.Parameters.Type,
|
||||
|
|
@ -35,6 +38,7 @@ public class FunctionDefMongoElement
|
|||
{
|
||||
Name = mongoFunction.Name,
|
||||
Description = mongoFunction.Description,
|
||||
Impact = mongoFunction.Impact,
|
||||
Parameters = new FunctionParametersDef
|
||||
{
|
||||
Type = mongoFunction.Parameters.Type,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ using BotSharp.Abstraction.Routing.Models;
|
|||
|
||||
namespace BotSharp.Plugin.MongoStorage.Models;
|
||||
|
||||
[BsonIgnoreExtraElements]
|
||||
public class RoutingRuleMongoElement
|
||||
{
|
||||
public string Field { get; set; }
|
||||
|
|
|
|||
|
|
@ -10,4 +10,5 @@ global using BotSharp.Abstraction.Plugins;
|
|||
global using Microsoft.Extensions.Configuration;
|
||||
global using Microsoft.Extensions.DependencyInjection;
|
||||
global using MongoDB.Bson;
|
||||
global using MongoDB.Driver;
|
||||
global using MongoDB.Driver;
|
||||
global using MongoDB.Bson.Serialization.Attributes;
|
||||
|
|
@ -5,6 +5,7 @@
|
|||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<UserSecretsId>4fb8c9df-7975-4926-ba73-46c8ca440691</UserSecretsId>
|
||||
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ You're {{router.name}} ({{router.description}}). Follow these steps to handle us
|
|||
1. Read the [CONVERSATION] content.
|
||||
2. Select a appropriate function from [FUNCTIONS].
|
||||
3. Determine which agent is suitable to handle this conversation.
|
||||
4. Re-think about the selected function or agent is the best choice.
|
||||
5. For agent required arguments, leave it blank if user doesn't provide it.
|
||||
4. Re-think on whether the function you chose matches the reason.
|
||||
5. For agent required arguments, leave it as blank object if user doesn't provide it.
|
||||
|
||||
[FUNCTIONS]
|
||||
{% for handler in routing_handlers %}
|
||||
|
|
|
|||
|
|
@ -1 +1,4 @@
|
|||
What is the next step based on the CONVERSATION? Response must be in appropriate JSON format.
|
||||
What is the next step based on the CONVERSATION?
|
||||
Response must be in appropriate JSON format.
|
||||
Route to the Agent that last handled the conversation if necessary.
|
||||
If user wants to speak to customer service, use function human_intervention_needed.
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
using BotSharp.Abstraction.Conversations.Models;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace BotSharp.Plugin.PizzaBot.Functions;
|
||||
|
||||
|
|
@ -14,6 +15,7 @@ public class GetPizzaPricesFn : IFunctionCallback
|
|||
cheese_unit_price = 3.5,
|
||||
margherita_unit_price = 3.8,
|
||||
};
|
||||
message.Content = JsonSerializer.Serialize(message.Data);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue