Skip to content
Draft
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
11 changes: 11 additions & 0 deletions BotSharp.sln
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.Plugin.ChartHandle
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.Plugin.ExcelHandler", "src\Plugins\BotSharp.Plugin.ExcelHandler\BotSharp.Plugin.ExcelHandler.csproj", "{FC63C875-E880-D8BB-B8B5-978AB7B62983}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.Plugin.ImageHandler", "src\Plugins\BotSharp.Plugin.ImageHandler\BotSharp.Plugin.ImageHandler.csproj", "{242F2D93-FCCE-4982-8075-F3052ECCA92C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -619,6 +621,14 @@ Global
{FC63C875-E880-D8BB-B8B5-978AB7B62983}.Release|Any CPU.Build.0 = Release|Any CPU
{FC63C875-E880-D8BB-B8B5-978AB7B62983}.Release|x64.ActiveCfg = Release|Any CPU
{FC63C875-E880-D8BB-B8B5-978AB7B62983}.Release|x64.Build.0 = Release|Any CPU
{242F2D93-FCCE-4982-8075-F3052ECCA92C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{242F2D93-FCCE-4982-8075-F3052ECCA92C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{242F2D93-FCCE-4982-8075-F3052ECCA92C}.Debug|x64.ActiveCfg = Debug|Any CPU
{242F2D93-FCCE-4982-8075-F3052ECCA92C}.Debug|x64.Build.0 = Debug|Any CPU
{242F2D93-FCCE-4982-8075-F3052ECCA92C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{242F2D93-FCCE-4982-8075-F3052ECCA92C}.Release|Any CPU.Build.0 = Release|Any CPU
{242F2D93-FCCE-4982-8075-F3052ECCA92C}.Release|x64.ActiveCfg = Release|Any CPU
{242F2D93-FCCE-4982-8075-F3052ECCA92C}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -690,6 +700,7 @@ Global
{B067B126-88CD-4282-BEEF-7369B64423EF} = {32FAFFFE-A4CB-4FEE-BF7C-84518BBC6DCC}
{0428DEAA-E4FE-4259-A6D8-6EDD1A9D0702} = {51AFE054-AE99-497D-A593-69BAEFB5106F}
{FC63C875-E880-D8BB-B8B5-978AB7B62983} = {51AFE054-AE99-497D-A593-69BAEFB5106F}
{242F2D93-FCCE-4982-8075-F3052ECCA92C} = {51AFE054-AE99-497D-A593-69BAEFB5106F}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A9969D89-C98B-40A5-A12B-FC87E55B3A19}
Expand Down
10 changes: 10 additions & 0 deletions src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using BotSharp.Abstraction.Agents.Options;
using BotSharp.Abstraction.Functions.Models;
using BotSharp.Abstraction.Plugins.Models;
using BotSharp.Abstraction.Repositories.Filters;
Expand Down Expand Up @@ -65,4 +66,13 @@ public interface IAgentService
Task<List<UserAgent>> GetUserAgents(string userId);

PluginDef GetPlugin(string agentId);

Task<List<AgentCodeScript>> GetAgentCodeScripts(string agentId, AgentCodeScriptFilter? filter = null)
=> Task.FromResult(new List<AgentCodeScript>());

Task<string?> GetAgentCodeScript(string agentId, string scriptName, string scriptType = AgentCodeScriptType.Src)
=> Task.FromResult(string.Empty);

Task<bool> UpdateAgentCodeScripts(string agentId, List<AgentCodeScript> codeScripts, AgentCodeScriptUpdateOptions? options = null)
=> Task.FromResult(false);
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,49 @@ public class AgentLlmConfig
[JsonPropertyName("reasoning_effort_level")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? ReasoningEffortLevel { get; set; }

/// <summary>
/// Image generation config
/// </summary>
[JsonPropertyName("image_generation")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public LlmImageGenerationConfig? ImageGeneration { get; set; }

/// <summary>
/// Image edit config
/// </summary>
[JsonPropertyName("image_edit")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public LlmImageEditConfig? ImageEdit { get; set; }

/// <summary>
/// Audio transcription config
/// </summary>
[JsonPropertyName("audio_transcription")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public LlmAudioTranscriptionConfig? AudioTranscription { get; set; }

/// <summary>
/// Realtime config
/// </summary>
[JsonPropertyName("realtime")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public LlmRealtimeConfig? Realtime { get; set; }
}


public class LlmImageGenerationConfig : LlmProviderModel
{
}

public class LlmImageEditConfig : LlmProviderModel
{
}

public class LlmAudioTranscriptionConfig : LlmProviderModel
{
}

public class LlmRealtimeConfig : LlmProviderModel
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using BotSharp.Abstraction.Repositories.Models;

namespace BotSharp.Abstraction.Agents.Options;

public class AgentCodeScriptUpdateOptions : AgentCodeScriptDbUpdateOptions
{
public bool DeleteIfNotIncluded { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,6 @@ public string RoleContent
{
text = !string.IsNullOrWhiteSpace(Payload) ? Payload : Content;
}
else
{
text = !string.IsNullOrWhiteSpace(Content) ? Content : RichContent?.Message?.Text;
}

return text;
}
Expand Down
18 changes: 8 additions & 10 deletions src/Infrastructure/BotSharp.Abstraction/Models/LlmConfigBase.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace BotSharp.Abstraction.Models;

public class LlmConfigBase : LlmBase
public class LlmConfigBase : LlmProviderModel
{
/// <summary>
/// Llm maximum output tokens
Expand All @@ -13,15 +13,13 @@ public class LlmConfigBase : LlmBase
public string? ReasoningEffortLevel { get; set; }
}

public class LlmBase
public class LlmProviderModel
{
/// <summary>
/// Llm provider
/// </summary>
public string? LlmProvider { get; set; }
[JsonPropertyName("provider")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? Provider { get; set; }

/// <summary>
/// Llm model
/// </summary>
public string? LlmModel { get; set; }
[JsonPropertyName("model")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? Model { get; set; }
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using BotSharp.Abstraction.Loggers.Models;
using BotSharp.Abstraction.Plugins.Models;
using BotSharp.Abstraction.Repositories.Filters;
using BotSharp.Abstraction.Repositories.Models;
using BotSharp.Abstraction.Roles.Models;
using BotSharp.Abstraction.Shared;
using BotSharp.Abstraction.Statistics.Enums;
Expand Down Expand Up @@ -43,7 +44,7 @@
List<User> GetUsersByAffiliateId(string affiliateId) => throw new NotImplementedException();
User? GetUserByUserName(string userName) => throw new NotImplementedException();
void UpdateUserName(string userId, string userName) => throw new NotImplementedException();
Dashboard? GetDashboard(string id = null) => throw new NotImplementedException();

Check warning on line 47 in src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest)

Cannot convert null literal to non-nullable reference type.

Check warning on line 47 in src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest)

Cannot convert null literal to non-nullable reference type.

Check warning on line 47 in src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

Cannot convert null literal to non-nullable reference type.

Check warning on line 47 in src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

Cannot convert null literal to non-nullable reference type.

Check warning on line 47 in src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Cannot convert null literal to non-nullable reference type.

Check warning on line 47 in src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Cannot convert null literal to non-nullable reference type.
void CreateUser(User user) => throw new NotImplementedException();
void UpdateExistUser(string userId, User user) => throw new NotImplementedException();
void UpdateUserVerified(string userId) => throw new NotImplementedException();
Expand Down Expand Up @@ -111,7 +112,7 @@
=> throw new NotImplementedException();
string? GetAgentCodeScript(string agentId, string scriptName, string scriptType = AgentCodeScriptType.Src)
=> throw new NotImplementedException();
bool UpdateAgentCodeScripts(string agentId, List<AgentCodeScript> scripts)
bool UpdateAgentCodeScripts(string agentId, List<AgentCodeScript> scripts, AgentCodeScriptDbUpdateOptions? options = null)
=> throw new NotImplementedException();
bool BulkInsertAgentCodeScripts(string agentId, List<AgentCodeScript> scripts)
=> throw new NotImplementedException();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace BotSharp.Abstraction.Repositories.Models;

public class AgentCodeScriptDbUpdateOptions
{
public bool IsUpsert { get; set; }
}
41 changes: 35 additions & 6 deletions src/Infrastructure/BotSharp.Core.Realtime/Services/RealtimeHub.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Functions.Models;
using BotSharp.Abstraction.Hooks;
using BotSharp.Abstraction.Models;
Expand All @@ -10,18 +11,23 @@ namespace BotSharp.Core.Realtime.Services;
public class RealtimeHub : IRealtimeHub
{
private readonly IServiceProvider _services;
private readonly ILogger _logger;
private readonly ILogger<RealtimeHub> _logger;
private readonly RealtimeModelSettings _settings;

private RealtimeHubConnection _conn;
public RealtimeHubConnection HubConn => _conn;

private IRealTimeCompletion _completer;
public IRealTimeCompletion Completer => _completer;

public RealtimeHub(IServiceProvider services, ILogger<RealtimeHub> logger)
public RealtimeHub(
IServiceProvider services,
ILogger<RealtimeHub> logger,
RealtimeModelSettings settings)
{
_services = services;
_logger = logger;
_settings = settings;
}

public async Task ConnectToModel(
Expand All @@ -43,10 +49,10 @@ public async Task ConnectToModel(
routing.Context.SetDialogs(dialogs);
routing.Context.SetMessageId(_conn.ConversationId, Guid.Empty.ToString());

var states = _services.GetRequiredService<IConversationStateService>();
var settings = _services.GetRequiredService<RealtimeModelSettings>();
var (provider, model) = GetLlmProviderModel(agent);

_completer = _services.GetServices<IRealTimeCompletion>().First(x => x.Provider == settings.Provider);
_completer = _services.GetServices<IRealTimeCompletion>().First(x => x.Provider == provider);
_completer.SetModelName(model);
_completer.SetOptions(options);

await _completer.Connect(
Expand Down Expand Up @@ -156,7 +162,7 @@ await HookEmitter.Emit<IRoutingHook>(_services, async hook => await hook.OnRouti
},
onInterruptionDetected: async () =>
{
if (settings.InterruptResponse)
if (_settings.InterruptResponse)
{
// Reset states
_conn.ResetResponseState();
Expand All @@ -179,4 +185,27 @@ public RealtimeHubConnection SetHubConnection(string conversationId)

return _conn;
}

private (string, string) GetLlmProviderModel(Agent agent)
{
var provider = agent?.LlmConfig?.Realtime?.Provider;
var model = agent?.LlmConfig?.Realtime?.Model;

if (!string.IsNullOrEmpty(provider) && !string.IsNullOrEmpty(model))
{
return (provider, model);
}

provider = _settings.Provider;
model = _settings.Model;

if (!string.IsNullOrEmpty(provider) && !string.IsNullOrEmpty(model))
{
return (provider, model);
}

provider = "openai";
model = "gpt-realtime";
return (provider, model);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using BotSharp.Abstraction.Agents.Options;

namespace BotSharp.Core.Agents.Services;

public partial class AgentService
{
public async Task<List<AgentCodeScript>> GetAgentCodeScripts(string agentId, AgentCodeScriptFilter? filter = null)
{
var db = _services.GetRequiredService<IBotSharpRepository>();
var scripts = db.GetAgentCodeScripts(agentId, filter);
return await Task.FromResult(scripts);
}

public async Task<string?> GetAgentCodeScript(string agentId, string scriptName, string scriptType = AgentCodeScriptType.Src)
{
var db = _services.GetRequiredService<IBotSharpRepository>();
var script = db.GetAgentCodeScript(agentId, scriptName, scriptType);
return await Task.FromResult(script);
}

public async Task<bool> UpdateAgentCodeScripts(string agentId, List<AgentCodeScript> codeScripts, AgentCodeScriptUpdateOptions? options = null)
{
if (string.IsNullOrWhiteSpace(agentId) || codeScripts.IsNullOrEmpty())
{
return false;
}

var db = _services.GetRequiredService<IBotSharpRepository>();

var toDeleteScripts = new List<AgentCodeScript>();
if (options?.DeleteIfNotIncluded == true)
{
var curDbScripts = await GetAgentCodeScripts(agentId);
var codePaths = codeScripts.Select(x => x.CodePath).ToList();
toDeleteScripts = curDbScripts.Where(x => !codePaths.Contains(x.CodePath)).ToList();
}

var updateResult = db.UpdateAgentCodeScripts(agentId, codeScripts, options);
if (!toDeleteScripts.IsNullOrEmpty())
{
db.DeleteAgentCodeScripts(agentId, toDeleteScripts);
}

return updateResult;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,8 @@ private async Task<IEnumerable<MessageFileModel>> SelectFiles(IEnumerable<Messag
var foundAgent = await agentService.GetAgent(agentId);
var agent = new Agent
{
Id = foundAgent?.Id ?? BuiltInAgentId.UtilityAssistant,
Name = foundAgent?.Name ?? "Utility Assistant",
Id = foundAgent?.Id ?? BuiltInAgentId.FileAssistant,
Name = foundAgent?.Name ?? "File Assistant",
Instruction = prompt,
LlmConfig = new AgentLlmConfig
{
Expand All @@ -153,8 +153,8 @@ private async Task<IEnumerable<MessageFileModel>> SelectFiles(IEnumerable<Messag


// Get ai response
var provider = options.LlmProvider ?? "openai";
var model = options?.LlmModel ?? "gpt-5-mini";
var provider = options.Provider ?? "openai";
var model = options?.Model ?? "gpt-5-mini";
var completion = CompletionProvider.GetChatCompletion(_services, provider: provider, model: model);

var response = await completion.GetChatCompletions(agent, innerDialogs);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,8 @@ await hook.OnResponseGenerated(new InstructResponseModel
return response;
}


var agentService = _services.GetRequiredService<IAgentService>();
var state = _services.GetRequiredService<IConversationStateService>();
var db = _services.GetRequiredService<IBotSharpRepository>();
var hooks = _services.GetHooks<IInstructHook>(agent.Id);

var codeProvider = codeOptions?.CodeInterpretProvider ?? "botsharp-py-interpreter";
Expand Down Expand Up @@ -187,7 +186,7 @@ await hook.OnResponseGenerated(new InstructResponseModel
}

// Get code script
var codeScript = db.GetAgentCodeScript(agent.Id, scriptName, scriptType: AgentCodeScriptType.Src);
var codeScript = await agentService.GetAgentCodeScript(agent.Id, scriptName, scriptType: AgentCodeScriptType.Src);
if (string.IsNullOrWhiteSpace(codeScript))
{
#if DEBUG
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using BotSharp.Abstraction.Repositories.Models;
using System.IO;

namespace BotSharp.Core.Repository;
Expand Down Expand Up @@ -73,7 +74,7 @@ public List<AgentCodeScript> GetAgentCodeScripts(string agentId, AgentCodeScript
return string.Empty;
}

public bool UpdateAgentCodeScripts(string agentId, List<AgentCodeScript> scripts)
public bool UpdateAgentCodeScripts(string agentId, List<AgentCodeScript> scripts, AgentCodeScriptDbUpdateOptions? options = null)
{
if (string.IsNullOrWhiteSpace(agentId) || scripts.IsNullOrEmpty())
{
Expand All @@ -95,7 +96,10 @@ public bool UpdateAgentCodeScripts(string agentId, List<AgentCodeScript> scripts
}

var file = Path.Combine(dir, script.Name);
File.WriteAllText(file, script.Content);
if (options?.IsUpsert == true || File.Exists(file))
{
File.WriteAllText(file, script.Content);
}
}

return true;
Expand Down
Loading
Loading