From dc2e3028eca7306a89390be1e88dd59a302f3c93 Mon Sep 17 00:00:00 2001
From: Jicheng Lu <103353@smsassist.com>
Date: Fri, 10 Oct 2025 11:39:45 -0500
Subject: [PATCH] refine llm config
---
.../Agents/Models/AgentLlmConfig.cs | 45 ++++++++++++++
.../Models/LlmConfigBase.cs | 18 +++---
.../FileInstructService.SelectFile.cs | 4 +-
.../Functions/ReadAudioFn.cs | 30 +++++-----
.../Settings/AudioHandlerSettings.cs | 2 +-
.../Functions/PlotChartFn.cs | 27 ++++-----
.../Functions/HandleEmailSenderFn.cs | 4 +-
.../Functions/ReadPdfFn.cs | 34 +++--------
.../Settings/FileHandlerSettings.cs | 2 +-
.../Functions/EditImageFn.cs | 58 +++++--------------
.../Functions/GenerateImageFn.cs | 52 ++++-------------
.../Functions/ReadImageFn.cs | 26 ++-------
.../Settings/ImageHandlerSettings.cs | 6 +-
.../Functions/PyProgrammerFn.cs | 22 +++----
src/WebStarter/appsettings.json | 32 +++++-----
15 files changed, 154 insertions(+), 208 deletions(-)
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentLlmConfig.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentLlmConfig.cs
index 75e3aa93..7c7c5325 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentLlmConfig.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentLlmConfig.cs
@@ -41,4 +41,49 @@ public class AgentLlmConfig
[JsonPropertyName("reasoning_effort_level")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? ReasoningEffortLevel { get; set; }
+
+ ///
+ /// Image generation config
+ ///
+ [JsonPropertyName("image_generation")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public LlmImageGenerationConfig? ImageGeneration { get; set; }
+
+ ///
+ /// Image edit config
+ ///
+ [JsonPropertyName("image_edit")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public LlmImageEditConfig? ImageEdit { get; set; }
+
+ ///
+ /// Audio transcription config
+ ///
+ [JsonPropertyName("audio_transcription")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public LlmAudioTranscriptionConfig? AudioTranscription { get; set; }
+
+ ///
+ /// Realtime config
+ ///
+ [JsonPropertyName("realtime")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public LlmRealtimeConfig? Realtime { get; set; }
}
+
+
+public class LlmImageGenerationConfig : LlmProviderModel
+{
+}
+
+public class LlmImageEditConfig : LlmProviderModel
+{
+}
+
+public class LlmRealtimeConfig : LlmProviderModel
+{
+}
+
+public class LlmAudioTranscriptionConfig : LlmProviderModel
+{
+}
\ No newline at end of file
diff --git a/src/Infrastructure/BotSharp.Abstraction/Models/LlmConfigBase.cs b/src/Infrastructure/BotSharp.Abstraction/Models/LlmConfigBase.cs
index 1d88942c..899f6e7a 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Models/LlmConfigBase.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Models/LlmConfigBase.cs
@@ -1,6 +1,6 @@
namespace BotSharp.Abstraction.Models;
-public class LlmConfigBase : LlmBase
+public class LlmConfigBase : LlmProviderModel
{
///
/// Llm maximum output tokens
@@ -13,15 +13,13 @@ public class LlmConfigBase : LlmBase
public string? ReasoningEffortLevel { get; set; }
}
-public class LlmBase
+public class LlmProviderModel
{
- ///
- /// Llm provider
- ///
- public string? LlmProvider { get; set; }
+ [JsonPropertyName("provider")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? Provider { get; set; }
- ///
- /// Llm model
- ///
- public string? LlmModel { get; set; }
+ [JsonPropertyName("model")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? Model { get; set; }
}
\ No newline at end of file
diff --git a/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.SelectFile.cs b/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.SelectFile.cs
index 50264576..a4cf2d88 100644
--- a/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.SelectFile.cs
+++ b/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.SelectFile.cs
@@ -153,8 +153,8 @@ public partial class FileInstructService
// 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);
diff --git a/src/Plugins/BotSharp.Plugin.AudioHandler/Functions/ReadAudioFn.cs b/src/Plugins/BotSharp.Plugin.AudioHandler/Functions/ReadAudioFn.cs
index 7306bb2a..4dd1ada3 100644
--- a/src/Plugins/BotSharp.Plugin.AudioHandler/Functions/ReadAudioFn.cs
+++ b/src/Plugins/BotSharp.Plugin.AudioHandler/Functions/ReadAudioFn.cs
@@ -34,9 +34,12 @@ public class ReadAudioFn : IFunctionCallback
public async Task Execute(RoleDialogModel message)
{
var args = JsonSerializer.Deserialize(message.FunctionArgs, _options.JsonSerializerOptions);
+ var agentService = _services.GetRequiredService();
var conv = _services.GetRequiredService();
var routingCtx = _services.GetRequiredService();
+ var agent = await agentService.GetAgent(message.CurrentAgentId);
+
var wholeDialogs = routingCtx.GetDialogs();
if (wholeDialogs.IsNullOrEmpty())
{
@@ -44,7 +47,7 @@ public class ReadAudioFn : IFunctionCallback
}
var dialogs = AssembleFiles(conv.ConversationId, wholeDialogs);
- var response = await GetAudioTranscription(dialogs);
+ var response = await GetAudioTranscription(agent, dialogs);
message.Content = response;
dialogs.ForEach(x => x.Files = null);
return true;
@@ -54,7 +57,7 @@ public class ReadAudioFn : IFunctionCallback
{
if (dialogs.IsNullOrEmpty())
{
- return new List();
+ return [];
}
var messageId = dialogs.Select(x => x.MessageId).Distinct().ToList();
@@ -85,13 +88,13 @@ public class ReadAudioFn : IFunctionCallback
return dialogs;
}
- private async Task GetAudioTranscription(List dialogs)
+ private async Task GetAudioTranscription(Agent agent, List dialogs)
{
- var audioCompletion = PrepareModel();
+ var audioCompletion = PrepareModel(agent);
var dialog = dialogs.Where(x => !x.Files.IsNullOrEmpty()).LastOrDefault();
var transcripts = new List();
- if (dialog != null)
+ if (dialog?.Files != null)
{
foreach (var file in dialog.Files)
{
@@ -129,9 +132,9 @@ public class ReadAudioFn : IFunctionCallback
return string.Join("\r\n\r\n", transcripts);
}
- private IAudioTranscription PrepareModel()
+ private IAudioTranscription PrepareModel(Agent agent)
{
- var (provider, model) = GetLlmProviderModel();
+ var (provider, model) = GetLlmProviderModel(agent);
return CompletionProvider.GetAudioTranscriber(_services, provider: provider, model: model);
}
@@ -142,21 +145,18 @@ public class ReadAudioFn : IFunctionCallback
|| !string.IsNullOrEmpty(FileUtility.GetFileContentType(fileName));
}
- private (string, string) GetLlmProviderModel()
+ private (string, string) GetLlmProviderModel(Agent agent)
{
- var state = _services.GetRequiredService();
- var llmProviderService = _services.GetRequiredService();
-
- var provider = state.GetState("audio_read_llm_provider");
- var model = state.GetState("audio_read_llm_provider");
+ var provider = agent?.LlmConfig?.AudioTranscription?.Provider;
+ var model = agent?.LlmConfig?.AudioTranscription?.Model;
if (!string.IsNullOrEmpty(provider) && !string.IsNullOrEmpty(model))
{
return (provider, model);
}
- provider = _settings?.Audio?.Reading?.LlmProvider;
- model = _settings?.Audio?.Reading?.LlmModel;
+ provider = _settings?.Audio?.Reading?.Provider;
+ model = _settings?.Audio?.Reading?.Model;
if (!string.IsNullOrEmpty(provider) && !string.IsNullOrEmpty(model))
{
diff --git a/src/Plugins/BotSharp.Plugin.AudioHandler/Settings/AudioHandlerSettings.cs b/src/Plugins/BotSharp.Plugin.AudioHandler/Settings/AudioHandlerSettings.cs
index b6353b05..8c4c1af0 100644
--- a/src/Plugins/BotSharp.Plugin.AudioHandler/Settings/AudioHandlerSettings.cs
+++ b/src/Plugins/BotSharp.Plugin.AudioHandler/Settings/AudioHandlerSettings.cs
@@ -13,7 +13,7 @@ public class AudioSettings
public AudioReadSettings? Reading { get; set; }
}
-public class AudioReadSettings : LlmBase
+public class AudioReadSettings : LlmProviderModel
{
}
#endregion
\ No newline at end of file
diff --git a/src/Plugins/BotSharp.Plugin.ChartHandler/Functions/PlotChartFn.cs b/src/Plugins/BotSharp.Plugin.ChartHandler/Functions/PlotChartFn.cs
index 1cac2c81..187e22ae 100644
--- a/src/Plugins/BotSharp.Plugin.ChartHandler/Functions/PlotChartFn.cs
+++ b/src/Plugins/BotSharp.Plugin.ChartHandler/Functions/PlotChartFn.cs
@@ -12,7 +12,6 @@ public class PlotChartFn : IFunctionCallback
public string Name => "util-chart-plot_chart";
public string Indication => "Plotting chart";
-
public PlotChartFn(
IServiceProvider services,
ILogger logger,
@@ -35,8 +34,8 @@ public class PlotChartFn : IFunctionCallback
var inst = GetChartPlotInstruction(message.CurrentAgentId);
var innerAgent = new Agent
{
- Id = agent.Id,
- Name = agent.Name,
+ Id = agent?.Id ?? BuiltInAgentId.AIProgrammer,
+ Name = agent?.Name ?? "AI Programmer",
Instruction = inst,
LlmConfig = GetLlmConfig(),
TemplateDict = new Dictionary
@@ -132,16 +131,16 @@ public class PlotChartFn : IFunctionCallback
private (string, string) GetLlmProviderModel()
{
- var provider = "openai";
- var model = "gpt-5";
+ var provider = _settings.ChartPlot?.Provider;
+ var model = _settings.ChartPlot?.Model;
- var state = _services.GetRequiredService();
- provider = state.GetState("chart_plot_llm_provider")
- .IfNullOrEmptyAs(_settings.ChartPlot?.LlmProvider)
- .IfNullOrEmptyAs(provider);
- model = state.GetState("chart_plot_llm_model")
- .IfNullOrEmptyAs(_settings.ChartPlot?.LlmModel)
- .IfNullOrEmptyAs(model);
+ if (!string.IsNullOrEmpty(provider) && !string.IsNullOrEmpty(model))
+ {
+ return (provider, model);
+ }
+
+ provider = "openai";
+ model = "gpt-5";
return (provider, model);
}
@@ -151,10 +150,6 @@ public class PlotChartFn : IFunctionCallback
var maxOutputTokens = _settings?.ChartPlot?.MaxOutputTokens ?? 8192;
var reasoningEffortLevel = _settings?.ChartPlot?.ReasoningEffortLevel ?? "minimal";
- var state = _services.GetRequiredService();
- maxOutputTokens = int.TryParse(state.GetState("chart_plot_max_output_tokens"), out var tokens) ? tokens : maxOutputTokens;
- reasoningEffortLevel = state.GetState("chart_plot_reasoning_effort_level").IfNullOrEmptyAs(reasoningEffortLevel);
-
return new AgentLlmConfig
{
MaxOutputTokens = maxOutputTokens,
diff --git a/src/Plugins/BotSharp.Plugin.EmailHandler/Functions/HandleEmailSenderFn.cs b/src/Plugins/BotSharp.Plugin.EmailHandler/Functions/HandleEmailSenderFn.cs
index 8352a848..e38233c3 100644
--- a/src/Plugins/BotSharp.Plugin.EmailHandler/Functions/HandleEmailSenderFn.cs
+++ b/src/Plugins/BotSharp.Plugin.EmailHandler/Functions/HandleEmailSenderFn.cs
@@ -76,8 +76,8 @@ public class HandleEmailSenderFn : IFunctionCallback
IsIncludeBotFiles = true,
IsAttachFiles = true,
MessageLimit = convSettings?.FileSelect?.MessageLimit,
- LlmProvider = convSettings?.FileSelect?.LlmProvider,
- LlmModel = convSettings?.FileSelect?.LlmModel,
+ Provider = convSettings?.FileSelect?.Provider,
+ Model = convSettings?.FileSelect?.Model,
MaxOutputTokens = convSettings?.FileSelect?.MaxOutputTokens,
ReasoningEffortLevel = convSettings?.FileSelect?.ReasoningEffortLevel
});
diff --git a/src/Plugins/BotSharp.Plugin.FileHandler/Functions/ReadPdfFn.cs b/src/Plugins/BotSharp.Plugin.FileHandler/Functions/ReadPdfFn.cs
index a2c2f4e5..c0f9236e 100644
--- a/src/Plugins/BotSharp.Plugin.FileHandler/Functions/ReadPdfFn.cs
+++ b/src/Plugins/BotSharp.Plugin.FileHandler/Functions/ReadPdfFn.cs
@@ -29,20 +29,15 @@ public class ReadPdfFn : IFunctionCallback
public async Task Execute(RoleDialogModel message)
{
var args = JsonSerializer.Deserialize(message.FunctionArgs);
+ var agentService = _services.GetRequiredService();
var conv = _services.GetRequiredService();
var routingCtx = _services.GetRequiredService();
- var agentService = _services.GetRequiredService();
-
- Agent? fromAgent = null;
- if (!string.IsNullOrEmpty(message.CurrentAgentId))
- {
- fromAgent = await agentService.GetAgent(message.CurrentAgentId);
- }
-
+
+ var fromAgent = await agentService.GetAgent(message.CurrentAgentId);
var agent = new Agent
{
- Id = fromAgent?.Id ?? BuiltInAgentId.UtilityAssistant,
- Name = fromAgent?.Name ?? "Utility Assistant",
+ Id = fromAgent?.Id ?? BuiltInAgentId.FileAssistant,
+ Name = fromAgent?.Name ?? "File Assistant",
Instruction = fromAgent?.Instruction ?? args?.UserRequest ?? "Please describe the pdf file(s).",
LlmConfig = fromAgent?.LlmConfig ?? new()
};
@@ -140,27 +135,16 @@ public class ReadPdfFn : IFunctionCallback
private (string, string) GetLlmProviderModel()
{
- var state = _services.GetRequiredService();
- var llmProviderService = _services.GetRequiredService();
-
- var provider = state.GetState("pdf_read_llm_provider");
- var model = state.GetState("pdf_read_llm_model");
+ var provider = _settings?.Pdf?.Reading?.Provider;
+ var model = _settings?.Pdf?.Reading?.Model;
if (!string.IsNullOrEmpty(provider) && !string.IsNullOrEmpty(model))
{
return (provider, model);
}
- provider = _settings?.Pdf?.Reading?.LlmProvider;
- model = _settings?.Pdf?.Reading?.LlmModel;
-
- if (!string.IsNullOrEmpty(provider) && !string.IsNullOrEmpty(model))
- {
- return (provider, model);
- }
-
- provider = "openai";
- model = "gpt-5-mini";
+ provider = "google-ai";
+ model = "gemini-2.0-flash";
return (provider, model);
}
diff --git a/src/Plugins/BotSharp.Plugin.FileHandler/Settings/FileHandlerSettings.cs b/src/Plugins/BotSharp.Plugin.FileHandler/Settings/FileHandlerSettings.cs
index 69889659..efbe8d11 100644
--- a/src/Plugins/BotSharp.Plugin.FileHandler/Settings/FileHandlerSettings.cs
+++ b/src/Plugins/BotSharp.Plugin.FileHandler/Settings/FileHandlerSettings.cs
@@ -13,7 +13,7 @@ public class PdfSettings
public PdfReadSettings? Reading { get; set; }
}
-public class PdfReadSettings : LlmBase
+public class PdfReadSettings : LlmProviderModel
{
public bool ConvertToImage { get; set; }
public string? ImageDetailLevel { get; set; }
diff --git a/src/Plugins/BotSharp.Plugin.ImageHandler/Functions/EditImageFn.cs b/src/Plugins/BotSharp.Plugin.ImageHandler/Functions/EditImageFn.cs
index d45c7237..31772771 100644
--- a/src/Plugins/BotSharp.Plugin.ImageHandler/Functions/EditImageFn.cs
+++ b/src/Plugins/BotSharp.Plugin.ImageHandler/Functions/EditImageFn.cs
@@ -11,7 +11,6 @@ public class EditImageFn : IFunctionCallback
private readonly ILogger _logger;
private readonly ImageHandlerSettings _settings;
- private Agent _agent;
private string _conversationId;
private string _messageId;
@@ -29,11 +28,15 @@ public class EditImageFn : IFunctionCallback
{
var args = JsonSerializer.Deserialize(message.FunctionArgs);
var descrpition = args?.UserRequest ?? string.Empty;
+
+ var agentService = _services.GetRequiredService();
+ var agent = await agentService.GetAgent(message.CurrentAgentId);
+
await Init(message);
SetImageOptions();
var image = await SelectImage(descrpition);
- var response = await GetImageEditGeneration(message, descrpition, image);
+ var response = await GetImageEdit(agent, message, descrpition, image);
message.Content = response;
message.StopCompletion = true;
return true;
@@ -41,10 +44,8 @@ public class EditImageFn : IFunctionCallback
private async Task Init(RoleDialogModel message)
{
- var agentService = _services.GetRequiredService();
var convService = _services.GetRequiredService();
- _agent = await agentService.GetAgent(message.CurrentAgentId);
_conversationId = convService.ConversationId;
_messageId = message.MessageId;
}
@@ -68,15 +69,15 @@ public class EditImageFn : IFunctionCallback
IsAttachFiles = true,
ContentTypes = [MediaTypeNames.Image.Png, MediaTypeNames.Image.Jpeg],
MessageLimit = convSettings?.FileSelect?.MessageLimit,
- LlmProvider = convSettings?.FileSelect?.LlmProvider,
- LlmModel = convSettings?.FileSelect?.LlmModel,
+ Provider = convSettings?.FileSelect?.Provider,
+ Model = convSettings?.FileSelect?.Model,
MaxOutputTokens = convSettings?.FileSelect?.MaxOutputTokens,
ReasoningEffortLevel = convSettings?.FileSelect?.ReasoningEffortLevel
});
return selecteds?.FirstOrDefault();
}
- private async Task GetImageEditGeneration(RoleDialogModel message, string description, MessageFileModel? image)
+ private async Task GetImageEdit(Agent agent, RoleDialogModel message, string description, MessageFileModel? image)
{
if (image == null)
{
@@ -85,15 +86,10 @@ public class EditImageFn : IFunctionCallback
try
{
- var (provider, model) = GetLlmProviderModel();
+ var (provider, model) = GetLlmProviderModel(agent);
var completion = CompletionProvider.GetImageCompletion(_services, provider: provider, model: model);
var text = !string.IsNullOrWhiteSpace(description) ? description : message.Content;
var dialog = RoleDialogModel.From(message, AgentRole.User, text);
- var agent = new Agent
- {
- Id = _agent?.Id ?? BuiltInAgentId.FileAssistant,
- Name = _agent?.Name ?? "File Assistant"
- };
var fileStorage = _services.GetRequiredService();
var fileBinary = fileStorage.GetFileBytes(image.FileStorageUrl);
@@ -112,7 +108,7 @@ public class EditImageFn : IFunctionCallback
return response.Content;
}
- return await GetImageEditResponse(description, defaultContent: null);
+ return await GetImageEditResponse(agent, description);
}
catch (Exception ex)
{
@@ -122,45 +118,23 @@ public class EditImageFn : IFunctionCallback
}
}
- private async Task GetImageEditResponse(string description, string? defaultContent)
+ private async Task GetImageEditResponse(Agent agent, string description)
{
- if (defaultContent != null)
- {
- return defaultContent;
- }
-
- var llmConfig = _agent.LlmConfig;
- var agent = new Agent
- {
- Id = _agent?.Id ?? BuiltInAgentId.FileAssistant,
- Name = _agent?.Name ?? "File Assistant",
- LlmConfig = new AgentLlmConfig
- {
- Provider = llmConfig?.Provider ?? "openai",
- Model = llmConfig?.Model ?? "gpt-5-mini",
- MaxOutputTokens = llmConfig?.MaxOutputTokens,
- ReasoningEffortLevel = llmConfig?.ReasoningEffortLevel
- }
- };
-
return await AiResponseHelper.GetImageGenerationResponse(_services, agent, description);
}
- private (string, string) GetLlmProviderModel()
+ private (string, string) GetLlmProviderModel(Agent agent)
{
- var state = _services.GetRequiredService();
- var llmProviderService = _services.GetRequiredService();
-
- var provider = state.GetState("image_edit_llm_provider");
- var model = state.GetState("image_edit_llm_provider");
+ var provider = agent?.LlmConfig?.ImageEdit?.Provider;
+ var model = agent?.LlmConfig?.ImageEdit?.Model;
if (!string.IsNullOrEmpty(provider) && !string.IsNullOrEmpty(model))
{
return (provider, model);
}
- provider = _settings?.Edit?.LlmProvider;
- model = _settings?.Edit?.LlmModel;
+ provider = _settings?.Edit?.Provider;
+ model = _settings?.Edit?.Model;
if (!string.IsNullOrEmpty(provider) && !string.IsNullOrEmpty(model))
{
diff --git a/src/Plugins/BotSharp.Plugin.ImageHandler/Functions/GenerateImageFn.cs b/src/Plugins/BotSharp.Plugin.ImageHandler/Functions/GenerateImageFn.cs
index b73d5869..ccb3e43c 100644
--- a/src/Plugins/BotSharp.Plugin.ImageHandler/Functions/GenerateImageFn.cs
+++ b/src/Plugins/BotSharp.Plugin.ImageHandler/Functions/GenerateImageFn.cs
@@ -9,7 +9,6 @@ public class GenerateImageFn : IFunctionCallback
private readonly ILogger _logger;
private readonly ImageHandlerSettings _settings;
- private Agent _agent;
private string _conversationId;
private string _messageId;
@@ -30,9 +29,9 @@ public class GenerateImageFn : IFunctionCallback
SetImageOptions();
var agentService = _services.GetRequiredService();
- _agent = await agentService.GetAgent(message.CurrentAgentId);
+ var currentAgent = await agentService.GetAgent(message.CurrentAgentId);
- var response = await GetImageGeneration(message, args?.ImageDescription);
+ var response = await GetImageGeneration(currentAgent, message, args?.ImageDescription);
message.Content = response;
message.StopCompletion = true;
return true;
@@ -53,18 +52,11 @@ public class GenerateImageFn : IFunctionCallback
state.SetState("image_response_format", "bytes");
}
- private async Task GetImageGeneration(RoleDialogModel message, string? description)
+ private async Task GetImageGeneration(Agent agent, RoleDialogModel message, string? description)
{
try
{
- var agent = new Agent
- {
- Id = _agent?.Id ?? BuiltInAgentId.FileAssistant,
- Name = _agent?.Name ?? "File Assistant",
- Instruction = description
- };
-
- var (provider, model) = GetLlmProviderModel();
+ var (provider, model) = GetLlmProviderModel(agent);
var completion = CompletionProvider.GetImageCompletion(_services, provider: provider, model: model);
var text = !string.IsNullOrWhiteSpace(description) ? description : message.Content;
var dialog = RoleDialogModel.From(message, AgentRole.User, text);
@@ -76,7 +68,7 @@ public class GenerateImageFn : IFunctionCallback
return result.Content;
}
- return await GetImageGenerationResponse(description, defaultContent: null);
+ return await GetImageGenerationResponse(agent, description);
}
catch (Exception ex)
{
@@ -86,45 +78,23 @@ public class GenerateImageFn : IFunctionCallback
}
}
- private async Task GetImageGenerationResponse(string description, string? defaultContent)
+ private async Task GetImageGenerationResponse(Agent agent, string description)
{
- if (defaultContent != null)
- {
- return defaultContent;
- }
-
- var llmConfig = _agent.LlmConfig;
- var agent = new Agent
- {
- Id = _agent?.Id ?? BuiltInAgentId.FileAssistant,
- Name = _agent?.Name ?? "File Assistant",
- LlmConfig = new AgentLlmConfig
- {
- Provider = llmConfig?.Provider ?? "openai",
- Model = llmConfig?.Model ?? "gpt-5-mini",
- MaxOutputTokens = llmConfig?.MaxOutputTokens,
- ReasoningEffortLevel = llmConfig?.ReasoningEffortLevel
- }
- };
-
return await AiResponseHelper.GetImageGenerationResponse(_services, agent, description);
}
- private (string, string) GetLlmProviderModel()
+ private (string, string) GetLlmProviderModel(Agent agent)
{
- var state = _services.GetRequiredService();
- var llmProviderService = _services.GetRequiredService();
-
- var provider = state.GetState("image_generate_llm_provider");
- var model = state.GetState("image_generate_llm_model");
+ var provider = agent?.LlmConfig?.ImageGeneration?.Provider;
+ var model = agent?.LlmConfig?.ImageGeneration?.Model;
if (!string.IsNullOrEmpty(provider) && !string.IsNullOrEmpty(model))
{
return (provider, model);
}
- provider = _settings?.Generation?.LlmProvider;
- model = _settings?.Generation?.LlmModel;
+ provider = _settings?.Generation?.Provider;
+ model = _settings?.Generation?.Model;
if (!string.IsNullOrEmpty(provider) && !string.IsNullOrEmpty(model))
{
diff --git a/src/Plugins/BotSharp.Plugin.ImageHandler/Functions/ReadImageFn.cs b/src/Plugins/BotSharp.Plugin.ImageHandler/Functions/ReadImageFn.cs
index 236e9f60..9a42f47d 100644
--- a/src/Plugins/BotSharp.Plugin.ImageHandler/Functions/ReadImageFn.cs
+++ b/src/Plugins/BotSharp.Plugin.ImageHandler/Functions/ReadImageFn.cs
@@ -30,16 +30,11 @@ public class ReadImageFn : IFunctionCallback
public async Task Execute(RoleDialogModel message)
{
var args = JsonSerializer.Deserialize(message.FunctionArgs);
+ var agentService = _services.GetRequiredService();
var conv = _services.GetRequiredService();
var routingCtx = _services.GetRequiredService();
- var agentService = _services.GetRequiredService();
-
- Agent? fromAgent = null;
- if (!string.IsNullOrEmpty(message.CurrentAgentId))
- {
- fromAgent = await agentService.GetAgent(message.CurrentAgentId);
- }
-
+
+ var fromAgent = await agentService.GetAgent(message.CurrentAgentId);
var agent = new Agent
{
Id = fromAgent?.Id ?? BuiltInAgentId.FileAssistant,
@@ -133,19 +128,8 @@ public class ReadImageFn : IFunctionCallback
private (string, string) GetLlmProviderModel()
{
- var state = _services.GetRequiredService();
- var llmProviderService = _services.GetRequiredService();
-
- var provider = state.GetState("image_read_llm_provider");
- var model = state.GetState("image_read_llm_model");
-
- if (!string.IsNullOrEmpty(provider) && !string.IsNullOrEmpty(model))
- {
- return (provider, model);
- }
-
- provider = _settings?.Reading?.LlmProvider;
- model = _settings?.Reading?.LlmModel;
+ var provider = _settings?.Reading?.Provider;
+ var model = _settings?.Reading?.Model;
if (!string.IsNullOrEmpty(provider) && !string.IsNullOrEmpty(model))
{
diff --git a/src/Plugins/BotSharp.Plugin.ImageHandler/Settings/ImageHandlerSettings.cs b/src/Plugins/BotSharp.Plugin.ImageHandler/Settings/ImageHandlerSettings.cs
index b8f147b9..81a11c8d 100644
--- a/src/Plugins/BotSharp.Plugin.ImageHandler/Settings/ImageHandlerSettings.cs
+++ b/src/Plugins/BotSharp.Plugin.ImageHandler/Settings/ImageHandlerSettings.cs
@@ -9,17 +9,17 @@ public class ImageHandlerSettings
public ImageEditSettings? Edit { get; set; }
}
-public class ImageReadSettings : LlmBase
+public class ImageReadSettings : LlmProviderModel
{
public string? ImageDetailLevel { get; set; }
}
-public class ImageGenerationSettings : LlmBase
+public class ImageGenerationSettings : LlmProviderModel
{
}
-public class ImageEditSettings : LlmBase
+public class ImageEditSettings : LlmProviderModel
{
public SettingBase? ImageConverter { get; set; }
}
\ No newline at end of file
diff --git a/src/Plugins/BotSharp.Plugin.PythonInterpreter/Functions/PyProgrammerFn.cs b/src/Plugins/BotSharp.Plugin.PythonInterpreter/Functions/PyProgrammerFn.cs
index 0a69b7a8..45a1e778 100644
--- a/src/Plugins/BotSharp.Plugin.PythonInterpreter/Functions/PyProgrammerFn.cs
+++ b/src/Plugins/BotSharp.Plugin.PythonInterpreter/Functions/PyProgrammerFn.cs
@@ -186,16 +186,16 @@ public class PyProgrammerFn : IFunctionCallback
private (string, string) GetLlmProviderModel()
{
- var provider = "openai";
- var model = "gpt-5";
+ var provider = _settings.CodeGeneration?.Provider;
+ var model = _settings.CodeGeneration?.Model;
- var state = _services.GetRequiredService();
- provider = state.GetState("py_intepreter_llm_provider")
- .IfNullOrEmptyAs(_settings.CodeGeneration?.LlmProvider)
- .IfNullOrEmptyAs(provider);
- model = state.GetState("py_intepreter_llm_model")
- .IfNullOrEmptyAs(_settings.CodeGeneration?.LlmModel)
- .IfNullOrEmptyAs(model);
+ if (!string.IsNullOrEmpty(provider) && !string.IsNullOrEmpty(model))
+ {
+ return (provider, model);
+ }
+
+ provider = "openai";
+ model = "gpt-5";
return (provider, model);
}
@@ -205,10 +205,6 @@ public class PyProgrammerFn : IFunctionCallback
var maxOutputTokens = _settings?.CodeGeneration?.MaxOutputTokens ?? 8192;
var reasoningEffortLevel = _settings?.CodeGeneration?.ReasoningEffortLevel ?? "minimal";
- var state = _services.GetRequiredService();
- maxOutputTokens = int.TryParse(state.GetState("py_intepreter_max_output_tokens"), out var tokens) ? tokens : maxOutputTokens;
- reasoningEffortLevel = state.GetState("py_intepreter_reasoning_effort_level").IfNullOrEmptyAs(reasoningEffortLevel);
-
return new AgentLlmConfig
{
MaxOutputTokens = maxOutputTokens,
diff --git a/src/WebStarter/appsettings.json b/src/WebStarter/appsettings.json
index b067b052..276f853e 100644
--- a/src/WebStarter/appsettings.json
+++ b/src/WebStarter/appsettings.json
@@ -301,8 +301,8 @@
"MinTimeSecondsBetweenMessages": 2
},
"FileSelect": {
- "LlmProvider": "openai",
- "LlmModel": "gpt-5-mini",
+ "Provider": "openai",
+ "Model": "gpt-5-mini",
"MaxOutputTokens": 8192,
"ReasoningEffortLevel": "low",
"MessageLimit": 50
@@ -433,8 +433,8 @@
"FileHandler": {
"Pdf": {
"Reading": {
- "LlmProvider": "google-ai",
- "LlmModel": "gemini-2.0-flash",
+ "Provider": "google-ai",
+ "Model": "gemini-2.0-flash",
"ConvertToImage": false,
"ImageDetailLevel": "auto",
"ImageConverter": {
@@ -446,17 +446,17 @@
"ImageHandler": {
"Reading": {
- "LlmProvider": "openai",
- "LlmModel": "gpt-5-mini",
+ "Provider": "openai",
+ "Model": "gpt-5-mini",
"ImageDetailLevel": "auto"
},
"Generation": {
- "LlmProvider": "openai",
- "LlmModel": "gpt-image-1"
+ "Provider": "openai",
+ "Model": "gpt-image-1"
},
"Edit": {
- "LlmProvider": "openai",
- "LlmModel": "gpt-image-1",
+ "Provider": "openai",
+ "Model": "gpt-image-1",
"ImageConverter": {
"Provider": "image-handler"
}
@@ -466,8 +466,8 @@
"AudioHandler": {
"Audio": {
"Reading": {
- "LlmProvider": "openai",
- "LlmModel": "gpt-4o-mini-transcribe"
+ "Provider": "openai",
+ "Model": "gpt-4o-mini-transcribe"
}
}
},
@@ -486,8 +486,8 @@
"ChartHandler": {
"ChartPlot": {
- "LlmProvider": "openai",
- "LlmModel": "gpt-5",
+ "Provider": "openai",
+ "Model": "gpt-5",
"MaxOutputTokens": 8192,
"ReasoningEffortLevel": "minimal",
"MessageLimit": 50
@@ -570,8 +570,8 @@
"InstallLocation": "C:/Users/xxx/AppData/Local/Programs/Python/Python313/python313.dll",
"PythonVersion": "3.13.3",
"CodeGeneration": {
- "LlmProvider": "openai",
- "LlmModel": "gpt-5",
+ "Provider": "openai",
+ "Model": "gpt-5",
"MaxOutputTokens": 8192,
"ReasoningEffortLevel": "minimal",
"MessageLimit": 50