Merge branch 'SciSharp:master' into master

This commit is contained in:
C. Oceania 2024-04-22 18:52:13 -05:00 committed by GitHub
commit c073937682
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
32 changed files with 237 additions and 65 deletions

View file

@ -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}]";
}
}

View file

@ -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>

View file

@ -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;
}

View file

@ -1,7 +1,10 @@
using Newtonsoft.Json;
namespace BotSharp.Abstraction.Messaging;
public interface ITemplateMessage
{
[JsonPropertyName("template_type")]
[JsonProperty("template_type")]
string TemplateType => string.Empty;
}

View file

@ -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)]

View file

@ -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; }
}

View file

@ -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; }
}

View file

@ -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>();
}

View file

@ -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; }
}

View file

@ -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; }
}

View file

@ -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; }
}

View file

@ -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; }
}

View file

@ -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;
}

View file

@ -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;

View file

@ -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);
}

View file

@ -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();

View file

@ -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>

View file

@ -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);
}
}
}

View file

@ -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);

View file

@ -5,7 +5,6 @@ using System.Drawing;
using System.IO;
using System.Reflection;
using System.Xml;
using BotSharp.Abstraction.Repositories;
namespace BotSharp.Core.Plugins;

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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" : "")}");
}
}

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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" ]
}

View file

@ -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" ]
}
}
]

View file

@ -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.

View file

@ -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.

View file

@ -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
});
}
}

View file

@ -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;
}

View file

@ -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
};
}
}