refactor instruction

This commit is contained in:
Jicheng Lu 2025-03-05 17:22:46 -06:00
parent 263ec44517
commit 366e1339c6
57 changed files with 537 additions and 136 deletions

View file

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>$(TargetFramework)</TargetFramework>

View file

@ -108,7 +108,8 @@ public class RoleDialogModel : ITrackableMessage
[JsonPropertyName("generated_images")]
public List<ImageGeneration> GeneratedImages { get; set; } = new List<ImageGeneration>();
[JsonIgnore(Condition = JsonIgnoreCondition.Always)]
public string RenderedInstruction { get; set; } = string.Empty;
private RoleDialogModel()
{

View file

@ -7,7 +7,7 @@ public class InstructLogFilter : Pagination
public List<string>? AgentIds { get; set; }
public List<string>? Providers { get; set; }
public List<string>? Models { get; set; }
public List<KeyValue>? States { get; set; }
public List<string>? TemplateNames { get; set; }
public static InstructLogFilter Empty()
{

View file

@ -3,6 +3,10 @@ namespace BotSharp.Abstraction.Instructs.Models;
public class InstructResponseModel
{
public string? AgentId { get; set; }
public string Provider { get; set; }
public string Model { get; set; }
public string Provider { get; set; } = default!;
public string Model { get; set; } = default!;
public string? TemplateName { get; set; }
public string UserMessage { get; set; } = default!;
public string? SystemInstruction { get; set; }
public string CompletionText { get; set; } = default!;
}

View file

@ -1,24 +1,50 @@
using System.Text.Json;
namespace BotSharp.Abstraction.Loggers.Models;
public class InstructionLogModel
{
[JsonPropertyName("id")]
public string Id { get; set; } = default!;
[JsonPropertyName("agent_id")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? AgentId { get; set; }
[JsonPropertyName("agent_name")]
[JsonIgnore]
public string? AgentName { get; set; }
[JsonPropertyName("provider")]
public string Provider { get; set; } = default!;
[JsonPropertyName("model")]
public string Model { get; set; } = default!;
[JsonPropertyName("template_name")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? TemplateName { get; set; }
[JsonPropertyName("user_message")]
public string UserMessage { get; set; } = string.Empty;
[JsonPropertyName("system_instruction")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? SystemInstruction { get; set; }
[JsonPropertyName("completion_text")]
public string CompletionText { get; set; } = string.Empty;
[JsonPropertyName("user_id")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? UserId { get; set; }
[JsonPropertyName("states")]
[JsonIgnore]
public Dictionary<string, string> States { get; set; } = [];
[JsonPropertyName("states")]
public Dictionary<string, JsonDocument> InnerStates { get; set; } = [];
[JsonPropertyName("created_time")]
public DateTime CreatedTime { get; set; } = DateTime.UtcNow;
}

View file

@ -6,6 +6,8 @@ public interface IAudioCompletion
{
string Provider { get; }
string Model { get; }
Task<string> GenerateTextFromAudioAsync(Stream audio, string audioFileName, string? text = null);
Task<BinaryData> GenerateAudioFromTextAsync(string text);

View file

@ -7,6 +7,8 @@ public interface IChatCompletion
/// </summary>
string Provider { get; }
string Model { get; }
/// <summary>
/// Set model name, one provider can consume different model or version(s)
/// </summary>

View file

@ -9,6 +9,8 @@ public interface IImageCompletion
/// </summary>
string Provider { get; }
string Model { get; }
/// <summary>
/// Set model name, one provider can consume different model or version(s)
/// </summary>

View file

@ -6,7 +6,6 @@ public interface IRealTimeCompletion
{
string Provider { get; }
string Model { get; }
void SetModelName(string model);
Task Connect(RealtimeHubConnection conn,

View file

@ -6,6 +6,7 @@ public interface ITextCompletion
/// The LLM provider like Microsoft Azure, OpenAI, ClaudAI
/// </summary>
string Provider { get; }
string Model { get; }
/// <summary>
/// Set model name, one provider can consume different model or version(s)

View file

@ -6,9 +6,14 @@ public interface ITextEmbedding
/// The Embedding provider like Microsoft Azure, OpenAI, ClaudAI
/// </summary>
string Provider { get; }
string Model { get; }
void SetModelName(string model);
Task<float[]> GetVectorAsync(string text);
Task<List<float[]>> GetVectorsAsync(List<string> texts);
void SetModelName(string model);
void SetDimension(int dimension);
int GetDimension();
}

View file

@ -1,3 +1,5 @@
using BotSharp.Abstraction.Instructs.Models;
using BotSharp.Abstraction.Instructs;
using System.IO;
namespace BotSharp.Core.Files.Services;
@ -6,10 +8,11 @@ public partial class FileInstructService
{
public async Task<string> ReadImages(string? provider, string? model, string text, IEnumerable<InstructFileModel> images, string? agentId = null)
{
var innerAgentId = agentId ?? Guid.Empty.ToString();
var completion = CompletionProvider.GetChatCompletion(_services, provider: provider ?? "openai", model: model ?? "gpt-4o", multiModal: true);
var message = await completion.GetChatCompletions(new Agent()
{
Id = agentId ?? Guid.Empty.ToString(),
Id = innerAgentId,
}, new List<RoleDialogModel>
{
new RoleDialogModel(AgentRole.User, text)
@ -17,16 +20,55 @@ public partial class FileInstructService
Files = images?.Select(x => new BotSharpFile { FileUrl = x.FileUrl, FileData = x.FileData }).ToList() ?? new List<BotSharpFile>()
}
});
var hooks = _services.GetServices<IInstructHook>();
foreach (var hook in hooks)
{
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agentId)
{
continue;
}
await hook.OnResponseGenerated(new InstructResponseModel
{
AgentId = innerAgentId,
Provider = completion.Provider,
Model = completion.Model,
UserMessage = text,
CompletionText = message.Content
});
}
return message.Content;
}
public async Task<RoleDialogModel> GenerateImage(string? provider, string? model, string text, string? agentId = null)
{
var innerAgentId = agentId ?? Guid.Empty.ToString();
var completion = CompletionProvider.GetImageCompletion(_services, provider: provider ?? "openai", model: model ?? "dall-e-3");
var message = await completion.GetImageGeneration(new Agent()
{
Id = agentId ?? Guid.Empty.ToString(),
Id = innerAgentId,
}, new RoleDialogModel(AgentRole.User, text));
var hooks = _services.GetServices<IInstructHook>();
foreach (var hook in hooks)
{
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agentId)
{
continue;
}
await hook.OnResponseGenerated(new InstructResponseModel
{
AgentId = innerAgentId,
Provider = completion.Provider,
Model = completion.Model,
UserMessage = text,
CompletionText = message.Content
});
}
return message;
}
@ -37,6 +79,7 @@ public partial class FileInstructService
throw new ArgumentException($"Cannot find image url or data!");
}
var innerAgentId = agentId ?? Guid.Empty.ToString();
var completion = CompletionProvider.GetImageCompletion(_services, provider: provider ?? "openai", model: model ?? "dall-e-2");
var bytes = await DownloadFile(image);
using var stream = new MemoryStream();
@ -46,10 +89,29 @@ public partial class FileInstructService
var fileName = $"{image.FileName ?? "image"}.{image.FileExtension ?? "png"}";
var message = await completion.GetImageVariation(new Agent()
{
Id = agentId ?? Guid.Empty.ToString()
Id = innerAgentId
}, new RoleDialogModel(AgentRole.User, string.Empty), stream, fileName);
stream.Close();
var hooks = _services.GetServices<IInstructHook>();
foreach (var hook in hooks)
{
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agentId)
{
continue;
}
await hook.OnResponseGenerated(new InstructResponseModel
{
AgentId = innerAgentId,
Provider = completion.Provider,
Model = completion.Model,
UserMessage = string.Empty,
CompletionText = message.Content
});
}
return message;
}
@ -60,6 +122,7 @@ public partial class FileInstructService
throw new ArgumentException($"Cannot find image url or data!");
}
var innerAgentId = agentId ?? Guid.Empty.ToString();
var completion = CompletionProvider.GetImageCompletion(_services, provider: provider ?? "openai", model: model ?? "dall-e-2");
var bytes = await DownloadFile(image);
using var stream = new MemoryStream();
@ -69,10 +132,29 @@ public partial class FileInstructService
var fileName = $"{image.FileName ?? "image"}.{image.FileExtension ?? "png"}";
var message = await completion.GetImageEdits(new Agent()
{
Id = agentId ?? Guid.Empty.ToString()
Id = innerAgentId
}, new RoleDialogModel(AgentRole.User, text), stream, fileName);
stream.Close();
var hooks = _services.GetServices<IInstructHook>();
foreach (var hook in hooks)
{
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agentId)
{
continue;
}
await hook.OnResponseGenerated(new InstructResponseModel
{
AgentId = innerAgentId,
Provider = completion.Provider,
Model = completion.Model,
UserMessage = text,
CompletionText = message.Content
});
}
return message;
}
@ -84,6 +166,7 @@ public partial class FileInstructService
throw new ArgumentException($"Cannot find image/mask url or data");
}
var innerAgentId = agentId ?? Guid.Empty.ToString();
var completion = CompletionProvider.GetImageCompletion(_services, provider: provider ?? "openai", model: model ?? "dall-e-2");
var imageBytes = await DownloadFile(image);
var maskBytes = await DownloadFile(mask);
@ -100,11 +183,30 @@ public partial class FileInstructService
var maskName = $"{mask.FileName ?? "mask"}.{mask.FileExtension ?? "png"}";
var message = await completion.GetImageEdits(new Agent()
{
Id = agentId ?? Guid.Empty.ToString()
Id = innerAgentId
}, new RoleDialogModel(AgentRole.User, text), imageStream, imageName, maskStream, maskName);
imageStream.Close();
maskStream.Close();
var hooks = _services.GetServices<IInstructHook>();
foreach (var hook in hooks)
{
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agentId)
{
continue;
}
await hook.OnResponseGenerated(new InstructResponseModel
{
AgentId = innerAgentId,
Provider = completion.Provider,
Model = completion.Model,
UserMessage = text,
CompletionText = message.Content
});
}
return message;
}

View file

@ -1,4 +1,6 @@
using BotSharp.Abstraction.Files.Converters;
using BotSharp.Abstraction.Instructs.Models;
using BotSharp.Abstraction.Instructs;
namespace BotSharp.Core.Files.Services;
@ -23,11 +25,12 @@ public partial class FileInstructService
var images = await ConvertPdfToImages(pdfFiles);
if (images.IsNullOrEmpty()) return content;
var innerAgentId = agentId ?? Guid.Empty.ToString();
var completion = CompletionProvider.GetChatCompletion(_services, provider: provider ?? "openai",
model: model, modelId: modelId ?? "gpt-4", multiModal: true);
var message = await completion.GetChatCompletions(new Agent()
{
Id = agentId ?? Guid.Empty.ToString(),
Id = innerAgentId,
}, new List<RoleDialogModel>
{
new RoleDialogModel(AgentRole.User, prompt)
@ -35,6 +38,25 @@ public partial class FileInstructService
Files = images.Select(x => new BotSharpFile { FileStorageUrl = x }).ToList()
}
});
var hooks = _services.GetServices<IInstructHook>();
foreach (var hook in hooks)
{
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agentId)
{
continue;
}
await hook.OnResponseGenerated(new InstructResponseModel
{
AgentId = innerAgentId,
Provider = completion.Provider,
Model = completion.Model,
UserMessage = prompt,
CompletionText = message.Content
});
}
return message.Content;
}
catch (Exception ex)

View file

@ -1,4 +1,5 @@
using BotSharp.Abstraction.Plugins.Models;
using BotSharp.Abstraction.Users.Enums;
using Microsoft.Extensions.Configuration;
namespace BotSharp.Core.Instructs;
@ -17,7 +18,15 @@ public class InsturctionPlugin : IBotSharpPlugin
public bool AttachMenu(List<PluginMenuDef> menu)
{
var section = menu.First(x => x.Label == "Apps");
menu.Add(new PluginMenuDef("Instruction", link: "page/instruction", icon: "bx bx-book-content", weight: section.Weight + 5));
menu.Add(new PluginMenuDef("Instruction", icon: "bx bx-book-content", weight: section.Weight + 5)
{
SubMenu = new List<PluginMenuDef>
{
new PluginMenuDef("Instruction", link: "page/instruction"),
new PluginMenuDef("Log", link: "page/instruction/log") { Roles = [UserRole.Root, UserRole.Admin] }
}
});
return true;
}
}

View file

@ -43,6 +43,9 @@ public partial class InstructService
}
}
var provider = string.Empty;
var model = string.Empty;
// Render prompt
var prompt = string.IsNullOrEmpty(templateName) ?
agentService.RenderedInstruction(agent) :
@ -57,11 +60,18 @@ public partial class InstructService
};
if (completer is ITextCompletion textCompleter)
{
instruction = null;
provider = textCompleter.Provider;
model = textCompleter.Model;
var result = await textCompleter.GetCompletion(prompt, agentId, message.MessageId);
response.Text = result;
}
else if (completer is IChatCompletion chatCompleter)
{
provider = chatCompleter.Provider;
model = chatCompleter.Model;
if (instruction == "#TEMPLATE#")
{
instruction = prompt;
@ -93,6 +103,16 @@ public partial class InstructService
}
await hook.AfterCompletion(agent, response);
await hook.OnResponseGenerated(new InstructResponseModel
{
AgentId = agentId,
Provider = provider,
Model = model,
TemplateName = templateName,
UserMessage = prompt,
SystemInstruction = instruction,
CompletionText = response.Text
});
}
return response;

View file

@ -136,7 +136,8 @@ namespace BotSharp.Core.Repository
foreach (var log in logs)
{
var file = Path.Combine(baseDir, $"{Guid.NewGuid()}.log");
var file = Path.Combine(baseDir, $"{Guid.NewGuid()}.json");
log.InnerStates = BuildLogStates(log.States);
var text = JsonSerializer.Serialize(log, _options);
File.WriteAllText(file, text);
}
@ -150,9 +151,67 @@ namespace BotSharp.Core.Repository
filter = InstructLogFilter.Empty();
}
var baseDir = Path.Combine(_dbSettings.FileRepository, INSTRUCTION_LOG_FOLDER);
if (!Directory.Exists(baseDir))
{
return new();
}
var logs = new List<InstructionLogModel>();
var files = Directory.GetFiles(baseDir);
foreach (var file in files)
{
var json = File.ReadAllText(file);
var log = JsonSerializer.Deserialize<InstructionLogModel>(json, _options);
if (log == null) continue;
var matched = true;
if (!filter.AgentIds.IsNullOrEmpty())
{
matched = matched && filter.AgentIds.Contains(log.AgentId);
}
if (!filter.Providers.IsNullOrEmpty())
{
matched = matched && filter.Providers.Contains(log.Provider);
}
if (!filter.Models.IsNullOrEmpty())
{
matched = matched && filter.Models.Contains(log.Model);
}
if (!filter.TemplateNames.IsNullOrEmpty())
{
matched = matched && filter.TemplateNames.Contains(log.TemplateName);
}
if (!matched) continue;
log.Id = Path.GetFileNameWithoutExtension(file);
logs.Add(log);
}
var records = logs.OrderByDescending(x => x.CreatedTime).Skip(filter.Offset).Take(filter.Size);
var agentIds = records.Where(x => !string.IsNullOrEmpty(x.AgentId)).Select(x => x.AgentId).ToList();
var agents = GetAgents(new AgentFilter
{
AgentIds = agentIds
});
records = records.Select(x =>
{
var states = x.InnerStates.ToDictionary(p => p.Key, p =>
{
var data = p.Value.RootElement.GetProperty("data");
return data.ValueKind != JsonValueKind.Null ? data.ToString() : null;
});
x.AgentName = !string.IsNullOrEmpty(x.AgentId) ? agents.FirstOrDefault(a => a.Id == x.AgentId)?.Name : null;
x.States = states ?? [];
return x;
}).ToList();
return new PagedItems<InstructionLogModel>
{
Items = records,
Count = logs.Count()
};
}
#endregion
@ -176,6 +235,28 @@ namespace BotSharp.Core.Repository
return logIndexes.IsNullOrEmpty() ? 0 : logIndexes.Max() + 1;
}
private Dictionary<string, JsonDocument> BuildLogStates(Dictionary<string, string> states)
{
var dic = new Dictionary<string, JsonDocument>();
foreach (var pair in states)
{
try
{
var jsonStr = JsonSerializer.Serialize(new { Data = JsonDocument.Parse(pair.Value) }, _options);
var json = JsonDocument.Parse(jsonStr);
dic[pair.Key] = json;
}
catch
{
var str = JsonSerializer.Serialize(new { Data = pair.Value }, _options);
var json = JsonDocument.Parse(str);
dic[pair.Key] = json;
}
}
return dic;
}
#endregion
}
}

View file

@ -1,8 +1,6 @@
using BotSharp.Abstraction.Instructs.Models;
using BotSharp.Abstraction.Loggers.Models;
using BotSharp.Abstraction.Options;
using BotSharp.Abstraction.Users;
using System.Text.Json;
namespace BotSharp.Logger.Hooks;
@ -10,19 +8,18 @@ public class InstructionLogHook : InstructHookBase
{
private readonly IServiceProvider _services;
private readonly ILogger<InstructionLogHook> _logger;
private readonly BotSharpOptions _options;
private readonly IUserIdentity _user;
public override string SelfId => string.Empty;
public InstructionLogHook(
IServiceProvider services,
ILogger<InstructionLogHook> logger,
IUserIdentity user,
BotSharpOptions options)
IUserIdentity user)
{
_services = services;
_logger = logger;
_user = user;
_options = options;
}
public override async Task OnResponseGenerated(InstructResponseModel response)
@ -40,57 +37,14 @@ public class InstructionLogHook : InstructHookBase
AgentId = response.AgentId,
Provider = response.Provider,
Model = response.Model,
TemplateName = response.TemplateName,
UserMessage = response.UserMessage,
SystemInstruction = response.SystemInstruction,
CompletionText = response.CompletionText,
States = state.GetStates(),
UserId = user?.Id
}
});
return;
}
private Dictionary<string, string> CollectStates()
{
var res = new Dictionary<string, object>();
var state = _services.GetRequiredService<IConversationStateService>();
var curStates = state.GetStates();
curStates["test"] = JsonSerializer.Serialize(new
{
Number = "789",
Dummy = new
{
Id = 123,
Name = "name",
Score = 12.123
},
Items = new List<object>
{
new
{
Name = "image",
Label = "before-service",
Attribute = new
{
Location = "Chicago",
Time = "afternoon"
}
},
new
{
Name = "pdf",
Label = "after-service",
Attribute = new
{
Location = "New York",
Time = "morning"
}
},
},
Lists = new List<object>
{
"abc",
"bcd"
}
}, _options.JsonSerializerOptions);
return curStates;
}
}

View file

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>$(TargetFramework)</TargetFramework>

View file

@ -52,8 +52,29 @@ public class InstructModeController : ControllerBase
.SetState("model", input.Model, source: StateSource.External)
.SetState("model_id", input.ModelId, source: StateSource.External);
var agentId = input.AgentId ?? Guid.Empty.ToString();
var textCompletion = CompletionProvider.GetTextCompletion(_services);
return await textCompletion.GetCompletion(input.Text, input.AgentId ?? Guid.Empty.ToString(), Guid.NewGuid().ToString());
var response = await textCompletion.GetCompletion(input.Text, agentId, Guid.NewGuid().ToString());
var hooks = _services.GetServices<IInstructHook>();
foreach (var hook in hooks)
{
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agentId)
{
continue;
}
await hook.OnResponseGenerated(new InstructResponseModel
{
AgentId = agentId,
Provider = textCompletion.Provider,
Model = textCompletion.Model,
TemplateName = input.Template,
UserMessage = input.Text,
CompletionText = response
});
}
return response;
}
#region Chat
@ -66,10 +87,11 @@ public class InstructModeController : ControllerBase
.SetState("model", input.Model, source: StateSource.External)
.SetState("model_id", input.ModelId, source: StateSource.External);
var agentId = input.AgentId ?? Guid.Empty.ToString();
var completion = CompletionProvider.GetChatCompletion(_services);
var message = await completion.GetChatCompletions(new Agent()
{
Id = input.AgentId ?? Guid.Empty.ToString(),
Id = agentId,
Instruction = input.Instruction
}, new List<RoleDialogModel>
{
@ -79,14 +101,22 @@ public class InstructModeController : ControllerBase
var hooks = _services.GetServices<IInstructHook>();
foreach (var hook in hooks)
{
if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agentId)
{
continue;
}
await hook.OnResponseGenerated(new InstructResponseModel
{
AgentId = input.AgentId,
Provider = input.Provider,
Model = input.Model
AgentId = agentId,
Provider = completion.Provider,
Model = completion.Model,
TemplateName = input.Template,
UserMessage = input.Text,
SystemInstruction = message.RenderedInstruction,
CompletionText = message.Content
});
}
return message.Content;
}
#endregion

View file

@ -1,4 +1,8 @@
using BotSharp.Abstraction.Instructs.Models;
using BotSharp.Abstraction.Loggers.Models;
using BotSharp.Abstraction.Repositories;
using BotSharp.OpenAPI.ViewModels.Logs;
using EntityFrameworkCore.BootKit;
using Microsoft.AspNetCore.Hosting;
namespace BotSharp.OpenAPI.Controllers;
@ -45,4 +49,16 @@ public class LoggerController : ControllerBase
var conversationService = _services.GetRequiredService<IConversationService>();
return await conversationService.GetConversationStateLogs(conversationId);
}
[HttpGet("/logger/instruction/log")]
public async Task<PagedItems<InstructionLogViewModel>> GetInstructionLogs([FromQuery] InstructLogFilter request)
{
var db = _services.GetRequiredService<IBotSharpRepository>();
var logs = db.GetInstructionLogs(request);
return new PagedItems<InstructionLogViewModel>
{
Items = logs.Items.Select(x => InstructionLogViewModel.From(x)),
Count = logs.Count
};
}
}

View file

@ -15,4 +15,5 @@ public class IncomingInstructRequest : IncomingMessageModel
{
public string? AgentId { get; set; }
public string? Instruction { get; set; }
public string? Template { get; set; }
}

View file

@ -9,10 +9,12 @@ namespace BotSharp.Plugin.AnthropicAI.Providers;
public class ChatCompletionProvider : IChatCompletion
{
public string Provider => "anthropic";
public string Model => _model;
protected readonly AnthropicSettings _settings;
protected readonly IServiceProvider _services;
protected readonly ILogger _logger;
private List<string> renderedInstructions = [];
protected string _model;
@ -57,6 +59,7 @@ public class ChatCompletionProvider : IChatCompletion
ToolCallId = toolResult.Id,
FunctionName = toolResult.Name,
FunctionArgs = JsonSerializer.Serialize(toolResult.Input),
RenderedInstruction = string.Join("\r\n", renderedInstructions)
};
}
else
@ -66,6 +69,7 @@ public class ChatCompletionProvider : IChatCompletion
{
CurrentAgentId = agent.Id,
MessageId = conversations.LastOrDefault()?.MessageId ?? string.Empty,
RenderedInstruction = string.Join("\r\n", renderedInstructions)
};
}
@ -98,12 +102,15 @@ public class ChatCompletionProvider : IChatCompletion
private (string, MessageParameters) PrepareOptions(Agent agent, List<RoleDialogModel> conversations, LlmModelSetting settings)
{
var instruction = "";
renderedInstructions = [];
var agentService = _services.GetRequiredService<IAgentService>();
if (!string.IsNullOrEmpty(agent.Instruction) || !agent.SecondaryInstructions.IsNullOrEmpty())
{
instruction += agentService.RenderedInstruction(agent);
var text = agentService.RenderedInstruction(agent);
instruction += text;
renderedInstructions.Add(text);
}
/*var routing = _services.GetRequiredService<IRoutingService>();

View file

@ -15,6 +15,8 @@ public class NativeWhisperProvider : IAudioCompletion
private readonly ILogger<NativeWhisperProvider> _logger;
public string Provider => "native-whisper";
public string Model => _model;
private string _model;
public NativeWhisperProvider(
BotSharpDatabaseSettings dbSettings,
@ -56,11 +58,13 @@ public class NativeWhisperProvider : IAudioCompletion
{
if (Enum.TryParse(model, true, out GgmlType ggmlType))
{
_model = model;
LoadWhisperModel(ggmlType);
}
else
{
_logger.LogWarning($"Unsupported model type: {model}. Use Tiny model instead!");
_model = "Tiny";
LoadWhisperModel(GgmlType.Tiny);
}
}

View file

@ -5,6 +5,8 @@ public partial class AudioCompletionProvider : IAudioCompletion
private readonly IServiceProvider _services;
public string Provider => "openai";
public string Model => _model;
private string _model;
public AudioCompletionProvider(IServiceProvider service)

View file

@ -9,10 +9,12 @@ public class ChatCompletionProvider : IChatCompletion
protected readonly AzureOpenAiSettings _settings;
protected readonly IServiceProvider _services;
protected readonly ILogger<ChatCompletionProvider> _logger;
private List<string> renderedInstructions = [];
protected string _model;
public virtual string Provider => "azure-openai";
public string Model => _model;
public ChatCompletionProvider(
AzureOpenAiSettings settings,
@ -58,7 +60,8 @@ public class ChatCompletionProvider : IChatCompletion
CurrentAgentId = agent.Id,
MessageId = conversations.LastOrDefault()?.MessageId ?? string.Empty,
FunctionName = toolCall?.FunctionName,
FunctionArgs = toolCall?.FunctionArguments?.ToString()
FunctionArgs = toolCall?.FunctionArguments?.ToString(),
RenderedInstruction = string.Join("\r\n", renderedInstructions)
};
// Somethings LLM will generate a function name with agent name.
@ -73,6 +76,7 @@ public class ChatCompletionProvider : IChatCompletion
{
CurrentAgentId = agent.Id,
MessageId = conversations.LastOrDefault()?.MessageId ?? string.Empty,
RenderedInstruction = string.Join("\r\n", renderedInstructions)
};
}
}
@ -83,6 +87,7 @@ public class ChatCompletionProvider : IChatCompletion
{
CurrentAgentId = agent.Id,
MessageId = conversations.LastOrDefault()?.MessageId ?? string.Empty,
RenderedInstruction = string.Join("\r\n", renderedInstructions)
};
}
catch (Exception ex)
@ -92,6 +97,7 @@ public class ChatCompletionProvider : IChatCompletion
{
CurrentAgentId = agent.Id,
MessageId = conversations.LastOrDefault()?.MessageId ?? string.Empty,
RenderedInstruction = string.Join("\r\n", renderedInstructions)
};
}
@ -136,7 +142,8 @@ public class ChatCompletionProvider : IChatCompletion
var msg = new RoleDialogModel(AgentRole.Assistant, text)
{
CurrentAgentId = agent.Id
CurrentAgentId = agent.Id,
RenderedInstruction = string.Join("\r\n", renderedInstructions)
};
// After chat completion hook
@ -163,7 +170,8 @@ public class ChatCompletionProvider : IChatCompletion
MessageId = conversations.LastOrDefault()?.MessageId ?? string.Empty,
ToolCallId = toolCall?.Id,
FunctionName = toolCall?.FunctionName,
FunctionArgs = toolCall?.FunctionArguments?.ToString()
FunctionArgs = toolCall?.FunctionArguments?.ToString(),
RenderedInstruction = string.Join("\r\n", renderedInstructions)
};
// Somethings LLM will generate a function name with agent name.
@ -199,7 +207,10 @@ public class ChatCompletionProvider : IChatCompletion
var update = choice.ToolCallUpdates?.FirstOrDefault()?.FunctionArgumentsUpdate?.ToString() ?? string.Empty;
Console.Write(update);
await onMessageReceived(new RoleDialogModel(AgentRole.Assistant, update));
await onMessageReceived(new RoleDialogModel(AgentRole.Assistant, update)
{
RenderedInstruction = string.Join("\r\n", renderedInstructions)
});
continue;
}
@ -207,7 +218,10 @@ public class ChatCompletionProvider : IChatCompletion
_logger.LogInformation(choice.ContentUpdate[0]?.Text);
await onMessageReceived(new RoleDialogModel(choice.Role?.ToString() ?? ChatMessageRole.Assistant.ToString(), choice.ContentUpdate[0]?.Text ?? string.Empty));
await onMessageReceived(new RoleDialogModel(choice.Role?.ToString() ?? ChatMessageRole.Assistant.ToString(), choice.ContentUpdate[0]?.Text ?? string.Empty)
{
RenderedInstruction = string.Join("\r\n", renderedInstructions)
});
}
return true;
@ -221,6 +235,7 @@ public class ChatCompletionProvider : IChatCompletion
var settingsService = _services.GetRequiredService<ILlmProviderService>();
var settings = settingsService.GetSetting(Provider, _model);
var allowMultiModal = settings != null && settings.MultiModal;
renderedInstructions = [];
var messages = new List<ChatMessage>();
@ -251,6 +266,7 @@ public class ChatCompletionProvider : IChatCompletion
if (!string.IsNullOrEmpty(agent.Instruction) || !agent.SecondaryInstructions.IsNullOrEmpty())
{
var instruction = agentService.RenderedInstruction(agent);
renderedInstructions.Add(instruction);
messages.Add(new SystemChatMessage(instruction));
}

View file

@ -13,6 +13,7 @@ public class TextEmbeddingProvider : ITextEmbedding
protected int _dimension;
public virtual string Provider => "azure-openai";
public string Model => _model;
public TextEmbeddingProvider(
AzureOpenAiSettings settings,
@ -49,6 +50,7 @@ public class TextEmbeddingProvider : ITextEmbedding
_model = model;
}
public void SetDimension(int dimension)
{
_dimension = dimension > 0 ? dimension : DEFAULT_DIMENSION;

View file

@ -14,6 +14,7 @@ public partial class ImageCompletionProvider : IImageCompletion
protected string _model;
public virtual string Provider => "azure-openai";
public string Model => _model;
public ImageCompletionProvider(
AzureOpenAiSettings settings,

View file

@ -22,6 +22,7 @@ public class TextCompletionProvider : ITextCompletion
};
public virtual string Provider => "azure-openai";
public string Model => _model;
public TextCompletionProvider(
AzureOpenAiSettings settings,

View file

@ -9,9 +9,11 @@ public class ChatCompletionProvider : IChatCompletion
{
protected readonly IServiceProvider _services;
protected readonly ILogger<ChatCompletionProvider> _logger;
private List<string> renderedInstructions = [];
protected string _model;
public virtual string Provider => "deepseek-ai";
public string Model => _model;
public ChatCompletionProvider(
IServiceProvider services,
@ -51,7 +53,8 @@ public class ChatCompletionProvider : IChatCompletion
MessageId = conversations.LastOrDefault()?.MessageId ?? string.Empty,
ToolCallId = toolCall?.Id,
FunctionName = toolCall?.FunctionName,
FunctionArgs = toolCall?.FunctionArguments?.ToString()
FunctionArgs = toolCall?.FunctionArguments?.ToString(),
RenderedInstruction = string.Join("\r\n", renderedInstructions)
};
// Somethings LLM will generate a function name with agent name.
@ -66,6 +69,7 @@ public class ChatCompletionProvider : IChatCompletion
{
CurrentAgentId = agent.Id,
MessageId = conversations.LastOrDefault()?.MessageId ?? string.Empty,
RenderedInstruction = string.Join("\r\n", renderedInstructions)
};
}
@ -107,7 +111,8 @@ public class ChatCompletionProvider : IChatCompletion
var msg = new RoleDialogModel(AgentRole.Assistant, text)
{
CurrentAgentId = agent.Id
CurrentAgentId = agent.Id,
RenderedInstruction = string.Join("\r\n", renderedInstructions)
};
// After chat completion hook
@ -134,7 +139,8 @@ public class ChatCompletionProvider : IChatCompletion
MessageId = conversations.LastOrDefault()?.MessageId ?? string.Empty,
ToolCallId = toolCall?.Id,
FunctionName = toolCall?.FunctionName,
FunctionArgs = toolCall?.FunctionArguments?.ToString()
FunctionArgs = toolCall?.FunctionArguments?.ToString(),
RenderedInstruction = string.Join("\r\n", renderedInstructions)
};
// Somethings LLM will generate a function name with agent name.
@ -170,7 +176,10 @@ public class ChatCompletionProvider : IChatCompletion
var update = choice.ToolCallUpdates?.FirstOrDefault()?.FunctionArgumentsUpdate?.ToString() ?? string.Empty;
_logger.LogInformation(update);
await onMessageReceived(new RoleDialogModel(AgentRole.Assistant, update));
await onMessageReceived(new RoleDialogModel(AgentRole.Assistant, update)
{
RenderedInstruction = string.Join("\r\n", renderedInstructions)
});
continue;
}
@ -178,7 +187,10 @@ public class ChatCompletionProvider : IChatCompletion
_logger.LogInformation(choice.ContentUpdate[0]?.Text);
await onMessageReceived(new RoleDialogModel(choice.Role?.ToString() ?? ChatMessageRole.Assistant.ToString(), choice.ContentUpdate[0]?.Text ?? string.Empty));
await onMessageReceived(new RoleDialogModel(choice.Role?.ToString() ?? ChatMessageRole.Assistant.ToString(), choice.ContentUpdate[0]?.Text ?? string.Empty)
{
RenderedInstruction = string.Join("\r\n", renderedInstructions)
});
}
return true;
@ -197,6 +209,7 @@ public class ChatCompletionProvider : IChatCompletion
var settingsService = _services.GetRequiredService<ILlmProviderService>();
var settings = settingsService.GetSetting(Provider, _model);
var allowMultiModal = settings != null && settings.MultiModal;
renderedInstructions = [];
var messages = new List<ChatMessage>();
@ -226,6 +239,7 @@ public class ChatCompletionProvider : IChatCompletion
if (!string.IsNullOrEmpty(agent.Instruction) || !agent.SecondaryInstructions.IsNullOrEmpty())
{
var text = agentService.RenderedInstruction(agent);
renderedInstructions.Add(text);
messages.Add(new SystemChatMessage(text));
}

View file

@ -10,6 +10,7 @@ public class TextCompletionProvider : ITextCompletion
protected string _model;
public string Provider => "deepseek-ai";
public string Model => _model;
public TextCompletionProvider(
IServiceProvider services,

View file

@ -2,7 +2,6 @@ using BotSharp.Abstraction.Agents;
using BotSharp.Abstraction.Agents.Enums;
using BotSharp.Abstraction.Conversations;
using BotSharp.Abstraction.Loggers;
using Google.Protobuf.WellKnownTypes;
using Microsoft.Extensions.Logging;
using Mscc.GenerativeAI;
@ -12,10 +11,12 @@ public class GeminiChatCompletionProvider : IChatCompletion
{
private readonly IServiceProvider _services;
private readonly ILogger<GeminiChatCompletionProvider> _logger;
private List<string> renderedInstructions = [];
private string _model;
public string Provider => "google-ai";
public string Model => _model;
public GeminiChatCompletionProvider(
IServiceProvider services,
@ -53,7 +54,8 @@ public class GeminiChatCompletionProvider : IChatCompletion
MessageId = conversations.LastOrDefault()?.MessageId ?? string.Empty,
ToolCallId = part.FunctionCall.Name,
FunctionName = part.FunctionCall.Name,
FunctionArgs = part.FunctionCall.Args?.ToString()
FunctionArgs = part.FunctionCall.Args?.ToString(),
RenderedInstruction = string.Join("\r\n", renderedInstructions)
};
}
else
@ -62,6 +64,7 @@ public class GeminiChatCompletionProvider : IChatCompletion
{
CurrentAgentId = agent.Id,
MessageId = conversations.LastOrDefault()?.MessageId ?? string.Empty,
RenderedInstruction = string.Join("\r\n", renderedInstructions)
};
}
@ -98,6 +101,7 @@ public class GeminiChatCompletionProvider : IChatCompletion
{
var agentService = _services.GetRequiredService<IAgentService>();
var googleSettings = _services.GetRequiredService<GoogleAiSettings>();
renderedInstructions = [];
// Add settings
aiModel.UseGoogleSearch = googleSettings.Gemini.UseGoogleSearch;
@ -117,6 +121,7 @@ public class GeminiChatCompletionProvider : IChatCompletion
Role = AgentRole.User
});
renderedInstructions.Add(instruction);
systemPrompts.Add(instruction);
}

View file

@ -13,10 +13,12 @@ public class PalmChatCompletionProvider : IChatCompletion
{
private readonly IServiceProvider _services;
private readonly ILogger<PalmChatCompletionProvider> _logger;
private List<string> renderedInstructions = [];
private string _model;
public string Provider => "google-palm";
public string Model => _model;
public PalmChatCompletionProvider(
IServiceProvider services,
@ -61,7 +63,8 @@ public class PalmChatCompletionProvider : IChatCompletion
{
CurrentAgentId = agent.Id,
FunctionName = llmResponse.FunctionName,
FunctionArgs = JsonSerializer.Serialize(llmResponse.Args)
FunctionArgs = JsonSerializer.Serialize(llmResponse.Args),
RenderedInstruction = string.Join("\r\n", renderedInstructions)
};
}
else
@ -75,7 +78,8 @@ public class PalmChatCompletionProvider : IChatCompletion
msg = new RoleDialogModel(llmResponse.Role, llmResponse.Content ?? message.Content)
{
CurrentAgentId = agent.Id
CurrentAgentId = agent.Id,
RenderedInstruction = string.Join("\r\n", renderedInstructions)
};
}

View file

@ -14,6 +14,7 @@ public class GeminiTextCompletionProvider : ITextCompletion
private string _model;
public string Provider => "google-ai";
public string Model => _model;
public GeminiTextCompletionProvider(
IServiceProvider services,
@ -74,7 +75,6 @@ public class GeminiTextCompletionProvider : ITextCompletion
_model = model;
}
private void PrepareOptions(GenerativeModel aiModel)
{
var settings = _services.GetRequiredService<GoogleAiSettings>();

View file

@ -14,6 +14,7 @@ public class PalmTextCompletionProvider : ITextCompletion
private string _model;
public string Provider => "google-palm";
public string Model => _model;
public PalmTextCompletionProvider(
IServiceProvider services,

View file

@ -10,10 +10,12 @@ namespace BotSharp.Plugin.HuggingFace.Providers;
public class ChatCompletionProvider : IChatCompletion
{
public string Provider => "huggingface";
public string Model => _model;
private readonly IServiceProvider _services;
private readonly HuggingFaceSettings _settings;
private readonly ILogger _logger;
private List<string> renderedInstructions = [];
private string _model;
public ChatCompletionProvider(IServiceProvider services,

View file

@ -8,6 +8,7 @@ public class ChatCompletionProvider : IChatCompletion
private readonly IServiceProvider _services;
private readonly ILogger _logger;
private readonly LlamaSharpSettings _settings;
private List<string> renderedInstructions = [];
private string _model;
public ChatCompletionProvider(IServiceProvider services,
@ -20,6 +21,7 @@ public class ChatCompletionProvider : IChatCompletion
}
public string Provider => "llama-sharp";
public string Model => _model;
public async Task<RoleDialogModel> GetChatCompletions(Agent agent, List<RoleDialogModel> conversations)
{
@ -64,7 +66,8 @@ public class ChatCompletionProvider : IChatCompletion
var msg = new RoleDialogModel(AgentRole.Assistant, totalResponse)
{
CurrentAgentId = agent.Id
CurrentAgentId = agent.Id,
RenderedInstruction = instruction
};
// After chat completion hook
@ -146,7 +149,8 @@ public class ChatCompletionProvider : IChatCompletion
var msg = new RoleDialogModel(AgentRole.Assistant, totalResponse)
{
CurrentAgentId = agent.Id
CurrentAgentId = agent.Id,
RenderedInstruction = agent.Instruction
};
// Text response received

View file

@ -10,6 +10,7 @@ public class TextCompletionProvider : ITextCompletion
private readonly ITokenStatistics _tokenStatistics;
private string _model;
public string Provider => "llama-sharp";
public string Model => _model;
public TextCompletionProvider(IServiceProvider services,
ILogger<TextCompletionProvider> logger,

View file

@ -1,6 +1,4 @@
using System.IO;
using System.Xml.Linq;
using static System.Net.Mime.MediaTypeNames;
namespace BotSharp.Plugin.LLamaSharp.Providers;
@ -14,6 +12,7 @@ public class TextEmbeddingProvider : ITextEmbedding
protected int _dimension = DEFAULT_DIMENSION;
public string Provider => "llama-sharp";
public string Model => string.Empty;
public TextEmbeddingProvider(IServiceProvider services, LlamaSharpSettings settings)
{

View file

@ -20,6 +20,8 @@ namespace BotSharp.Plugin.VertexAI.Providers
IServiceProvider services) : IChatCompletion
{
public string Provider => "vertexai";
public string Model => _model;
private readonly VertexAIConfiguration _config = config;
private readonly ChatSettings? _settings = settings;
private readonly IServiceProvider _services = services;

View file

@ -19,6 +19,8 @@ namespace BotSharp.Plugin.VertexAI.Providers
IServiceProvider services) : ITextCompletion
{
public string Provider => "vertexai";
public string Model => _model;
private readonly VertexAIConfiguration _config = config;
private readonly ChatSettings? _settings = settings;
private readonly IServiceProvider _services = services;

View file

@ -1,4 +1,5 @@
using BotSharp.Abstraction.MLTasks;
using BotSharp.Abstraction.Models;
using BotSharp.Plugin.MetaAI.Settings;
using FastText.NetWrapper;
using Microsoft.Extensions.DependencyInjection;
@ -17,6 +18,7 @@ public class fastTextEmbeddingProvider : ITextEmbedding
private int _dimension;
public string Provider => "meta-ai";
public string Model => string.Empty;
public fastTextEmbeddingProvider(IServiceProvider services)
{

View file

@ -5,11 +5,13 @@ namespace BotSharp.Plugin.MetaGLM.Providers;
public class ChatCompletionProvider : IChatCompletion
{
public string Provider => "metaglm";
public string Model => _model;
private readonly MetaGLMSettings _settings;
private readonly IServiceProvider _services;
private readonly ILogger _logger;
private readonly MetaGLMClient metaGLMClient;
private List<string> renderedInstructions = [];
private string _model;
public ChatCompletionProvider(IServiceProvider services,
@ -49,7 +51,8 @@ public class ChatCompletionProvider : IChatCompletion
responseMessage = new RoleDialogModel(AgentRole.Assistant, response?.choices.FirstOrDefault()?.message.content)
{
CurrentAgentId = agent.Id,
MessageId = conversations.Last().MessageId
MessageId = conversations.Last().MessageId,
RenderedInstruction = string.Join("\r\n", renderedInstructions)
};
}
@ -61,7 +64,8 @@ public class ChatCompletionProvider : IChatCompletion
CurrentAgentId = agent.Id,
MessageId = conversations.Last().MessageId,
FunctionName = toolcall.function.name,
FunctionArgs = toolcall.function.arguments
FunctionArgs = toolcall.function.arguments,
RenderedInstruction = string.Join("\r\n", renderedInstructions)
};
}
@ -87,10 +91,12 @@ public class ChatCompletionProvider : IChatCompletion
var agentService = _services.GetRequiredService<IAgentService>();
List<MessageItem> messages = new List<MessageItem>();
List<FunctionTool> toolcalls = new List<FunctionTool>();
renderedInstructions = [];
if (!string.IsNullOrEmpty(agent.Instruction) || !agent.SecondaryInstructions.IsNullOrEmpty())
{
var instruction = agentService.RenderedInstruction(agent);
renderedInstructions.Add(instruction);
messages.Add(new MessageItem("system", instruction));
}

View file

@ -27,6 +27,7 @@ public sealed class MicrosoftExtensionsAIChatCompletionProvider : IChatCompletio
private readonly IChatClient _client;
private readonly ILogger<MicrosoftExtensionsAIChatCompletionProvider> _logger;
private readonly IServiceProvider _services;
private List<string> renderedInstructions = [];
private string? _model;
/// <summary>
@ -45,6 +46,7 @@ public sealed class MicrosoftExtensionsAIChatCompletionProvider : IChatCompletio
/// <inheritdoc/>
public string Provider => "microsoft.extensions.ai";
public string Model => _model;
/// <inheritdoc/>
public void SetModelName(string model) => _model = model;
@ -54,6 +56,7 @@ public sealed class MicrosoftExtensionsAIChatCompletionProvider : IChatCompletio
{
// Before chat completion hook
var hooks = _services.GetServices<IContentGeneratingHook>().ToArray();
renderedInstructions = [];
await Task.WhenAll(hooks.Select(hook => hook.BeforeGenerating(agent, conversations)));
// Configure options
@ -82,6 +85,7 @@ public sealed class MicrosoftExtensionsAIChatCompletionProvider : IChatCompletio
if (_services.GetRequiredService<IAgentService>().RenderedInstruction(agent) is string instruction &&
instruction.Length > 0)
{
renderedInstructions.Add(instruction);
messages.Add(new(ChatRole.System, instruction));
}
@ -143,7 +147,8 @@ public sealed class MicrosoftExtensionsAIChatCompletionProvider : IChatCompletio
RoleDialogModel result = new(AgentRole.Assistant, string.Concat(completion.Message.Contents.OfType<TextContent>()))
{
CurrentAgentId = agent.Id
CurrentAgentId = agent.Id,
RenderedInstruction = string.Join("\r\n", renderedInstructions)
};
if (completion.Message.Contents.OfType<FunctionCallContent>().FirstOrDefault() is { } fcc)

View file

@ -24,6 +24,7 @@ public sealed class MicrosoftExtensionsAITextCompletionProvider : ITextCompletio
/// <inheritdoc/>
public string Provider => "microsoft-extensions-ai";
public string Model => _model;
/// <summary>
/// Creates an instance of the <see cref="MicrosoftExtensionsAITextCompletionProvider"/> class.

View file

@ -23,6 +23,7 @@ public sealed class MicrosoftExtensionsAITextEmbeddingProvider : ITextEmbedding
/// <inheritdoc/>
public string Provider => "microsoft-extensions-ai";
public string Model => _model;
/// <inheritdoc/>
public async Task<float[]> GetVectorAsync(string text) =>

View file

@ -1,5 +1,4 @@
using BotSharp.Abstraction.Loggers.Models;
using System.Text.Json;
namespace BotSharp.Plugin.MongoStorage.Collections;
@ -8,6 +7,10 @@ public class InstructionLogBetaDocument : MongoBase
public string? AgentId { get; set; }
public string Provider { get; set; } = default!;
public string Model { get; set; } = default!;
public string? TemplateName { get; set; }
public string UserMessage { get; set; } = default!;
public string? SystemInstruction { get; set; }
public string CompletionText { get; set; } = default!;
public string? UserId { get; set; }
public Dictionary<string, BsonDocument> States { get; set; } = new();
public DateTime CreatedTime { get; set; }
@ -19,6 +22,10 @@ public class InstructionLogBetaDocument : MongoBase
AgentId = log.AgentId,
Provider = log.Provider,
Model = log.Model,
TemplateName = log.TemplateName,
UserMessage = log.UserMessage,
SystemInstruction = log.SystemInstruction,
CompletionText = log.CompletionText,
UserId = log.UserId,
CreatedTime = log.CreatedTime
};
@ -28,9 +35,14 @@ public class InstructionLogBetaDocument : MongoBase
{
return new InstructionLogModel
{
Id = log.Id,
AgentId = log.AgentId,
Provider = log.Provider,
Model = log.Model,
TemplateName = log.TemplateName,
UserMessage = log.UserMessage,
SystemInstruction = log.SystemInstruction,
CompletionText = log.CompletionText,
UserId = log.UserId,
CreatedTime = log.CreatedTime
};

View file

@ -194,5 +194,5 @@ public class MongoDbContext
=> GetCollectionOrCreate<GlobalStatisticsDocument>("GlobalStatistics");
public IMongoCollection<InstructionLogBetaDocument> InstructionLogs
=> GetCollectionOrCreate<InstructionLogBetaDocument>("InstructionLogsBeta");
=> GetCollectionOrCreate<InstructionLogBetaDocument>("InstructionLogs");
}

View file

@ -1,5 +1,6 @@
using BotSharp.Abstraction.Instructs.Models;
using BotSharp.Abstraction.Loggers.Models;
using BotSharp.Abstraction.Repositories.Filters;
using System.Text.Json;
namespace BotSharp.Plugin.MongoStorage.Repository;
@ -167,28 +168,9 @@ public partial class MongoRepository
{
filters.Add(builder.In(x => x.Model, filter.Models));
}
if (!filter.States.IsNullOrEmpty())
if (!filter.TemplateNames.IsNullOrEmpty())
{
foreach (var pair in filter.States)
{
if (string.IsNullOrWhiteSpace(pair.Key)) continue;
// Format key
var keys = pair.Key.Split(".").ToList();
keys.Insert(1, "data");
keys.Insert(0, "States");
var formattedKey = string.Join(".", keys);
if (pair.Value == null)
{
filters.Add(builder.Exists(formattedKey));
}
else
{
filters.Add(builder.Eq(formattedKey, pair.Value));
}
}
filters.Add(builder.In(x => x.TemplateName, filter.TemplateNames));
}
var filterDef = builder.And(filters);
@ -196,10 +178,23 @@ public partial class MongoRepository
var docs = _dc.InstructionLogs.Find(filterDef).Sort(sortDef).Skip(filter.Offset).Limit(filter.Size).ToList();
var count = _dc.InstructionLogs.CountDocuments(filterDef);
var agentIds = docs.Where(x => !string.IsNullOrEmpty(x.AgentId)).Select(x => x.AgentId).ToList();
var agents = GetAgents(new AgentFilter
{
AgentIds = agentIds
});
var logs = docs.Select(x =>
{
var log = InstructionLogBetaDocument.ToDomainModel(x);
log.States = x.States.ToDictionary(x => x.Key, x => x.Value.GetElement("data").Value.ToString() ?? string.Empty);
log.AgentName = !string.IsNullOrEmpty(x.AgentId) ? agents.FirstOrDefault(a => a.Id == x.AgentId)?.Name : null;
log.States = x.States.ToDictionary(p => p.Key, p =>
{
var jsonStr = p.Value.ToJson();
var jsonDoc = JsonDocument.Parse(jsonStr);
var data = jsonDoc.RootElement.GetProperty("data");
return data.ValueKind != JsonValueKind.Null ? data.ToString() : null;
});
return log;
}).ToList();

View file

@ -7,6 +7,8 @@ public partial class AudioCompletionProvider : IAudioCompletion
private readonly IServiceProvider _services;
public string Provider => "openai";
public string Model => _model;
private string _model;
public AudioCompletionProvider(IServiceProvider service)

View file

@ -10,8 +10,10 @@ public class ChatCompletionProvider : IChatCompletion
protected readonly ILogger<ChatCompletionProvider> _logger;
protected string _model;
private List<string> renderedInstructions = [];
public virtual string Provider => "openai";
public string Model => _model;
public ChatCompletionProvider(
OpenAiSettings settings,
@ -53,7 +55,8 @@ public class ChatCompletionProvider : IChatCompletion
MessageId = conversations.LastOrDefault()?.MessageId ?? string.Empty,
ToolCallId = toolCall?.Id,
FunctionName = toolCall?.FunctionName,
FunctionArgs = toolCall?.FunctionArguments?.ToString()
FunctionArgs = toolCall?.FunctionArguments?.ToString(),
RenderedInstruction = string.Join("\r\n", renderedInstructions)
};
// Somethings LLM will generate a function name with agent name.
@ -68,6 +71,7 @@ public class ChatCompletionProvider : IChatCompletion
{
CurrentAgentId = agent.Id,
MessageId = conversations.LastOrDefault()?.MessageId ?? string.Empty,
RenderedInstruction = string.Join("\r\n", renderedInstructions)
};
}
@ -112,7 +116,8 @@ public class ChatCompletionProvider : IChatCompletion
var msg = new RoleDialogModel(AgentRole.Assistant, text)
{
CurrentAgentId = agent.Id
CurrentAgentId = agent.Id,
RenderedInstruction = string.Join("\r\n", renderedInstructions)
};
// After chat completion hook
@ -139,7 +144,8 @@ public class ChatCompletionProvider : IChatCompletion
MessageId = conversations.LastOrDefault()?.MessageId ?? string.Empty,
ToolCallId = toolCall?.Id,
FunctionName = toolCall?.FunctionName,
FunctionArgs = toolCall?.FunctionArguments?.ToString()
FunctionArgs = toolCall?.FunctionArguments?.ToString(),
RenderedInstruction = string.Join("\r\n", renderedInstructions)
};
// Somethings LLM will generate a function name with agent name.
@ -175,7 +181,10 @@ public class ChatCompletionProvider : IChatCompletion
var update = choice.ToolCallUpdates?.FirstOrDefault()?.FunctionArgumentsUpdate?.ToString() ?? string.Empty;
_logger.LogInformation(update);
await onMessageReceived(new RoleDialogModel(AgentRole.Assistant, update));
await onMessageReceived(new RoleDialogModel(AgentRole.Assistant, update)
{
RenderedInstruction = string.Join("\r\n", renderedInstructions)
});
continue;
}
@ -183,7 +192,10 @@ public class ChatCompletionProvider : IChatCompletion
_logger.LogInformation(choice.ContentUpdate[0]?.Text);
await onMessageReceived(new RoleDialogModel(choice.Role?.ToString() ?? ChatMessageRole.Assistant.ToString(), choice.ContentUpdate[0]?.Text ?? string.Empty));
await onMessageReceived(new RoleDialogModel(choice.Role?.ToString() ?? ChatMessageRole.Assistant.ToString(), choice.ContentUpdate[0]?.Text ?? string.Empty)
{
RenderedInstruction = string.Join("\r\n", renderedInstructions)
});
}
return true;
@ -198,6 +210,7 @@ public class ChatCompletionProvider : IChatCompletion
var settingsService = _services.GetRequiredService<ILlmProviderService>();
var settings = settingsService.GetSetting(Provider, _model);
var allowMultiModal = settings != null && settings.MultiModal;
renderedInstructions = [];
var messages = new List<ChatMessage>();
@ -227,6 +240,7 @@ public class ChatCompletionProvider : IChatCompletion
if (!string.IsNullOrEmpty(agent.Instruction) || !agent.SecondaryInstructions.IsNullOrEmpty())
{
var text = agentService.RenderedInstruction(agent);
renderedInstructions.Add(text);
messages.Add(new SystemChatMessage(text));
}

View file

@ -13,6 +13,7 @@ public class TextEmbeddingProvider : ITextEmbedding
protected int _dimension = DEFAULT_DIMENSION;
public virtual string Provider => "openai";
public string Model => _model;
public TextEmbeddingProvider(
OpenAiSettings settings,

View file

@ -14,6 +14,7 @@ public partial class ImageCompletionProvider : IImageCompletion
protected string _model;
public virtual string Provider => "openai";
public string Model => _model;
public ImageCompletionProvider(
OpenAiSettings settings,

View file

@ -15,6 +15,7 @@ public class TextCompletionProvider : ITextCompletion
protected string _model;
public virtual string Provider => "openai";
public string Model => _model;
public TextCompletionProvider(
OpenAiSettings settings,

View file

@ -26,6 +26,7 @@ namespace BotSharp.Plugin.SemanticKernel
/// <inheritdoc/>
public string Provider => "semantic-kernel";
public string Model => _model;
/// <summary>
/// Create a new instance of <see cref="SemanticKernelChatCompletionProvider"/>
@ -74,7 +75,8 @@ namespace BotSharp.Plugin.SemanticKernel
var response = chatMessageContent != null ? chatMessageContent.Content :string.Empty;
var msg = new RoleDialogModel(AgentRole.Assistant, response)
{
CurrentAgentId = agent.Id
CurrentAgentId = agent.Id,
RenderedInstruction = instruction
};
// After chat completion hook

View file

@ -23,6 +23,7 @@ namespace BotSharp.Plugin.SemanticKernel
/// <inheritdoc/>
public string Provider => "semantic-kernel";
public string Model => _model;
/// <summary>
/// Create a new instance of <see cref="SemanticKernelTextCompletionProvider"/>

View file

@ -1,4 +1,5 @@
using BotSharp.Abstraction.MLTasks;
using BotSharp.Abstraction.Models;
using Microsoft.Extensions.Configuration;
using Microsoft.SemanticKernel.Embeddings;
using System.Collections.Generic;
@ -33,6 +34,7 @@ namespace BotSharp.Plugin.SemanticKernel
protected int _dimension;
public string Provider => "semantic-kernel";
public string Model => string.Empty;
/// <inheritdoc/>
public async Task<float[]> GetVectorAsync(string text)

View file

@ -7,10 +7,12 @@ namespace BotSharp.Plugin.SparkDesk.Providers;
public class ChatCompletionProvider : IChatCompletion
{
public string Provider => "sparkdesk";
public string Model => _model;
private readonly SparkDeskSettings _settings;
private readonly IServiceProvider _services;
private readonly ILogger _logger;
private List<string> renderedInstructions = [];
private string _model;
public ChatCompletionProvider(IServiceProvider services,
@ -42,7 +44,8 @@ public class ChatCompletionProvider : IChatCompletion
var responseMessage = new RoleDialogModel(AgentRole.Assistant, response.Text)
{
CurrentAgentId = agent.Id,
MessageId = conversations.Last().MessageId
MessageId = conversations.Last().MessageId,
RenderedInstruction = string.Join("\r\n", renderedInstructions)
};
if (response.FunctionCall != null)
@ -52,7 +55,8 @@ public class ChatCompletionProvider : IChatCompletion
CurrentAgentId = agent.Id,
MessageId = conversations.Last().MessageId,
FunctionName = response.FunctionCall.Name,
FunctionArgs = response.FunctionCall.Arguments
FunctionArgs = response.FunctionCall.Arguments,
RenderedInstruction = string.Join("\r\n", renderedInstructions)
};
}
@ -92,7 +96,8 @@ public class ChatCompletionProvider : IChatCompletion
var msg = new RoleDialogModel(AgentRole.Assistant, response.Text)
{
CurrentAgentId = agent.Id
CurrentAgentId = agent.Id,
RenderedInstruction = string.Join("\r\n", renderedInstructions)
};
// After chat completion hook
@ -116,7 +121,8 @@ public class ChatCompletionProvider : IChatCompletion
{
CurrentAgentId = agent.Id,
FunctionName = response.FunctionCall.Name,
FunctionArgs = response.FunctionCall.Arguments
FunctionArgs = response.FunctionCall.Arguments,
RenderedInstruction = string.Join("\r\n", renderedInstructions)
};
// Somethings LLM will generate a function name with agent name.
@ -150,14 +156,16 @@ public class ChatCompletionProvider : IChatCompletion
{
CurrentAgentId = agent.Id,
FunctionName = response.FunctionCall.Name,
FunctionArgs = response.FunctionCall.Arguments
FunctionArgs = response.FunctionCall.Arguments,
RenderedInstruction = string.Join("\r\n", renderedInstructions)
});
continue;
}
await onMessageReceived(new RoleDialogModel(AgentRole.Assistant, response.Text)
{
CurrentAgentId = agent.Id
CurrentAgentId = agent.Id,
RenderedInstruction = string.Join("\r\n", renderedInstructions)
});
}
@ -175,10 +183,12 @@ public class ChatCompletionProvider : IChatCompletion
var functions = new List<FunctionDef>();
var agentService = _services.GetRequiredService<IAgentService>();
var messages = new List<ChatMessage>();
renderedInstructions = [];
if (!string.IsNullOrEmpty(agent.Instruction) || !agent.SecondaryInstructions.IsNullOrEmpty())
{
var instruction = agentService.RenderedInstruction(agent);
renderedInstructions.Add(instruction);
messages.Add(ChatMessage.FromSystem(instruction));
}
if (!string.IsNullOrEmpty(agent.Knowledges))