diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentLlmConfig.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentLlmConfig.cs
index 6ed259a3..be75a01e 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentLlmConfig.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentLlmConfig.cs
@@ -35,6 +35,21 @@ public class AgentLlmConfig
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public int? MaxOutputTokens { get; set; }
+ ///
+ /// Sampling temperature override for this agent. null (the default) inherits the
+ /// conversation state / provider settings, so an unset field never changes global behavior.
+ ///
+ [JsonPropertyName("temperature")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public float? Temperature { get; set; }
+
+ ///
+ /// Nucleus sampling (top-p) override for this agent. null inherits the defaults.
+ ///
+ [JsonPropertyName("top_p")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public float? TopP { get; set; }
+
///
/// Reasoning effort level
///
diff --git a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/Chat/ChatCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/Chat/ChatCompletionProvider.cs
index dc9a0fbc..62d2d18c 100644
--- a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/Chat/ChatCompletionProvider.cs
+++ b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/Chat/ChatCompletionProvider.cs
@@ -565,23 +565,33 @@ public class ChatCompletionProvider : IChatCompletion
var settingsService = _services.GetRequiredService();
var settings = settingsService.GetSetting(Provider, _model);
+ // Sampling: an explicit conversation state wins, then the agent's own override, then the
+ // model's configured reasoning defaults. Unset everywhere keeps the historical 0.0 fallback.
+ float? temperature = null;
+ if (state.ContainsState("temperature") && float.TryParse(state.GetState("temperature"), out var stateTemperature))
+ temperature = stateTemperature;
+ temperature ??= agent?.LlmConfig?.Temperature;
+ temperature ??= settings?.Reasoning?.Temperature;
+ temperature ??= 0.2f;
+
+ float? topP = null;
+ if (state.ContainsState("top_p") && float.TryParse(state.GetState("top_p"), out var stateTopP))
+ topP = stateTopP;
+ topP ??= agent?.LlmConfig?.TopP;
+
// Reasoning effort
ChatReasoningEffortLevel? reasoningEffortLevel = null;
- float? temperature = float.Parse(state.GetState("temperature", "0.0"));
- if (settings?.Reasoning != null)
- {
- temperature = settings.Reasoning.Temperature;
- var level = state.GetState("reasoning_effort_level")
- .IfNullOrEmptyAs(agent?.LlmConfig?.ReasoningEffortLevel)
- .IfNullOrEmptyAs(settings?.Reasoning?.EffortLevel);
- reasoningEffortLevel = ParseReasoningEffortLevel(level);
- }
+ var level = state.GetState("reasoning_effort_level")
+ .IfNullOrEmptyAs(agent?.LlmConfig?.ReasoningEffortLevel)
+ .IfNullOrEmptyAs(settings?.Reasoning?.EffortLevel);
+ reasoningEffortLevel = ParseReasoningEffortLevel(level);
// Web search
ChatWebSearchOptions? webSearchOptions = null;
if (settings?.WebSearch != null)
{
temperature = null;
+ topP = null;
reasoningEffortLevel = null;
webSearchOptions = new();
}
@@ -593,6 +603,7 @@ public class ChatCompletionProvider : IChatCompletion
return new ChatCompletionOptions()
{
Temperature = temperature,
+ TopP = topP,
MaxOutputTokenCount = maxTokens,
ReasoningEffortLevel = reasoningEffortLevel,
WebSearchOptions = webSearchOptions
diff --git a/src/Plugins/BotSharp.Plugin.DeepSeekAI/Providers/Chat/ChatCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.DeepSeekAI/Providers/Chat/ChatCompletionProvider.cs
index eebc64d1..bb684dbc 100644
--- a/src/Plugins/BotSharp.Plugin.DeepSeekAI/Providers/Chat/ChatCompletionProvider.cs
+++ b/src/Plugins/BotSharp.Plugin.DeepSeekAI/Providers/Chat/ChatCompletionProvider.cs
@@ -691,23 +691,33 @@ public class ChatCompletionProvider : IChatCompletion
var settingsService = _services.GetRequiredService();
var settings = settingsService.GetSetting(Provider, _model);
+ // Sampling: an explicit conversation state wins, then the agent's own override, then the
+ // model's configured reasoning defaults. Unset everywhere keeps the historical 0.0 fallback.
+ float? temperature = null;
+ if (state.ContainsState("temperature") && float.TryParse(state.GetState("temperature"), out var stateTemperature))
+ temperature = stateTemperature;
+ temperature ??= agent?.LlmConfig?.Temperature;
+ temperature ??= settings?.Reasoning?.Temperature;
+ temperature ??= 0.2f;
+
+ float? topP = null;
+ if (state.ContainsState("top_p") && float.TryParse(state.GetState("top_p"), out var stateTopP))
+ topP = stateTopP;
+ topP ??= agent?.LlmConfig?.TopP;
+
// Reasoning effort
ChatReasoningEffortLevel? reasoningEffortLevel = null;
- float? temperature = float.Parse(state.GetState("temperature", "0.0"));
- if (settings?.Reasoning != null)
- {
- temperature = settings.Reasoning.Temperature;
- var level = state.GetState("reasoning_effort_level")
- .IfNullOrEmptyAs(agent?.LlmConfig?.ReasoningEffortLevel)
- .IfNullOrEmptyAs(settings?.Reasoning?.EffortLevel);
- reasoningEffortLevel = ParseReasoningEffortLevel(level);
- }
+ var level = state.GetState("reasoning_effort_level")
+ .IfNullOrEmptyAs(agent?.LlmConfig?.ReasoningEffortLevel)
+ .IfNullOrEmptyAs(settings?.Reasoning?.EffortLevel);
+ reasoningEffortLevel = ParseReasoningEffortLevel(level);
// Web search
ChatWebSearchOptions? webSearchOptions = null;
if (settings?.WebSearch != null)
{
temperature = null;
+ topP = null;
reasoningEffortLevel = null;
webSearchOptions = new();
}
@@ -719,6 +729,7 @@ public class ChatCompletionProvider : IChatCompletion
return new ChatCompletionOptions()
{
Temperature = temperature,
+ TopP = topP,
MaxOutputTokenCount = maxTokens,
ReasoningEffortLevel = reasoningEffortLevel,
WebSearchOptions = webSearchOptions
diff --git a/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Chat/ChatCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Chat/ChatCompletionProvider.cs
index 7ab149e2..cfe655c0 100644
--- a/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Chat/ChatCompletionProvider.cs
+++ b/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Chat/ChatCompletionProvider.cs
@@ -534,23 +534,33 @@ public class ChatCompletionProvider : IChatCompletion
var settingsService = _services.GetRequiredService();
var settings = settingsService.GetSetting(Provider, _model);
+ // Sampling: an explicit conversation state wins, then the agent's own override, then the
+ // model's configured reasoning defaults. Unset everywhere keeps the historical 0.0 fallback.
+ float? temperature = null;
+ if (state.ContainsState("temperature") && float.TryParse(state.GetState("temperature"), out var stateTemperature))
+ temperature = stateTemperature;
+ temperature ??= agent?.LlmConfig?.Temperature;
+ temperature ??= settings?.Reasoning?.Temperature;
+ temperature ??= 0.2f;
+
+ float? topP = null;
+ if (state.ContainsState("top_p") && float.TryParse(state.GetState("top_p"), out var stateTopP))
+ topP = stateTopP;
+ topP ??= agent?.LlmConfig?.TopP;
+
// Reasoning effort
ChatReasoningEffortLevel? reasoningEffortLevel = null;
- float? temperature = float.Parse(state.GetState("temperature", "0.0"));
- if (settings?.Reasoning != null)
- {
- temperature = settings.Reasoning.Temperature;
- var level = state.GetState("reasoning_effort_level")
- .IfNullOrEmptyAs(agent?.LlmConfig?.ReasoningEffortLevel)
- .IfNullOrEmptyAs(settings?.Reasoning?.EffortLevel);
- reasoningEffortLevel = ParseReasoningEffortLevel(level);
- }
+ var level = state.GetState("reasoning_effort_level")
+ .IfNullOrEmptyAs(agent?.LlmConfig?.ReasoningEffortLevel)
+ .IfNullOrEmptyAs(settings?.Reasoning?.EffortLevel);
+ reasoningEffortLevel = ParseReasoningEffortLevel(level);
// Web search
ChatWebSearchOptions? webSearchOptions = null;
if (settings?.WebSearch != null)
{
temperature = null;
+ topP = null;
reasoningEffortLevel = null;
webSearchOptions = new();
}
@@ -562,6 +572,7 @@ public class ChatCompletionProvider : IChatCompletion
return new ChatCompletionOptions()
{
Temperature = temperature,
+ TopP = topP,
MaxOutputTokenCount = maxTokens,
ReasoningEffortLevel = reasoningEffortLevel,
WebSearchOptions = webSearchOptions