namespace AIStudio.Provider.Reasoning.Dialects;
///
/// Google's thinking config, thinking level, and thought summaries.
///
///
/// Google offers the same settings in several places at once: directly, under "generation_config",
/// and in both spellings of each key, because their own libraries write snake case while the REST
/// API answers in camel case. All of them are read, and the answers put together.
///
/// Summaries are the one setting which only ever says yes. Asking for thought summaries proves that
/// thinking is on; switching them off proves nothing, because a model can think without showing it.
///
public sealed class GoogleThinkingDialect : IReasoningDialect
{
///
public ReasoningDialect Dialect => ReasoningDialect.GOOGLE_THINKING;
///
public ReasoningConfigurationState Detect(IDictionary parameters)
{
var states = new List();
if (ReasoningParameters.TryGet(parameters, "thinking_config", out var thinkingConfig) &&
thinkingConfig is IDictionary thinkingConfigObject)
states.Add(ConfigOf(thinkingConfigObject));
if (ReasoningParameters.TryGet(parameters, "generation_config", out var generationConfig) &&
generationConfig is IDictionary generationConfigObject)
{
if (ReasoningParameters.TryGet(generationConfigObject, "thinking_config", out var nestedThinkingConfig) &&
nestedThinkingConfig is IDictionary nestedThinkingConfigObject)
states.Add(ConfigOf(nestedThinkingConfigObject));
if (ReasoningParameters.TryGet(generationConfigObject, "thinking_summaries", out var thinkingSummaries))
states.Add(SummariesOf(thinkingSummaries));
if (ReasoningParameters.TryGet(generationConfigObject, "thinking_level", out var thinkingLevel))
states.Add(ReasoningParameters.LevelOf(thinkingLevel));
}
if (ReasoningParameters.TryGet(parameters, "thinking_summaries", out var topLevelThinkingSummaries))
states.Add(SummariesOf(topLevelThinkingSummaries));
if (ReasoningParameters.TryGet(parameters, "thinking_level", out var topLevelThinkingLevel))
states.Add(ReasoningParameters.LevelOf(topLevelThinkingLevel));
return ReasoningParameters.Merge(states);
}
///
/// Reads a thinking config, in either spelling of its keys.
///
/// The parsed thinking config object.
/// What it says.
private static ReasoningConfigurationState ConfigOf(IDictionary thinkingConfig)
{
var states = new List();
if (ReasoningParameters.TryGet(thinkingConfig, "thinking_budget", out var thinkingBudget) ||
ReasoningParameters.TryGet(thinkingConfig, "thinkingBudget", out thinkingBudget))
states.Add(ReasoningParameters.BudgetOf(thinkingBudget));
if (ReasoningParameters.TryGet(thinkingConfig, "include_thoughts", out var includeThoughts) ||
ReasoningParameters.TryGet(thinkingConfig, "includeThoughts", out includeThoughts))
states.Add(ReasoningParameters.LevelOf(includeThoughts));
return ReasoningParameters.Merge(states);
}
///
/// Reads a thought summary setting, which can only ever say yes.
///
/// The configured summary setting.
/// Yes, when it asks for summaries; nothing otherwise.
private static ReasoningConfigurationState SummariesOf(object? value) => value switch
{
string text when text.Equals("auto", StringComparison.OrdinalIgnoreCase) ||
text.Equals("on", StringComparison.OrdinalIgnoreCase) ||
text.Equals("summarized", StringComparison.OrdinalIgnoreCase)
=> ReasoningConfigurationState.EXPLICITLY_ENABLED,
true => ReasoningConfigurationState.EXPLICITLY_ENABLED,
_ => ReasoningConfigurationState.NOT_CONFIGURED,
};
}