Merge pull request #327 from iceljc/features/add-log-agent-id

refine content log input
This commit is contained in:
C. Oceania 2024-02-29 23:48:55 -06:00 committed by GitHub
commit 5b7e2c64c2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 193 additions and 107 deletions

View file

@ -15,7 +15,7 @@ public interface IConversationService
Task<List<Conversation>> GetLastConversations();
Task<bool> DeleteConversation(string id);
Task<bool> TruncateConversation(string conversationId, string messageId);
Task<List<ConversationContentLogModel>> GetConversationContentLogs(string conversationId);
Task<List<ContentLogOutputModel>> GetConversationContentLogs(string conversationId);
Task<List<ConversationStateLogModel>> GetConversationStateLogs(string conversationId);
/// <summary>

View file

@ -0,0 +1,22 @@
namespace BotSharp.Abstraction.Loggers.Models;
public class ContentLogInputModel
{
public string ConversationId { get; set; }
public string? Name { get; set; }
public string? AgentId { get; set; }
public string Log { get; set; }
public string Source { get; set; }
public RoleDialogModel Message { get; set; }
public ContentLogInputModel()
{
}
public ContentLogInputModel(string conversationId, RoleDialogModel message)
{
ConversationId = conversationId;
Message = message;
}
}

View file

@ -1,6 +1,6 @@
namespace BotSharp.Abstraction.Loggers.Models;
public class ConversationContentLogModel
public class ContentLogOutputModel
{
[JsonPropertyName("conversation_id")]
public string ConversationId { get; set; }
@ -11,6 +11,9 @@ public class ConversationContentLogModel
[JsonPropertyName("name")]
public string? Name { get; set; }
[JsonPropertyName("agent_id")]
public string? AgentId { get; set; }
[JsonPropertyName("role")]
public string Role { get; set; }

View file

@ -72,8 +72,8 @@ public interface IBotSharpRepository
#endregion
#region Conversation Content Log
void SaveConversationContentLog(ConversationContentLogModel log);
List<ConversationContentLogModel> GetConversationContentLogs(string conversationId);
void SaveConversationContentLog(ContentLogOutputModel log);
List<ContentLogOutputModel> GetConversationContentLogs(string conversationId);
#endregion
#region Conversation State Log

View file

@ -5,7 +5,7 @@ namespace BotSharp.Core.Conversations.Services;
public partial class ConversationService
{
public async Task<List<ConversationContentLogModel>> GetConversationContentLogs(string conversationId)
public async Task<List<ContentLogOutputModel>> GetConversationContentLogs(string conversationId)
{
var db = _services.GetRequiredService<IBotSharpRepository>();
var logs = db.GetConversationContentLogs(conversationId);

View file

@ -257,12 +257,12 @@ public class BotSharpDbContext : Database, IBotSharpRepository
#endregion
#region Conversation Content Log
public void SaveConversationContentLog(ConversationContentLogModel log)
public void SaveConversationContentLog(ContentLogOutputModel log)
{
throw new NotImplementedException();
}
public List<ConversationContentLogModel> GetConversationContentLogs(string conversationId)
public List<ContentLogOutputModel> GetConversationContentLogs(string conversationId)
{
throw new NotImplementedException();
}

View file

@ -409,7 +409,7 @@ namespace BotSharp.Core.Repository
foreach (var file in Directory.GetFiles(contentLogDir))
{
var text = File.ReadAllText(file);
var log = JsonSerializer.Deserialize<ConversationContentLogModel>(text);
var log = JsonSerializer.Deserialize<ContentLogOutputModel>(text);
if (log == null) continue;
if (log.CreateTime >= refTime)

View file

@ -63,7 +63,7 @@ namespace BotSharp.Core.Repository
#endregion
#region Conversation Content Log
public void SaveConversationContentLog(ConversationContentLogModel log)
public void SaveConversationContentLog(ContentLogOutputModel log)
{
if (log == null) return;
@ -88,9 +88,9 @@ namespace BotSharp.Core.Repository
File.WriteAllText(file, JsonSerializer.Serialize(log, _options));
}
public List<ConversationContentLogModel> GetConversationContentLogs(string conversationId)
public List<ContentLogOutputModel> GetConversationContentLogs(string conversationId)
{
var logs = new List<ConversationContentLogModel>();
var logs = new List<ContentLogOutputModel>();
if (string.IsNullOrEmpty(conversationId)) return logs;
var convDir = FindConversationDirectory(conversationId);
@ -102,7 +102,7 @@ namespace BotSharp.Core.Repository
foreach (var file in Directory.GetFiles(logDir))
{
var text = File.ReadAllText(file);
var log = JsonSerializer.Deserialize<ConversationContentLogModel>(text);
var log = JsonSerializer.Deserialize<ContentLogOutputModel>(text);
if (log == null) continue;
logs.Add(log);

View file

@ -37,7 +37,7 @@ public class LoggerController : ControllerBase
}
[HttpGet("/logger/conversation/{conversationId}/content-log")]
public async Task<List<ConversationContentLogModel>> GetConversationContentLogs([FromRoute] string conversationId)
public async Task<List<ContentLogOutputModel>> GetConversationContentLogs([FromRoute] string conversationId)
{
var conversationService = _services.GetRequiredService<IConversationService>();
return await conversationService.GetConversationContentLogs(conversationId);

View file

@ -49,19 +49,19 @@ public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook, IR
{
var conversationId = _state.GetConversationId();
var log = $"{message.Content}";
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated",
BuildContentLog(conversationId, _user.UserName, log, ContentLogSource.UserInput, message));
var input = new ContentLogInputModel(conversationId, message)
{
Name = _user.UserName,
Source = ContentLogSource.UserInput,
Log = log
};
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", BuildContentLog(input));
}
public async Task BeforeGenerating(Agent agent, List<RoleDialogModel> conversations)
{
if (!_convSettings.ShowVerboseLog) return;
/*var _state = _services.GetRequiredService<IConversationStateService>();
var conversationId = _state.GetConversationId();
var dialog = conversations.Last();
var log = $"{dialog.Role}: {dialog.Content} [msg_id: {dialog.MessageId}] ==>";
await _chatHub.Clients.User(_user.Id).SendAsync("OnContentLogGenerated", BuildLog(conversationId, log));*/
}
public override async Task OnFunctionExecuted(RoleDialogModel message)
@ -69,8 +69,15 @@ public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook, IR
var conversationId = _state.GetConversationId();
var agent = await _agentService.LoadAgent(message.CurrentAgentId);
var log = $"{message.FunctionName}({message.FunctionArgs})\r\n => {message.Content}";
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated",
BuildContentLog(conversationId, agent?.Name, log, ContentLogSource.FunctionCall, message));
var input = new ContentLogInputModel(conversationId, message)
{
Name = agent?.Name,
AgentId = agent?.Id,
Source = ContentLogSource.FunctionCall,
Log = log
};
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", BuildContentLog(input));
}
/// <summary>
@ -87,8 +94,15 @@ public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook, IR
var agent = await _agentService.LoadAgent(message.CurrentAgentId);
var log = tokenStats.Prompt;
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated",
BuildContentLog(conversationId, agent?.Name, log, ContentLogSource.Prompt, message));
var input = new ContentLogInputModel(conversationId, message)
{
Name = agent?.Name,
AgentId = agent?.Id,
Source = ContentLogSource.Prompt,
Log = log
};
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", BuildContentLog(input));
}
/// <summary>
@ -111,31 +125,141 @@ public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook, IR
var richContent = JsonSerializer.Serialize(message.RichContent, _serializerOptions);
log += $"\r\n{richContent}";
}
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated",
BuildContentLog(conv.ConversationId, agent?.Name, log, ContentLogSource.AgentResponse, message));
var input = new ContentLogInputModel(conv.ConversationId, message)
{
Name = agent?.Name,
AgentId = agent?.Id,
Source = ContentLogSource.AgentResponse,
Log = log
};
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", BuildContentLog(input));
}
}
private string BuildContentLog(string conversationId, string? name, string logContent, string logSource, RoleDialogModel message)
#region IRoutingHook
public async Task OnAgentEnqueued(string agentId, string preAgentId, string? reason = null)
{
var log = new ConversationContentLogModel
var conversationId = _state.GetConversationId();
var agent = await _agentService.LoadAgent(agentId);
var preAgent = await _agentService.LoadAgent(preAgentId);
var log = $"{agent.Name} is enqueued{(reason != null ? $" ({reason})" : "")}";
var message = new RoleDialogModel(AgentRole.System, log)
{
ConversationId = conversationId,
MessageId = message.MessageId,
Name = name,
Role = message.Role,
Content = logContent,
Source = logSource,
MessageId = _routingCtx.MessageId
};
var input = new ContentLogInputModel(conversationId, message)
{
Name = "Router",
Source = ContentLogSource.HardRule,
Log = log
};
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", BuildContentLog(input));
}
public async Task OnAgentDequeued(string agentId, string currentAgentId, string? reason = null)
{
var conversationId = _state.GetConversationId();
var agent = await _agentService.LoadAgent(agentId);
var currentAgent = await _agentService.LoadAgent(currentAgentId);
var log = $"{agent.Name} is dequeued{(reason != null ? $" ({reason})" : "")}, current agent is {currentAgent?.Name}";
var message = new RoleDialogModel(AgentRole.System, log)
{
MessageId = _routingCtx.MessageId
};
var input = new ContentLogInputModel(conversationId, message)
{
Name = "Router",
Source = ContentLogSource.HardRule,
Log = log
};
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", BuildContentLog(input));
}
public async Task OnAgentReplaced(string fromAgentId, string toAgentId, string? reason = null)
{
var conversationId = _state.GetConversationId();
var fromAgent = await _agentService.LoadAgent(fromAgentId);
var toAgent = await _agentService.LoadAgent(toAgentId);
var log = $"{fromAgent.Name} is replaced to {toAgent.Name}{(reason != null ? $" ({reason})" : "")}";
var message = new RoleDialogModel(AgentRole.System, log)
{
MessageId = _routingCtx.MessageId
};
var input = new ContentLogInputModel(conversationId, message)
{
Name = "Router",
Source = ContentLogSource.HardRule,
Log = log
};
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", BuildContentLog(input));
}
public async Task OnAgentQueueEmptied(string agentId, string? reason = null)
{
var conversationId = _state.GetConversationId();
var agent = await _agentService.LoadAgent(agentId);
var log = reason ?? "Agent queue is cleared";
var message = new RoleDialogModel(AgentRole.System, log)
{
MessageId = _routingCtx.MessageId
};
var input = new ContentLogInputModel(conversationId, message)
{
Name = "Router",
Source = ContentLogSource.HardRule,
Log = log
};
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", BuildContentLog(input));
}
public async Task OnRoutingInstructionReceived(FunctionCallFromLlm instruct, RoleDialogModel message)
{
var conversationId = _state.GetConversationId();
var agent = await _agentService.LoadAgent(message.CurrentAgentId);
var log = JsonSerializer.Serialize(instruct, _serializerOptions);
var input = new ContentLogInputModel(conversationId, message)
{
Name = agent?.Name,
AgentId = agent?.Id,
Source = ContentLogSource.AgentResponse,
Log = log
};
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", BuildContentLog(input));
}
#endregion
private string BuildContentLog(ContentLogInputModel input)
{
var output = new ContentLogOutputModel
{
ConversationId = input.ConversationId,
MessageId = input.Message.MessageId,
Name = input.Name,
AgentId = input.AgentId,
Role = input.Message.Role,
Content = input.Log,
Source = input.Source,
CreateTime = DateTime.UtcNow
};
var json = JsonSerializer.Serialize(log, _serializerOptions);
var json = JsonSerializer.Serialize(output, _serializerOptions);
var convSettings = _services.GetRequiredService<ConversationSetting>();
if (convSettings.EnableContentLog)
{
var db = _services.GetRequiredService<IBotSharpRepository>();
db.SaveConversationContentLog(log);
db.SaveConversationContentLog(output);
}
return json;
@ -160,70 +284,4 @@ public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook, IR
return JsonSerializer.Serialize(log, _serializerOptions);
}
#region IRoutingHook
public async Task OnAgentEnqueued(string agentId, string preAgentId, string? reason = null)
{
var conversationId = _state.GetConversationId();
var agent = await _agentService.LoadAgent(agentId);
var preAgent = await _agentService.LoadAgent(preAgentId);
var log = $"{agent.Name} is enqueued{(reason != null ? $" ({reason})" : "")}";
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated",
BuildContentLog(conversationId, "Router", log, ContentLogSource.HardRule, new RoleDialogModel(AgentRole.System, log)
{
MessageId = _routingCtx.MessageId
}));
}
public async Task OnAgentDequeued(string agentId, string currentAgentId, string? reason = null)
{
var conversationId = _state.GetConversationId();
var agent = await _agentService.LoadAgent(agentId);
var currentAgent = await _agentService.LoadAgent(currentAgentId);
var log = $"{agent.Name} is dequeued{(reason != null ? $" ({reason})" : "")}, current agent is {currentAgent?.Name}";
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated",
BuildContentLog(conversationId, "Router", log, ContentLogSource.HardRule, new RoleDialogModel(AgentRole.System, log)
{
MessageId = _routingCtx.MessageId
}));
}
public async Task OnAgentReplaced(string fromAgentId, string toAgentId, string? reason = null)
{
var conversationId = _state.GetConversationId();
var fromAgent = await _agentService.LoadAgent(fromAgentId);
var toAgent = await _agentService.LoadAgent(toAgentId);
var log = $"{fromAgent.Name} is replaced to {toAgent.Name}{(reason != null ? $" ({reason})" : "")}";
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated",
BuildContentLog(conversationId, "Router", log, ContentLogSource.HardRule, new RoleDialogModel(AgentRole.System, log)
{
MessageId = _routingCtx.MessageId
}));
}
public async Task OnAgentQueueEmptied(string agentId, string? reason = null)
{
var conversationId = _state.GetConversationId();
var agent = await _agentService.LoadAgent(agentId);
var log = reason ?? "Agent queue is cleared";
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated",
BuildContentLog(conversationId, "Router", log, ContentLogSource.HardRule, new RoleDialogModel(AgentRole.System, log)
{
MessageId = _routingCtx.MessageId
}));
}
public async Task OnRoutingInstructionReceived(FunctionCallFromLlm instruct, RoleDialogModel message)
{
var conversationId = _state.GetConversationId();
var agent = await _agentService.LoadAgent(message.CurrentAgentId);
var log = JsonSerializer.Serialize(instruct, _serializerOptions);
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated",
BuildContentLog(conversationId, agent.Name, log, ContentLogSource.AgentResponse, message));
}
#endregion
}
}

View file

@ -5,6 +5,7 @@ public class ConversationContentLogDocument : MongoBase
public string ConversationId { get; set; }
public string MessageId { get; set; }
public string? Name { get; set; }
public string? AgentId { get; set; }
public string Role { get; set; }
public string Source { get; set; }
public string Content { get; set; }

View file

@ -60,7 +60,7 @@ public partial class MongoRepository
#endregion
#region Conversation Content Log
public void SaveConversationContentLog(ConversationContentLogModel log)
public void SaveConversationContentLog(ContentLogOutputModel log)
{
if (log == null) return;
@ -72,6 +72,7 @@ public partial class MongoRepository
ConversationId = conversationId,
MessageId = messageId,
Name = log.Name,
AgentId = log.AgentId,
Role = log.Role,
Source = log.Source,
Content = log.Content,
@ -81,16 +82,17 @@ public partial class MongoRepository
_dc.ContentLogs.InsertOne(logDoc);
}
public List<ConversationContentLogModel> GetConversationContentLogs(string conversationId)
public List<ContentLogOutputModel> GetConversationContentLogs(string conversationId)
{
var logs = _dc.ContentLogs
.AsQueryable()
.Where(x => x.ConversationId == conversationId)
.Select(x => new ConversationContentLogModel
.Select(x => new ContentLogOutputModel
{
ConversationId = x.ConversationId,
MessageId = x.MessageId,
Name = x.Name,
AgentId = x.AgentId,
Role = x.Role,
Source = x.Source,
Content = x.Content,