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, }; }