Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,24 @@ public class Conversation

public class DialogElement
{
public DialogMeta MetaData { get; set; }
public DialogMetaData MetaData { get; set; }
public string Content { get; set; }
public string? RichContent { get; set; }

public DialogElement()
{

}

public DialogElement(DialogMeta meta, string content)
public DialogElement(DialogMetaData meta, string content, string? richContent = null)
{
MetaData = meta;
Content = content;
RichContent = richContent;
}
}

public class DialogMeta
public class DialogMetaData
{
public string Role { get; set; }
public string AgentId { get; set; }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace BotSharp.Abstraction.Loggers.Enums;

public static class ContentLogSource
{
public const string UserInput = "user input";
public const string Prompt = "prompt";
public const string FunctionCall = "function call";
public const string AgentResponse = "agent response";
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,19 @@ public class ConversationContentLogModel
{
[JsonPropertyName("conversation_id")]
public string ConversationId { get; set; }

[JsonPropertyName("message_id")]
public string MessageId { get; set; }

[JsonPropertyName("name")]
public string? Name { get; set; }

[JsonPropertyName("role")]
public string Role { get; set; }

[JsonPropertyName("source")]
public string Source { get; set; }

[JsonPropertyName("content")]
public string Content { get; set; }

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using BotSharp.Abstraction.Messaging.Models.RichContent.Template;
using System.Text.Json;

namespace BotSharp.Abstraction.Messaging.JsonConverters;
Expand All @@ -6,7 +7,22 @@ public class RichContentJsonConverter : JsonConverter<IRichMessage>
{
public override IRichMessage? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
throw new NotImplementedException();
using var jsonDoc = JsonDocument.ParseValue(ref reader);
var root = jsonDoc.RootElement;
var jsonText = root.GetRawText();
JsonElement element;
object? res = null;

if (root.TryGetProperty("buttons", out element))
{
res = JsonSerializer.Deserialize<ButtonTemplateMessage>(jsonText, options);
}
else if (root.TryGetProperty("options", out element))
{
res = JsonSerializer.Deserialize<MultiSelectTemplateMessage>(jsonText, options);
}

return res as IRichMessage;
}

public override void Write(Utf8JsonWriter writer, IRichMessage value, JsonSerializerOptions options)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using BotSharp.Abstraction.Messaging.Models.RichContent.Template;
using System.Text.Json;

namespace BotSharp.Abstraction.Messaging.JsonConverters;
Expand All @@ -6,7 +7,22 @@ public class TemplateMessageJsonConverter : JsonConverter<ITemplateMessage>
{
public override ITemplateMessage? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
throw new NotImplementedException();
using var jsonDoc = JsonDocument.ParseValue(ref reader);
var root = jsonDoc.RootElement;
var jsonText = root.GetRawText();
JsonElement element;
object? res = null;

if (root.TryGetProperty("buttons", out element))
{
res = JsonSerializer.Deserialize<ButtonTemplateMessage>(jsonText, options);
}
else if (root.TryGetProperty("options", out element))
{
res = JsonSerializer.Deserialize<MultiSelectTemplateMessage>(jsonText, options);
}

return res as ITemplateMessage;
}

public override void Write(Utf8JsonWriter writer, ITemplateMessage value, JsonSerializerOptions options)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
using BotSharp.Abstraction.Messaging;
using BotSharp.Abstraction.Messaging.JsonConverters;
using BotSharp.Abstraction.Messaging.Models.RichContent;
using BotSharp.Abstraction.Repositories;
using System;
using System.IO;
Expand All @@ -8,12 +11,25 @@ public class ConversationStorage : IConversationStorage
{
private readonly BotSharpDatabaseSettings _dbSettings;
private readonly IServiceProvider _services;
private readonly JsonSerializerOptions _options;

public ConversationStorage(
BotSharpDatabaseSettings dbSettings,
IServiceProvider services)
{
_dbSettings = dbSettings;
_services = services;
_options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
AllowTrailingCommas = true,
Converters =
{
new RichContentJsonConverter(),
new TemplateMessageJsonConverter(),
}
};
}

public void Append(string conversationId, RoleDialogModel dialog)
Expand All @@ -24,7 +40,7 @@ public void Append(string conversationId, RoleDialogModel dialog)

if (dialog.Role == AgentRole.Function)
{
var meta = new DialogMeta
var meta = new DialogMetaData
{
Role = dialog.Role,
AgentId = agentId,
Expand All @@ -42,7 +58,7 @@ public void Append(string conversationId, RoleDialogModel dialog)
}
else
{
var meta = new DialogMeta
var meta = new DialogMetaData
{
Role = dialog.Role,
AgentId = agentId,
Expand All @@ -56,8 +72,8 @@ public void Append(string conversationId, RoleDialogModel dialog)
{
return;
}

dialogElements.Add(new DialogElement(meta, content));
var richContent = dialog.RichContent != null ? JsonSerializer.Serialize(dialog.RichContent, _options) : null;
dialogElements.Add(new DialogElement(meta, content, richContent));
}

db.AppendConversationDialogs(conversationId, dialogElements);
Expand All @@ -80,14 +96,17 @@ public List<RoleDialogModel> GetDialogs(string conversationId)
var function = role == AgentRole.Function ? meta.FunctionName : null;
var senderId = role == AgentRole.Function ? currentAgentId : meta.SenderId;
var createdAt = meta.CreateTime;
var richContent = !string.IsNullOrEmpty(dialog.RichContent) ?
JsonSerializer.Deserialize<RichContent<IRichMessage>>(dialog.RichContent, _options) : null;

var record = new RoleDialogModel(role, content)
{
CurrentAgentId = currentAgentId,
MessageId = messageId,
CreatedAt = createdAt,
SenderId = senderId,
FunctionName = function
FunctionName = function,
RichContent = richContent
};
results.Add(record);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ private List<DialogElement> CollectDialogElements(string dialogDir)
var blocks = rawDialogs[i].Split("|");
var content = rawDialogs[i + 1];
var trimmed = content.Substring(4);
var meta = new DialogMeta
var meta = new DialogMetaData
{
Role = blocks[1],
AgentId = blocks[2],
Expand All @@ -326,7 +326,13 @@ private List<DialogElement> CollectDialogElements(string dialogDir)
SenderId = blocks[1] == AgentRole.Function ? null : blocks[4],
CreateTime = DateTime.Parse(blocks[0])
};
dialogs.Add(new DialogElement(meta, trimmed));

string? richContent = null;
if (blocks.Count() > 5)
{
richContent = blocks[5];
}
dialogs.Add(new DialogElement(meta, trimmed, richContent));
}
}
return dialogs;
Expand All @@ -342,7 +348,7 @@ private List<string> ParseDialogElements(List<DialogElement> dialogs)
var meta = element.MetaData;
var createTime = meta.CreateTime.ToString("MM/dd/yyyy hh:mm:ss.fff tt", CultureInfo.InvariantCulture);
var source = meta.FunctionName ?? meta.SenderId;
var metaStr = $"{createTime}|{meta.Role}|{meta.AgentId}|{meta.MessageId}|{source}";
var metaStr = $"{createTime}|{meta.Role}|{meta.AgentId}|{meta.MessageId}|{source}|{element.RichContent}";
dialogTexts.Add(metaStr);
var content = $" - {element.Content}";
dialogTexts.Add(content);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ public async Task<IEnumerable<ChatResponseModel>> GetDialogs([FromRoute] string
{
FirstName = agent.Name,
Role = message.Role,
}
},
RichContent = message.RichContent
});
}
}
Expand Down
40 changes: 20 additions & 20 deletions src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Functions.Models;
using BotSharp.Abstraction.Loggers;
using BotSharp.Abstraction.Loggers.Enums;
using BotSharp.Abstraction.Loggers.Models;
using BotSharp.Abstraction.Repositories;
using BotSharp.Abstraction.Repositories.Filters;
using BotSharp.Abstraction.Routing.Settings;
using Microsoft.AspNetCore.SignalR;
using Serilog;

namespace BotSharp.Plugin.ChatHub.Hooks;

Expand Down Expand Up @@ -37,11 +37,13 @@ public StreamingLogHook(
AllowTrailingCommas = true
};
}

public override async Task OnMessageReceived(RoleDialogModel message)
{
var conversationId = _state.GetConversationId();
var log = $"MessageId: {message.MessageId} ==>\r\n{message.Role}: {message.Content}";
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", BuildContentLog(conversationId, _user.UserName, log, message));
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated",
BuildContentLog(conversationId, _user.UserName, log, ContentLogSource.UserInput, message));
}

public async Task BeforeGenerating(Agent agent, List<RoleDialogModel> conversations)
Expand All @@ -62,7 +64,8 @@ public override async Task OnFunctionExecuted(RoleDialogModel message)
var agent = await agentService.LoadAgent(message.CurrentAgentId);
var log = $"[{agent?.Name}]: {message.FunctionName}({message.FunctionArgs}) => {message.Content}";
log += $"\r\n<== MessageId: {message.MessageId}";
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", BuildContentLog(conversationId, agent?.Name, log, message));
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated",
BuildContentLog(conversationId, agent?.Name, log, ContentLogSource.FunctionCall, message));
}

/// <summary>
Expand All @@ -78,30 +81,25 @@ public async Task AfterGenerated(RoleDialogModel message, TokenStatsModel tokenS
var agentService = _services.GetRequiredService<IAgentService>();
var conversationId = _state.GetConversationId();
var agent = await agentService.LoadAgent(message.CurrentAgentId);
var logSource = string.Empty;

// Log routing output
try
{
var inst = message.Content.JsonContent<FunctionCallFromLlm>();
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", BuildContentLog(conversationId, agent?.Name, message.Content, message));
logSource = ContentLogSource.AgentResponse;
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated",
BuildContentLog(conversationId, agent?.Name, message.Content, logSource, message));
}
catch
{
// ignore
}

string log;
if (message.Role == AgentRole.Function)
{
log = $"[{agent?.Name}]: {message.FunctionName}({message.FunctionArgs}) => {message.Content}";
log += $"\r\n<== MessageId: {message.MessageId}";
}
else
{
log = tokenStats.Prompt;
}

await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", BuildContentLog(conversationId, agent?.Name, log, message));
var log = tokenStats.Prompt;
logSource = ContentLogSource.Prompt;
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated",
BuildContentLog(conversationId, agent?.Name, log, logSource, message));
}

/// <summary>
Expand All @@ -127,19 +125,21 @@ public override async Task OnResponseGenerated(RoleDialogModel message)
log += $"\r\n{richContent}";
}
log += $"\r\n<== MessageId: {message.MessageId}";
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", BuildContentLog(conv.ConversationId, agent?.Name, log, message));
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated",
BuildContentLog(conv.ConversationId, agent?.Name, log, ContentLogSource.AgentResponse, message));
}
}

private string BuildContentLog(string conversationId, string? name, string content, RoleDialogModel message)
private string BuildContentLog(string conversationId, string? name, string logContent, string logSource, RoleDialogModel message)
{
var log = new ConversationContentLogModel
{
ConversationId = conversationId,
MessageId = message.MessageId,
Name = name,
Role = message.Role,
Content = content,
Content = logContent,
Source = logSource,
CreateTime = DateTime.UtcNow
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ public class ConversationContentLogDocument : MongoBase
public string MessageId { get; set; }
public string? Name { get; set; }
public string Role { get; set; }
public string Source { get; set; }
public string Content { get; set; }
public DateTime CreateTime { get; set; }
}
Loading