Tool settings
Some values a tool needs are not the model's to choose, such as how many tickets a search returns. They go in a settings record that the tool receives and the model never sees.
The settings record
A settings record holds values a tool needs. Its parameterless constructor sets the code defaults, here through property initializers:
internal record SearchTicketsSettings
{
public int Limit { get; init; } = 10;
public bool IncludeClosed { get; init; }
public TimeSpan Timeout { get; init; } = TimeSpan.FromSeconds(5);
}It must be a record (TSH005). Settings resolve in layers, from these code defaults up to a single run, and each layer applies its values to a with copy of the defaults.
Configurable members
A configurable member is one that stored settings and runs may change. You choose which members are configurable, and you can declare that from either side. WithSettings<T>() keeps every member in code unless Configurable(...) names it:
AddTool(SearchTickets)
.ReadOnly()
.WithSettings<SearchTicketsSettings>()
.Configurable(s => s.IncludeClosed)
.Configurable(s => s.Limit);WithConfigurableSettings<T>() opens every settable member unless NotConfigurable(...) names it:
AddTool(SearchArticlesAsync)
.WithConfigurableSettings<SearchArticlesSettings>()
.NotConfigurable(s => s.Limit);The difference shows when you add a member to the record later. Under WithSettings<T>() it stays in code until you name it. Under WithConfigurableSettings<T>(), stored settings and runs can change it right away, without another code change.
WithSettings<T>()takes onlyConfigurableafter it, andWithConfigurableSettings<T>()onlyNotConfigurable.- The generator reads each lambda from your source and never runs it, so each one must be a plain member access,
s => s.Member(TSH015). - Under
WithConfigurableSettings<T>(), members marked[Obsolete]stay in code without aNotConfigurable(...). - A configurable member needs a public
setorinitaccessor (TSH013).
A renamed member loses its stored values
Stored settings keep each member under its name. Rename or remove a configurable member, and its stored value reads as missing, so the layer below applies. When that matters, raise the schema version the agent passes to WithSchemaVersion and migrate the stored documents, as Migrate older settings explains.
Storable types
A configurable member needs a type settings can store (TSH012):
- strings, Booleans, enums (stored by name),
Guid,DateTime,DateTimeOffset,TimeSpan,DateOnly,TimeOnly,UriandReasoningOptions; - the numbers
byte,short,int,long,float,doubleanddecimal; - non-generic classes and records with a public parameterless constructor, no
requiredmembers and storable settable members, replaced as a whole and never merged, and record structs that meet the same rules; - arrays, lists and sets of storable values, and dictionaries keyed by
stringor an enum.
Items and dictionary values cannot be nullable value types, and a type that contains itself is not storable. Other structs are not storable, because most keep their state in fields that no public setter writes.
Receiving settings in the tool
The tool takes a parameter of its settings type, and Typeshift fills it with the resolved settings when it calls the tool. The analyzer reports a tool that has settings but no such parameter (TSH010), since its settings would reach nothing:
/// <summary>
/// Searches the customer's support tickets, newest first.
/// </summary>
/// <param name="query">Words the ticket's title contains.</param>
public static IReadOnlyList<Ticket> SearchTickets(
string query,
SearchTicketsSettings settings,
IServiceProvider services) =>
services.GetRequiredService<ITicketClient>().Search(query, settings.IncludeClosed, settings.Limit);Toolsets lists the other parameters the call fills.
The generated overrides
For a tool with configurable members, the generator writes a {Tool}Overrides record into the toolset, such as TicketToolset.SearchTicketsOverrides, with each configurable member as nullable. Stored settings and run settings set a tool's values through this record, and a null keeps the value of the layer below. Generated members shows it in full.
The layers
A tool's settings resolve through four settings layers: the record's code defaults, the agent's Configure{Tool}(), the stored settings and the run's settings. The last two set values through the overrides, so they can change only the configurable members. The agent's Configure{Tool}() can set every settable member.
Related
- Toolsets: declaring the tools that take settings.
- Settings layering: which layer wins, and what a layer cannot do.
- Agents: setting a tool's settings in one agent.
- Builders: every call of a tool's declaration.