namespace AIStudio.Tools.ToolCallingSystem; /// /// Builds the schema describing a tool's settings. /// /// /// Settings are stored as text throughout, so there is no field type to choose here. What a /// field declares instead is whether it must be set, whether it holds a secret, and whether it /// offers a fixed choice.

/// Titles and descriptions are deliberately absent: they come from the implementation, which can /// translate them. See the settings field label and description hooks on the tool interface. ///
public sealed class ToolSettingsSchemaBuilder { private readonly Dictionary properties = new(StringComparer.Ordinal); private readonly HashSet requiredNames = new(StringComparer.Ordinal); private string currentGroup = string.Empty; public static ToolSettingsSchemaBuilder Create() => new(); /// /// Puts every field declared after this call into one group. /// /// /// Call it again with another name to start the next group, or with an empty name to /// leave grouping behind. Groups are shown in the order in which they first appear here, /// and so are the fields within them. /// public ToolSettingsSchemaBuilder InGroup(string groupKey) { this.currentGroup = groupKey; return this; } /// /// A field the tool cannot work without. /// /// /// The tool counts as unconfigured while a required field is empty, which keeps it out of the /// model's reach instead of letting it run and fail. /// public ToolSettingsSchemaBuilder Required(string name) => this.Add(name, isRequired: true); public ToolSettingsSchemaBuilder Optional(string name) => this.Add(name, isRequired: false); /// /// A required field whose value is picked from one of the app's option lists. /// public ToolSettingsSchemaBuilder RequiredChoice(string name, string optionSource) => this.Add(name, isRequired: true, optionSource: optionSource); public ToolSettingsSchemaBuilder OptionalChoice(string name, string optionSource) => this.Add(name, isRequired: false, optionSource: optionSource); /// /// An optional field whose value is picked from a short list the tool spells out itself. /// /// /// Use this for values only one tool knows, such as the markets a single search service /// offers. Anything the app maintains elsewhere belongs in an option source instead, which /// also gives the user a translated name rather than the raw value. /// public ToolSettingsSchemaBuilder OptionalEnum(string name, params string[] values) => this.Add(name, isRequired: false, enumValues: values); /// /// A field kept in the operating system's keyring rather than in the settings file. /// public ToolSettingsSchemaBuilder OptionalSecret(string name) => this.Add(name, isRequired: false, isSecret: true); public ToolSettingsSchemaBuilder RequiredSecret(string name) => this.Add(name, isRequired: true, isSecret: true); public ToolSettingsSchema Build() => new() { Properties = new(this.properties, StringComparer.Ordinal), Required = [..this.requiredNames], }; private ToolSettingsSchemaBuilder Add(string name, bool isRequired, string optionSource = "", bool isSecret = false, IReadOnlyList? enumValues = null) { this.properties[name] = new ToolSettingsFieldDefinition { OptionSource = optionSource, EnumValues = enumValues?.ToList() ?? [], Secret = isSecret, Group = this.currentGroup, }; if (isRequired) this.requiredNames.Add(name); return this; } }