Merge branch 'SciSharp:master' into master
This commit is contained in:
commit
c073937682
|
|
@ -34,23 +34,28 @@ public class DialogElement
|
|||
{
|
||||
public DialogMetaData MetaData { get; set; }
|
||||
public string Content { get; set; }
|
||||
public string? SecondaryContent { get; set; }
|
||||
public string? RichContent { get; set; }
|
||||
public string? SecondaryRichContent { get; set; }
|
||||
|
||||
public DialogElement()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public DialogElement(DialogMetaData meta, string content, string? richContent = null)
|
||||
public DialogElement(DialogMetaData meta, string content, string? richContent = null,
|
||||
string? secondaryContent = null, string? secondaryRichContent = null)
|
||||
{
|
||||
MetaData = meta;
|
||||
Content = content;
|
||||
RichContent = richContent;
|
||||
SecondaryContent = secondaryContent;
|
||||
SecondaryRichContent = secondaryRichContent;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{MetaData.Role}: {Content} [{MetaData.CreateTime}]";
|
||||
return $"{MetaData.Role}: {Content} [{MetaData?.CreateTime}]";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ public class RoleDialogModel : ITrackableMessage
|
|||
|
||||
public string Content { get; set; }
|
||||
|
||||
public string? SecondaryContent { get; set; }
|
||||
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string CurrentAgentId { get; set; }
|
||||
|
||||
|
|
@ -57,6 +59,9 @@ public class RoleDialogModel : ITrackableMessage
|
|||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public RichContent<IRichMessage>? RichContent { get; set; }
|
||||
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public RichContent<IRichMessage>? SecondaryRichContent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Stop conversation completion
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -1,12 +1,15 @@
|
|||
using BotSharp.Abstraction.Messaging.Enums;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BotSharp.Abstraction.Messaging;
|
||||
|
||||
public interface IRichMessage
|
||||
{
|
||||
[JsonPropertyName("text")]
|
||||
[JsonProperty("text")]
|
||||
string Text { get; set; }
|
||||
|
||||
[JsonPropertyName("rich_type")]
|
||||
[JsonProperty("rich_type")]
|
||||
string RichType => RichTypeEnum.Text;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
using Newtonsoft.Json;
|
||||
|
||||
namespace BotSharp.Abstraction.Messaging;
|
||||
|
||||
public interface ITemplateMessage
|
||||
{
|
||||
[JsonPropertyName("template_type")]
|
||||
[JsonProperty("template_type")]
|
||||
string TemplateType => string.Empty;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
using Newtonsoft.Json;
|
||||
using JsonIgnoreAttribute = System.Text.Json.Serialization.JsonIgnoreAttribute;
|
||||
|
||||
namespace BotSharp.Abstraction.Messaging.Models.RichContent;
|
||||
|
||||
public class ElementAction
|
||||
|
|
@ -8,6 +11,7 @@ public class ElementAction
|
|||
public string Url { get; set; }
|
||||
|
||||
[JsonPropertyName("webview_height_ratio")]
|
||||
[JsonProperty("webview_height_ratio")]
|
||||
public string WebViewHeightRatio { get; set; }
|
||||
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
using Newtonsoft.Json;
|
||||
using JsonIgnoreAttribute = System.Text.Json.Serialization.JsonIgnoreAttribute;
|
||||
|
||||
namespace BotSharp.Abstraction.Messaging.Models.RichContent;
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -16,11 +19,14 @@ public class ElementButton
|
|||
public string Payload { get; set; }
|
||||
|
||||
[JsonPropertyName("is_primary")]
|
||||
[JsonProperty("is_primary")]
|
||||
public bool IsPrimary { get; set; }
|
||||
|
||||
[JsonPropertyName("is_secondary")]
|
||||
[JsonProperty("is_secondary")]
|
||||
public bool IsSecondary { get; set; }
|
||||
|
||||
[JsonPropertyName("post_action_disclaimer")]
|
||||
[JsonProperty("post_action_disclaimer")]
|
||||
public string? PostActionDisclaimer { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
using Newtonsoft.Json;
|
||||
using JsonIgnoreAttribute = System.Text.Json.Serialization.JsonIgnoreAttribute;
|
||||
|
||||
namespace BotSharp.Abstraction.Messaging.Models.RichContent;
|
||||
|
||||
public class QuickReplyElement
|
||||
|
|
@ -9,6 +12,7 @@ public class QuickReplyElement
|
|||
public string? Payload { get; set; }
|
||||
|
||||
[JsonPropertyName("image_url")]
|
||||
[JsonProperty("image_url")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string? ImageUrl { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,16 @@
|
|||
using BotSharp.Abstraction.Messaging.Enums;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BotSharp.Abstraction.Messaging.Models.RichContent;
|
||||
|
||||
public class QuickReplyMessage : IRichMessage
|
||||
{
|
||||
[JsonPropertyName("rich_type")]
|
||||
[JsonProperty("rich_type")]
|
||||
public string RichType => RichTypeEnum.QuickReply;
|
||||
public string Text { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("quick_replies")]
|
||||
[JsonProperty("quick_replies")]
|
||||
public List<QuickReplyElement> QuickReplies { get; set; } = new List<QuickReplyElement>();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using BotSharp.Abstraction.Messaging.Enums;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BotSharp.Abstraction.Messaging.Models.RichContent.Template;
|
||||
|
||||
|
|
@ -8,17 +9,22 @@ namespace BotSharp.Abstraction.Messaging.Models.RichContent.Template;
|
|||
public class ButtonTemplateMessage : IRichMessage, ITemplateMessage
|
||||
{
|
||||
[JsonPropertyName("rich_type")]
|
||||
[JsonProperty("rich_type")]
|
||||
public string RichType => RichTypeEnum.ButtonTemplate;
|
||||
|
||||
[JsonPropertyName("text")]
|
||||
[JsonProperty("text")]
|
||||
public string Text { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("template_type")]
|
||||
[JsonProperty("template_type")]
|
||||
public string TemplateType => TemplateTypeEnum.Button;
|
||||
|
||||
[JsonPropertyName("buttons")]
|
||||
[JsonProperty("buttons")]
|
||||
public ElementButton[] Buttons { get; set; } = new ElementButton[0];
|
||||
|
||||
[JsonPropertyName("is_horizontal")]
|
||||
[JsonProperty("is_horizontal")]
|
||||
public bool IsHorizontal { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using BotSharp.Abstraction.Messaging.Enums;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BotSharp.Abstraction.Messaging.Models.RichContent.Template;
|
||||
|
||||
|
|
@ -9,30 +10,40 @@ namespace BotSharp.Abstraction.Messaging.Models.RichContent.Template;
|
|||
public class CouponTemplateMessage : IRichMessage, ITemplateMessage
|
||||
{
|
||||
[JsonPropertyName("rich_type")]
|
||||
[JsonProperty("rich_type")]
|
||||
public string RichType => RichTypeEnum.CouponTemplate;
|
||||
|
||||
[JsonPropertyName("text")]
|
||||
[JsonProperty("text")]
|
||||
public string Text { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string Subtitle { get; set; }
|
||||
|
||||
[JsonPropertyName("template_type")]
|
||||
[JsonProperty("template_type")]
|
||||
public string TemplateType => TemplateTypeEnum.Coupon;
|
||||
|
||||
[JsonPropertyName("coupon_code")]
|
||||
[JsonProperty("coupon_code")]
|
||||
public string CouponCode { get; set; }
|
||||
|
||||
[JsonPropertyName("coupon_url")]
|
||||
[JsonProperty("coupon_url")]
|
||||
public string CouponUrl { get; set; }
|
||||
|
||||
[JsonPropertyName("coupon_url_button_title")]
|
||||
[JsonProperty("coupon_url_button_title")]
|
||||
public string CouponUrlButtonTitle { get; set; } = "Shop now";
|
||||
|
||||
[JsonPropertyName("coupon_pre_message")]
|
||||
[JsonProperty("coupon_pre_message")]
|
||||
public string CouponPreMessage { get; set; } = "Here's a deal just for you!";
|
||||
|
||||
[JsonPropertyName("image_url")]
|
||||
[JsonProperty("image_url")]
|
||||
public string ImageUrl { get; set; }
|
||||
|
||||
[JsonPropertyName("payload")]
|
||||
[JsonProperty("payload")]
|
||||
public string Payload { get; set; }
|
||||
}
|
||||
|
|
@ -1,28 +1,36 @@
|
|||
using BotSharp.Abstraction.Messaging.Enums;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BotSharp.Abstraction.Messaging.Models.RichContent.Template;
|
||||
|
||||
public class GenericTemplateMessage<T> : IRichMessage, ITemplateMessage
|
||||
{
|
||||
[JsonPropertyName("rich_type")]
|
||||
[JsonProperty("rich_type")]
|
||||
public string RichType => RichTypeEnum.GenericTemplate;
|
||||
|
||||
[JsonPropertyName("text")]
|
||||
[JsonProperty("text")]
|
||||
public string Text { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("template_type")]
|
||||
[JsonProperty("template_type")]
|
||||
public virtual string TemplateType { get; set; } = TemplateTypeEnum.Generic;
|
||||
|
||||
[JsonPropertyName("elements")]
|
||||
[JsonProperty("elements")]
|
||||
public List<T> Elements { get; set; } = new List<T>();
|
||||
|
||||
[JsonPropertyName("is_horizontal")]
|
||||
[JsonProperty("is_horizontal")]
|
||||
public bool IsHorizontal { get; set; }
|
||||
|
||||
[JsonPropertyName("is_popup")]
|
||||
[JsonProperty("is_popup")]
|
||||
public bool IsPopup { get; set; }
|
||||
|
||||
[JsonPropertyName("element_type")]
|
||||
[JsonProperty("element_type")]
|
||||
public string ElementType => typeof(T).Name;
|
||||
}
|
||||
|
||||
|
|
@ -30,9 +38,13 @@ public class GenericElement
|
|||
{
|
||||
public string Title { get; set; }
|
||||
public string Subtitle { get; set; }
|
||||
|
||||
[JsonPropertyName("image_url")]
|
||||
[JsonProperty("image_url")]
|
||||
public string ImageUrl { get; set; }
|
||||
|
||||
[JsonPropertyName("default_action")]
|
||||
[JsonProperty("default_action")]
|
||||
public ElementAction DefaultAction { get; set; }
|
||||
public ElementButton[] Buttons { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,28 @@
|
|||
using BotSharp.Abstraction.Messaging.Enums;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BotSharp.Abstraction.Messaging.Models.RichContent.Template;
|
||||
|
||||
public class MultiSelectTemplateMessage : IRichMessage, ITemplateMessage
|
||||
{
|
||||
[JsonPropertyName("rich_type")]
|
||||
[JsonProperty("rich_type")]
|
||||
public string RichType => RichTypeEnum.MultiSelectTemplate;
|
||||
|
||||
[JsonPropertyName("text")]
|
||||
[JsonProperty("text")]
|
||||
public string Text { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("template_type")]
|
||||
[JsonProperty("template_type")]
|
||||
public string TemplateType => TemplateTypeEnum.MultiSelect;
|
||||
|
||||
[JsonPropertyName("options")]
|
||||
[JsonProperty("options")]
|
||||
public List<OptionElement> Options { get; set; } = new List<OptionElement>();
|
||||
|
||||
[JsonPropertyName("is_horizontal")]
|
||||
[JsonProperty("is_horizontal")]
|
||||
public bool IsHorizontal { get; set; }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,20 @@
|
|||
using BotSharp.Abstraction.Messaging.Enums;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BotSharp.Abstraction.Messaging.Models.RichContent.Template;
|
||||
|
||||
public class ProductTemplateMessage : IRichMessage, ITemplateMessage
|
||||
{
|
||||
[JsonPropertyName("rich_type")]
|
||||
[JsonProperty("rich_type")]
|
||||
public string RichType => RichTypeEnum.GenericTemplate;
|
||||
|
||||
[JsonPropertyName("text")]
|
||||
[JsonProperty("text")]
|
||||
public string Text { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("template_type")]
|
||||
[JsonProperty("template_type")]
|
||||
public string TemplateType => TemplateTypeEnum.Product;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
using BotSharp.Abstraction.Messaging.Enums;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BotSharp.Abstraction.Messaging.Models.RichContent;
|
||||
|
||||
public class TextMessage : IRichMessage
|
||||
{
|
||||
[JsonPropertyName("rich_type")]
|
||||
[JsonProperty("rich_type")]
|
||||
public string RichType => RichTypeEnum.Text;
|
||||
|
||||
public string Text { get; set; } = string.Empty;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@ namespace BotSharp.Abstraction.Routing;
|
|||
public interface IRoutingContext
|
||||
{
|
||||
string GetCurrentAgentId();
|
||||
string PreviousAgentId();
|
||||
string FirstGoalAgentId();
|
||||
bool ContainsAgentId(string agentId);
|
||||
string OriginAgentId { get; }
|
||||
string ConversationId { get; }
|
||||
string MessageId { get; }
|
||||
|
|
@ -13,6 +14,7 @@ public interface IRoutingContext
|
|||
int AgentCount { get; }
|
||||
void Push(string agentId, string? reason = null);
|
||||
void Pop(string? reason = null);
|
||||
void PopTo(string agentId, string reason);
|
||||
void Replace(string agentId, string? reason = null);
|
||||
void Empty(string? reason = null);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,13 @@ public class AgentPlugin : IBotSharpPlugin
|
|||
public SettingsMeta Settings =>
|
||||
new SettingsMeta("Agent");
|
||||
|
||||
public string[] AgentIds => new string[]
|
||||
{
|
||||
"01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a",
|
||||
"01e2fc5c-2c89-4ec7-8470-7688608b496c",
|
||||
"01dcc3e5-0af7-49e6-ad7a-a760bd12dc4b"
|
||||
};
|
||||
|
||||
public object GetNewSettingsInstance() =>
|
||||
new AgentSettings();
|
||||
|
||||
|
|
|
|||
|
|
@ -46,6 +46,9 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="data\agents\01dcc3e5-0af7-49e6-ad7a-a760bd12dc4b\agent.json" />
|
||||
<None Remove="data\agents\01dcc3e5-0af7-49e6-ad7a-a760bd12dc4b\functions.json" />
|
||||
<None Remove="data\agents\01dcc3e5-0af7-49e6-ad7a-a760bd12dc4b\instruction.liquid" />
|
||||
<None Remove="data\agents\01e2fc5c-2c89-4ec7-8470-7688608b496c\agent.json" />
|
||||
<None Remove="data\agents\01e2fc5c-2c89-4ec7-8470-7688608b496c\instruction.liquid" />
|
||||
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\agent.json" />
|
||||
|
|
@ -67,6 +70,15 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="data\agents\01dcc3e5-0af7-49e6-ad7a-a760bd12dc4b\agent.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="data\agents\01dcc3e5-0af7-49e6-ad7a-a760bd12dc4b\functions.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="data\agents\01dcc3e5-0af7-49e6-ad7a-a760bd12dc4b\instruction.liquid">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="data\agents\01e2fc5c-2c89-4ec7-8470-7688608b496c\agent.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
|
|
|||
|
|
@ -127,6 +127,8 @@ public class ConversationStateService : IConversationStateService, IDisposable
|
|||
_historyStates = _db.GetConversationStates(conversationId);
|
||||
var dialogs = _db.GetConversationDialogs(conversationId);
|
||||
var userDialogs = dialogs.Where(x => x.MetaData?.Role == AgentRole.User || x.MetaData?.Role == UserRole.Client)
|
||||
.GroupBy(x => x.MetaData?.MessageId)
|
||||
.Select(g => g.First())
|
||||
.OrderBy(x => x.MetaData?.CreateTime)
|
||||
.ToList();
|
||||
var curMsgIndex = userDialogs.FindIndex(x => !string.IsNullOrEmpty(curMsgId) && x.MetaData?.MessageId == curMsgId);
|
||||
|
|
@ -342,9 +344,17 @@ public class ConversationStateService : IConversationStateService, IDisposable
|
|||
{
|
||||
foreach (JsonProperty property in root.EnumerateObject())
|
||||
{
|
||||
if (!string.IsNullOrEmpty(property.Value.ToString()))
|
||||
var propertyValue = property.Value;
|
||||
var stateValue = propertyValue.ToString();
|
||||
if (!string.IsNullOrEmpty(stateValue))
|
||||
{
|
||||
SetState(property.Name, property.Value, source: StateSource.Application);
|
||||
if (propertyValue.ValueKind == JsonValueKind.True ||
|
||||
propertyValue.ValueKind == JsonValueKind.False)
|
||||
{
|
||||
stateValue = stateValue?.ToLower();
|
||||
}
|
||||
|
||||
SetState(property.Name, stateValue, source: StateSource.Application);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ public class ConversationStorage : IConversationStorage
|
|||
{
|
||||
return;
|
||||
}
|
||||
dialogElements.Add(new DialogElement(meta, content));
|
||||
dialogElements.Add(new DialogElement(meta, content, dialog.SecondaryContent));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -71,7 +71,8 @@ public class ConversationStorage : IConversationStorage
|
|||
}
|
||||
|
||||
var richContent = dialog.RichContent != null ? JsonSerializer.Serialize(dialog.RichContent, _options.JsonSerializerOptions) : null;
|
||||
dialogElements.Add(new DialogElement(meta, content, richContent));
|
||||
var secondaryRichContent = dialog.SecondaryRichContent != null ? JsonSerializer.Serialize(dialog.SecondaryRichContent, _options.JsonSerializerOptions) : null;
|
||||
dialogElements.Add(new DialogElement(meta, content, richContent, dialog.SecondaryContent, secondaryRichContent));
|
||||
}
|
||||
|
||||
db.AppendConversationDialogs(conversationId, dialogElements);
|
||||
|
|
@ -88,6 +89,7 @@ public class ConversationStorage : IConversationStorage
|
|||
{
|
||||
var meta = dialog.MetaData;
|
||||
var content = dialog.Content;
|
||||
var secondaryContent = dialog.SecondaryContent;
|
||||
var role = meta.Role;
|
||||
var currentAgentId = meta.AgentId;
|
||||
var messageId = meta.MessageId;
|
||||
|
|
@ -96,6 +98,8 @@ public class ConversationStorage : IConversationStorage
|
|||
var createdAt = meta.CreateTime;
|
||||
var richContent = !string.IsNullOrEmpty(dialog.RichContent) ?
|
||||
JsonSerializer.Deserialize<RichContent<IRichMessage>>(dialog.RichContent, _options.JsonSerializerOptions) : null;
|
||||
var secondaryRichContent = !string.IsNullOrEmpty(dialog.SecondaryRichContent) ?
|
||||
JsonSerializer.Deserialize<RichContent<IRichMessage>>(dialog.SecondaryRichContent, _options.JsonSerializerOptions) : null;
|
||||
|
||||
var record = new RoleDialogModel(role, content)
|
||||
{
|
||||
|
|
@ -104,7 +108,9 @@ public class ConversationStorage : IConversationStorage
|
|||
CreatedAt = createdAt,
|
||||
SenderId = senderId,
|
||||
FunctionName = function,
|
||||
RichContent = richContent
|
||||
RichContent = richContent,
|
||||
SecondaryContent = secondaryContent,
|
||||
SecondaryRichContent = secondaryRichContent,
|
||||
};
|
||||
results.Add(record);
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ using System.Drawing;
|
|||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Xml;
|
||||
using BotSharp.Abstraction.Repositories;
|
||||
|
||||
namespace BotSharp.Core.Plugins;
|
||||
|
||||
|
|
|
|||
|
|
@ -506,11 +506,14 @@ namespace BotSharp.Core.Repository
|
|||
var rawDialogs = File.ReadAllLines(dialogDir);
|
||||
if (!rawDialogs.IsNullOrEmpty())
|
||||
{
|
||||
for (int i = 0; i < rawDialogs.Count(); i += 2)
|
||||
for (int i = 0; i < rawDialogs.Count(); i += 5)
|
||||
{
|
||||
var blocks = rawDialogs[i].Split("|");
|
||||
var content = rawDialogs[i + 1];
|
||||
var trimmed = content.Substring(4);
|
||||
var content = rawDialogs[i + 2];
|
||||
var trimmedContent = content.Substring(4);
|
||||
var secondaryContent = rawDialogs[i + 4];
|
||||
var trimmedSecondaryContent = secondaryContent.Substring(4);
|
||||
|
||||
var meta = new DialogMetaData
|
||||
{
|
||||
Role = blocks[1],
|
||||
|
|
@ -521,8 +524,9 @@ namespace BotSharp.Core.Repository
|
|||
CreateTime = DateTime.Parse(blocks[0])
|
||||
};
|
||||
|
||||
var richContent = blocks.Count() > 6 ? DecodeRichContent(blocks[6]) : null;
|
||||
dialogs.Add(new DialogElement(meta, trimmed, richContent));
|
||||
var richContent = DecodeRichContent(rawDialogs[i + 1]);
|
||||
var secondaryRichContent = DecodeRichContent(rawDialogs[i + 3]);
|
||||
dialogs.Add(new DialogElement(meta, trimmedContent, richContent, trimmedSecondaryContent, secondaryRichContent));
|
||||
}
|
||||
}
|
||||
return dialogs;
|
||||
|
|
@ -538,10 +542,17 @@ namespace BotSharp.Core.Repository
|
|||
var meta = element.MetaData;
|
||||
var createTime = meta.CreateTime.ToString("MM/dd/yyyy hh:mm:ss.ffffff tt", CultureInfo.InvariantCulture);
|
||||
var encodedRichContent = EncodeRichContent(element.RichContent);
|
||||
var metaStr = $"{createTime}|{meta.Role}|{meta.AgentId}|{meta.MessageId}|{meta.SenderId}|{meta.FunctionName}|{encodedRichContent}";
|
||||
var encodedSecondaryRichContent = EncodeRichContent(element.SecondaryRichContent);
|
||||
var metaStr = $"{createTime}|{meta.Role}|{meta.AgentId}|{meta.MessageId}|{meta.SenderId}|{meta.FunctionName}";
|
||||
dialogTexts.Add(metaStr);
|
||||
|
||||
dialogTexts.Add(encodedRichContent);
|
||||
var content = $" - {element.Content}";
|
||||
dialogTexts.Add(content);
|
||||
|
||||
dialogTexts.Add(encodedSecondaryRichContent);
|
||||
var secondaryContent = $" - {element.SecondaryContent}";
|
||||
dialogTexts.Add(secondaryContent);
|
||||
}
|
||||
|
||||
return dialogTexts;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
using BotSharp.Abstraction.Functions;
|
||||
|
||||
namespace BotSharp.Core.Routing.Functions;
|
||||
|
||||
public class HumanInterventionNeededFn : IFunctionCallback
|
||||
{
|
||||
public string Name => "human_intervention_needed";
|
||||
|
||||
private readonly IServiceProvider _services;
|
||||
|
||||
public HumanInterventionNeededFn(IServiceProvider services)
|
||||
{
|
||||
_services = services;
|
||||
}
|
||||
|
||||
public async Task<bool> Execute(RoleDialogModel message)
|
||||
{
|
||||
var hooks = _services.GetServices<IConversationHook>()
|
||||
.OrderBy(x => x.Priority)
|
||||
.ToList();
|
||||
|
||||
foreach (var hook in hooks)
|
||||
{
|
||||
await hook.OnHumanInterventionNeeded(message);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -51,7 +51,7 @@ public partial class RouteToAgentFn : IFunctionCallback
|
|||
var originalAgent = db.GetAgents(filter).FirstOrDefault();
|
||||
if (originalAgent != null)
|
||||
{
|
||||
_context.Push(originalAgent.Id, $"user goal agent{(correctToOriginalAgent ? " & is corrected" : "")}");
|
||||
_context.Push(originalAgent.Id, $"user goal agent{(correctToOriginalAgent ? " " + originalAgent.Name + " & is corrected" : "")}");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,43 +0,0 @@
|
|||
using BotSharp.Abstraction.Routing.Settings;
|
||||
|
||||
namespace BotSharp.Core.Routing.Handlers;
|
||||
|
||||
public class HumanInterventionNeededHandler : RoutingHandlerBase, IRoutingHandler
|
||||
{
|
||||
public string Name => "human_intervention_needed";
|
||||
|
||||
public string Description => "Reach out to human customer service.";
|
||||
|
||||
public List<ParameterPropertyDef> Parameters => new List<ParameterPropertyDef>
|
||||
{
|
||||
new ParameterPropertyDef("reason", "why need customer service"),
|
||||
new ParameterPropertyDef("summary", "the whole conversation summary with important information"),
|
||||
new ParameterPropertyDef("response", "asking user whether to connect with customer service representative")
|
||||
};
|
||||
|
||||
public HumanInterventionNeededHandler(IServiceProvider services, ILogger<HumanInterventionNeededHandler> logger, RoutingSettings settings)
|
||||
: base(services, logger, settings)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public async Task<bool> Handle(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message)
|
||||
{
|
||||
var response = RoleDialogModel.From(message,
|
||||
role: AgentRole.Assistant,
|
||||
content: inst.Response);
|
||||
|
||||
_dialogs.Add(response);
|
||||
|
||||
var hooks = _services.GetServices<IConversationHook>()
|
||||
.OrderBy(x => x.Priority)
|
||||
.ToList();
|
||||
|
||||
foreach (var hook in hooks)
|
||||
{
|
||||
await hook.OnHumanInterventionNeeded(response);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
using BotSharp.Abstraction.Routing.Settings;
|
||||
using BotSharp.Abstraction.Utilities;
|
||||
|
||||
namespace BotSharp.Core.Routing;
|
||||
|
||||
|
|
@ -137,7 +138,18 @@ public class RoutingContext : IRoutingContext
|
|||
}
|
||||
}
|
||||
|
||||
public string PreviousAgentId()
|
||||
public void PopTo(string agentId, string reason)
|
||||
{
|
||||
var currentAgentId = GetCurrentAgentId();
|
||||
while (!string.IsNullOrEmpty(currentAgentId) &&
|
||||
currentAgentId != agentId)
|
||||
{
|
||||
Pop(reason);
|
||||
currentAgentId = GetCurrentAgentId();
|
||||
}
|
||||
}
|
||||
|
||||
public string FirstGoalAgentId()
|
||||
{
|
||||
if (_stack.Count == 1)
|
||||
{
|
||||
|
|
@ -151,6 +163,11 @@ public class RoutingContext : IRoutingContext
|
|||
return string.Empty;
|
||||
}
|
||||
|
||||
public bool ContainsAgentId(string agentId)
|
||||
{
|
||||
return _stack.ToArray().Contains(agentId);
|
||||
}
|
||||
|
||||
public void Replace(string agentId, string? reason = null)
|
||||
{
|
||||
var fromAgent = agentId;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"id": "01dcc3e5-0af7-49e6-ad7a-a760bd12dc4b",
|
||||
"name": "Human Support",
|
||||
"description": "Reach out to human customer service representative.",
|
||||
"type": "task",
|
||||
"createdDateTime": "2024-04-22T10:00:00Z",
|
||||
"updatedDateTime": "2024-04-22T10:00:00Z",
|
||||
"disabled": false,
|
||||
"isPublic": true,
|
||||
"profiles": [ "human" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
[
|
||||
{
|
||||
"name": "human_intervention_needed",
|
||||
"description": "If user wants to speak to human customer service.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"reason": {
|
||||
"type": "string",
|
||||
"description": "why customer needs customer service."
|
||||
},
|
||||
"summary": {
|
||||
"type": "string",
|
||||
"description": "the whole conversation summary with important information"
|
||||
}
|
||||
},
|
||||
"required": [ "reason", "summary" ]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
You are a human customer service connection program.
|
||||
When other AI customer service cannot solve user problems, you know how to call the API to transfer users to human customer service for answers.
|
||||
|
|
@ -10,5 +10,3 @@ Expected user goal agent is {{ expected_user_goal_agent }}.
|
|||
{%- else -%}
|
||||
User goal agent is inferred based on user initial request.
|
||||
{%- endif %}
|
||||
If user wants to speak to human customer service, use function human_intervention_needed.
|
||||
If user wants to or is processing with a specific task that can be handled by agents, respond in appropriate output format defined to let proper agent to handle the task.
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ public class ConversationController : ControllerBase
|
|||
MessageId = message.MessageId,
|
||||
CreatedAt = message.CreatedAt,
|
||||
Text = message.Content,
|
||||
SecondaryText = message.SecondaryContent,
|
||||
Data = message.Data,
|
||||
Sender = UserViewModel.FromUser(user)
|
||||
});
|
||||
|
|
@ -97,6 +98,7 @@ public class ConversationController : ControllerBase
|
|||
MessageId = message.MessageId,
|
||||
CreatedAt = message.CreatedAt,
|
||||
Text = message.Content,
|
||||
SecondaryText = message.SecondaryContent,
|
||||
Function = message.FunctionName,
|
||||
Data = message.Data,
|
||||
Sender = new UserViewModel
|
||||
|
|
@ -104,7 +106,8 @@ public class ConversationController : ControllerBase
|
|||
FirstName = agent.Name,
|
||||
Role = message.Role,
|
||||
},
|
||||
RichContent = message.RichContent
|
||||
RichContent = message.RichContent,
|
||||
SecondaryRichContent = message.SecondaryRichContent
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,9 @@ public class ChatResponseModel : InstructResult
|
|||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public FunctionCallFromLlm? Instruction { get; set; }
|
||||
|
||||
[JsonPropertyName("secondary_text")]
|
||||
public string? SecondaryText { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Rich message for UI rendering
|
||||
/// </summary>
|
||||
|
|
@ -28,6 +31,10 @@ public class ChatResponseModel : InstructResult
|
|||
[JsonPropertyName("rich_content")]
|
||||
public RichContent<IRichMessage>? RichContent { get; set; }
|
||||
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
[JsonPropertyName("secondary_rich_content")]
|
||||
public RichContent<IRichMessage>? SecondaryRichContent { get; set; }
|
||||
|
||||
[JsonPropertyName("created_at")]
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@ public class DialogMongoElement
|
|||
{
|
||||
public DialogMetaDataMongoElement MetaData { get; set; }
|
||||
public string Content { get; set; }
|
||||
public string? SecondaryContent { get; set; }
|
||||
public string? RichContent { get; set; }
|
||||
public string? SecondaryRichContent { get; set; }
|
||||
|
||||
public DialogMongoElement()
|
||||
{
|
||||
|
|
@ -19,7 +21,9 @@ public class DialogMongoElement
|
|||
{
|
||||
MetaData = DialogMetaDataMongoElement.ToMongoElement(dialog.MetaData),
|
||||
Content = dialog.Content,
|
||||
RichContent = dialog.RichContent
|
||||
SecondaryContent = dialog.SecondaryContent,
|
||||
RichContent = dialog.RichContent,
|
||||
SecondaryRichContent = dialog.SecondaryRichContent
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -29,7 +33,9 @@ public class DialogMongoElement
|
|||
{
|
||||
MetaData = DialogMetaDataMongoElement.ToDomainElement(dialog.MetaData),
|
||||
Content = dialog.Content,
|
||||
RichContent = dialog.RichContent
|
||||
SecondaryContent = dialog.SecondaryContent,
|
||||
RichContent = dialog.RichContent,
|
||||
SecondaryRichContent = dialog.SecondaryRichContent
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue