Tool Parameters

Top Level Parameters

Contrary to the typical Rock pattern, do not create a POCO representation of your tool parameters. Flatten the list into top-level arguments to the method.

There are two primary reasons for this. First, these tools are never intended to be called by other C# code. Therefore we do not have to worry about breaking changes like we do for other utility methods. Second, the language model can easily get confused with nested POCO objects. And if you start with a single POCO, you are almost guaranteed to have nested POCO properties. Possibly nested multiple layers deep.

// ✅ Good
public IAgentToolResult SendEmail( string communicationIdKey, bool sendImmediately = false )

// ⛔ Bad
public IAgentToolResult SendEmail( SendEmailOptions options )

Because of how C# handles method parameters, there are some rules that automatically get enforced and passed along to the language model to give it a better hint about how to handle them when it constructs the arguments to pass to your tool.

  • If a parameter has no default value, it is automatically enforced that it is required.
  • Conversely, to mark a parameter as optional, you can give it a default value. If it is truly optional, the default should be null.
  • For most reference types (numbers, bools, etc) you can use the ? suffix operator to indicate that it allows a null value.

Naming

Carefully think through how you name each parameter as well as whether it supports null values or not. In a normal C# method that operates on a person, a parameter name of idKey is good enough. We will general assume it is a person identifier it needs. And if we do it wrong, we'll get an immediate error and fix the code so it never errors again. With a language model, every time it does it wrong, it forgets that it did it wrong so it might do it wrong again. So naming the argument personIdKey will provide much more context to the language model.

// ✅ Good. Clearly identifies what kind of IdKey to pass.
public IAgentToolResult SendEmail( string communicationIdKey )

// ⛔ Bad. Maybe it's the person's IdKey we are sending to?
public IAgentToolResult SendEmail( string idKey )

Null Handling

Similarly, if you have an integer parameter called numberOfDays but do not make it nullable and give it a default value of null the language model might not treat it the way you expect. For example, suppose you have (int numberOfDays = 0), you might assume this means it is optional. But the language model could easily infer that you meant "the number is required, but we will give you a default value if you forget". By using int? and a default value of null you are explicitly stating it is optional.

// ✅ Implies that sendImmediately is a necessary field, but we will provide a default value.
public IAgentToolResult SendEmail( string communicationIdKey, bool sendImmediately = false )

// ✅ Implies that attachmentId is completely optional and no default will be provided.
public IAgentToolResult SendEmail( string communicationIdKey, int? attachmentId = null )