diff --git a/src/Infrastructure/BotSharp.Abstraction/Instructs/Models/InstructResponseModel.cs b/src/Infrastructure/BotSharp.Abstraction/Instructs/Models/InstructResponseModel.cs index 62752bf45..42287b10e 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Instructs/Models/InstructResponseModel.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Instructs/Models/InstructResponseModel.cs @@ -9,4 +9,5 @@ public class InstructResponseModel public string UserMessage { get; set; } = default!; public string? SystemInstruction { get; set; } public string CompletionText { get; set; } = default!; + public string LogId { get; set; } = default!; } diff --git a/src/Infrastructure/BotSharp.Abstraction/Instructs/Models/InstructResult.cs b/src/Infrastructure/BotSharp.Abstraction/Instructs/Models/InstructResult.cs index efaf4ffd0..cfdd68aa4 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Instructs/Models/InstructResult.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Instructs/Models/InstructResult.cs @@ -10,4 +10,7 @@ public class InstructResult : ITrackableMessage [JsonPropertyName("template")] public string? Template { get; set; } public Dictionary? States { get; set; } = new(); + + [JsonPropertyName("log_id")] + public string LogId { get; set; } = default!; } diff --git a/src/Infrastructure/BotSharp.Abstraction/Loggers/Services/ILoggerService.cs b/src/Infrastructure/BotSharp.Abstraction/Loggers/Services/ILoggerService.cs index 564fcf372..4bf35bdba 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Loggers/Services/ILoggerService.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Loggers/Services/ILoggerService.cs @@ -1,5 +1,6 @@ using BotSharp.Abstraction.Loggers.Models; using BotSharp.Abstraction.Repositories.Filters; +using BotSharp.Abstraction.Repositories.Models; namespace BotSharp.Abstraction.Loggers.Services; @@ -13,5 +14,6 @@ public interface ILoggerService #region Instruction Task> GetInstructionLogs(InstructLogFilter filter); Task> GetInstructionLogSearchKeys(InstructLogKeysFilter filter); + Task UpdateInstructionLogStates(UpdateInstructionLogStatesModel request); #endregion } diff --git a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs index 63ca3da3e..37d9a8119 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs @@ -195,6 +195,9 @@ ValueTask> GetInstructionLogs(InstructLogFilter List GetInstructionLogSearchKeys(InstructLogKeysFilter filter) => throw new NotImplementedException(); + + Task UpdateInstructionLogStates(UpdateInstructionLogStatesModel updateInstructionStates) + => throw new NotImplementedException(); #endregion #region Statistics diff --git a/src/Infrastructure/BotSharp.Abstraction/Repositories/Models/UpdateInstructionLogStatesModel.cs b/src/Infrastructure/BotSharp.Abstraction/Repositories/Models/UpdateInstructionLogStatesModel.cs new file mode 100644 index 000000000..48fd8ddbc --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Repositories/Models/UpdateInstructionLogStatesModel.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BotSharp.Abstraction.Repositories.Models +{ + public class UpdateInstructionLogStatesModel + { + public string LogId { get; set; } + public string StateKeyPrefix { get; set; } = "new_"; + public Dictionary States { get; set; } + } +} diff --git a/src/Infrastructure/BotSharp.Core/Instructs/Services/InstructService.Execute.cs b/src/Infrastructure/BotSharp.Core/Instructs/Services/InstructService.Execute.cs index f869ce359..1e6252d62 100644 --- a/src/Infrastructure/BotSharp.Core/Instructs/Services/InstructService.Execute.cs +++ b/src/Infrastructure/BotSharp.Core/Instructs/Services/InstructService.Execute.cs @@ -128,12 +128,14 @@ public async Task Execute( response.Text = result; } + response.LogId = Guid.NewGuid().ToString(); // After completion hooks foreach (var hook in hooks) { await hook.AfterCompletion(agent, response); await hook.OnResponseGenerated(new InstructResponseModel { + LogId = response.LogId, AgentId = agentId, Provider = provider, Model = model, diff --git a/src/Infrastructure/BotSharp.Core/Loggers/Services/LoggerService.Instruction.cs b/src/Infrastructure/BotSharp.Core/Loggers/Services/LoggerService.Instruction.cs index 965212ca8..2060b4916 100644 --- a/src/Infrastructure/BotSharp.Core/Loggers/Services/LoggerService.Instruction.cs +++ b/src/Infrastructure/BotSharp.Core/Loggers/Services/LoggerService.Instruction.cs @@ -1,4 +1,5 @@ using BotSharp.Abstraction.Loggers.Models; +using BotSharp.Abstraction.Repositories.Models; using BotSharp.Abstraction.Users.Models; namespace BotSharp.Core.Loggers.Services; @@ -77,4 +78,13 @@ public async Task> GetInstructionLogSearchKeys(InstructLogKeysFilte keys = filter.PreLoad ? keys : keys.Where(x => x.Contains(filter.Query ?? string.Empty, StringComparison.OrdinalIgnoreCase)).ToList(); return keys.OrderBy(x => x).Take(filter.KeyLimit).ToList(); } + + public async Task UpdateInstructionLogStates(UpdateInstructionLogStatesModel request) + { + if(request == null) return false; + if (string.IsNullOrEmpty(request.LogId) || request.States.IsNullOrEmpty()) return false; + + var db = _services.GetRequiredService(); + return await db.UpdateInstructionLogStates(request); + } } diff --git a/src/Infrastructure/BotSharp.Logger/Hooks/InstructionLogHook.cs b/src/Infrastructure/BotSharp.Logger/Hooks/InstructionLogHook.cs index c95af0c1d..484e82a86 100644 --- a/src/Infrastructure/BotSharp.Logger/Hooks/InstructionLogHook.cs +++ b/src/Infrastructure/BotSharp.Logger/Hooks/InstructionLogHook.cs @@ -48,6 +48,7 @@ public override async Task OnResponseGenerated(InstructResponseModel response) { new InstructionLogModel { + Id = response.LogId, AgentId = response.AgentId, Provider = response.Provider, Model = response.Model, diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/LoggerController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/LoggerController.cs index 7032bcd33..955d7dd14 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/LoggerController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/LoggerController.cs @@ -1,5 +1,6 @@ using BotSharp.Abstraction.Loggers.Models; using BotSharp.Abstraction.Loggers.Services; +using BotSharp.Abstraction.Repositories.Models; using BotSharp.OpenAPI.ViewModels.Instructs; using Microsoft.AspNetCore.Hosting; @@ -76,5 +77,13 @@ public async Task> GetInstructionLogKeys([FromQuery] InstructLogKey var keys = await logging.GetInstructionLogSearchKeys(request); return keys; } + + [HttpPost("/logger/instruction/log/{logId}/states")] + public async Task UpdateInstructionLogStates([FromRoute] string logId, UpdateInstructionLogStatesModel request) + { + request.LogId = logId; + var logging = _services.GetRequiredService(); + return await logging.UpdateInstructionLogStates(request); + } #endregion } diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/InstructionLogDocument.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/InstructionLogDocument.cs index 91bcdc685..0796959b2 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/InstructionLogDocument.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/InstructionLogDocument.cs @@ -19,6 +19,7 @@ public static InstructionLogDocument ToMongoModel(InstructionLogModel log) { return new InstructionLogDocument { + Id = log.Id, AgentId = log.AgentId, Provider = log.Provider, Model = log.Model, diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Log.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Log.cs index 9a2362774..3eedc0050 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Log.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Log.cs @@ -1,5 +1,6 @@ using BotSharp.Abstraction.Loggers.Models; using BotSharp.Abstraction.Repositories.Filters; +using BotSharp.Abstraction.Repositories.Models; using MongoDB.Driver; using System.Text.Json; @@ -169,6 +170,33 @@ public bool SaveInstructionLogs(IEnumerable logs) return true; } + public async Task UpdateInstructionLogStates(UpdateInstructionLogStatesModel updateInstructionStates) + { + var id = updateInstructionStates.LogId; + + var logDoc = await _dc.InstructionLogs.Find(p => p.Id == id).FirstOrDefaultAsync(); + if (logDoc == null) return false; + + foreach (var pair in updateInstructionStates.States) + { + var key = updateInstructionStates.StateKeyPrefix + pair.Key; + try + { + var jsonStr = JsonSerializer.Serialize(new { Data = JsonDocument.Parse(pair.Value) }, _botSharpOptions.JsonSerializerOptions); + var json = BsonDocument.Parse(jsonStr); + logDoc.States[key] = json; + } + catch + { + var jsonStr = JsonSerializer.Serialize(new { Data = pair.Value }, _botSharpOptions.JsonSerializerOptions); + var json = BsonDocument.Parse(jsonStr); + logDoc.States[key] = json; + } + } + await _dc.InstructionLogs.ReplaceOneAsync(p => p.Id == id, logDoc); + return true; + } + public async ValueTask> GetInstructionLogs(InstructLogFilter filter) { if (filter == null)