Skip to main content

Tool Definition

Tools extend an agent's capabilities by allowing it to perform specific actions or access external systems. Aigentic provides a flexible DSL for defining and using tools.

Tool Parameters​

Tool parameters define the in- and output structure for a tool. Aigentic has capabilities to automatically derive parameters from data classes annotated with the @AigenticParameter annotation:

@AigenticParameter
data class MessageParameters(
@Description("The Slack channel to send the message to (e.g., '#general', '@username')")
val channel: String,
@Description("The message text content to send to the Slack channel")
val text: String,
)

@AigenticParameter
data class SlackWebhookResponse(
@Description("Indicates whether the Slack webhook message was sent successfully")
val isSuccess: Boolean,
)

@AigenticParameter​

The @AigenticParameter annotation marks data classes that serve as input or output parameters for tools or agents in the Aigentic framework. This annotation enables Aigentic to automatically derive parameter schemas for the LLM.

Key features:

  • Applied at data classes
  • Has an optional description property that provides a high-level description of the parameter object

Importance of Descriptions​

The description property in @AigenticParameter is sent with the agent's output type, so the LLM knows what the object it returns is for.

Where descriptions end up:

  • Agent output type: the @AigenticParameter description is sent with the response schema.
  • Tool input type: only the properties are sent, as the tool's arguments. Describe the tool itself in the description of createTool or addTool.
  • Nested object: the @Description on the property that holds it is sent.

@Description​

The @Description annotation marks properties within parameter data classes with additional information about their meaning. These descriptions are used by Aigentic to generate accurate documentation and parameter schemas the LLM.

Key features:

  • Applied at the property level
  • Requires a string value that describes the property's purpose
  • Helps LLMs understand the expected input and output formats
  • Improves tool usability by providing clear guidance on parameter usage

Importance of Property Descriptions​

Property descriptions greatly enhance LLM interactions. Each property description is included in the tool schemas sent to the LLM, providing details about:

  • The specific purpose of each property
  • Expected formats and valid values
  • Relationships between properties
  • Examples of proper usage (when included in the description)

Clear property descriptions help the LLM create more accurate parameter objects, reducing errors and making your tools work better. Adding more context through descriptions helps the LLM understand how to use your tools properly.

Optional properties​

Make a property nullable (T?) when its value can be missing. Aigentic tells the LLM the property can be null, and on Gemini and VertexAI it can also leave the property out. Both end up as null in your object. Non-nullable properties stay required.

@AigenticParameter
data class Invoice(
val invoiceNumber: String,
@Description("The total amount, null when the invoice doesn't mention it")
val total: Double?,
)

This helps extraction agents most: instead of making up a placeholder like 0 or "", the LLM can return null when the source doesn't contain the value. If an optional nested object has a property that can also be missing, make that property nullable too.

Creating Tools​

Aigentic provides several ways to create tools:

Standalone Tool Creation​

Use the createTool function with type parameters to create a standalone reusable tool:


val slackWebhookTrigger = createTool<MessageParameters, SlackWebhookResponse>("slackWebhookTrigger", "Posts a webhook which sends a message in a channel") { parameters: MessageParameters ->
// Some code to call a Slack webhook with the MessageParameters provided by the LLM
SlackWebhookResponse(isSuccess = true)
}

This tool can be added to agents:

agent {
addTool(slackWebhookTrigger)
}

Inline Tool Definition​

You can define tools inline:

agent {
addTool<MessageParameters, SlackWebhookResponse>("slackWebhookTrigger", "Posts a webhook which sends a message in a channel") { parameters: MessageParameters ->
// Code to call a Slack webhook
SlackWebhookResponse(true)
}
}

Best Practices​

When creating tools for Aigentic agents, follow these best practices:

  1. Clear Descriptions: Provide clear and concise descriptions for your tools using the @AigenticParameter and @Description annotations
  2. Type Safety: Use strongly typed input and output types
  3. Error Handling: A tool that throws ends the run with Outcome.Fatal. Return an error value instead when the model should be able to recover
  4. Idempotency: Make tools idempotent when possible
  5. Security: Validate inputs and handle sensitive data carefully
// Example of a well-designed tool
val emailTool = createTool<EmailRequest, EmailResponse>(
name = "sendEmail",
description = "Send an email to a recipient"
) { request ->
// Return validation errors to the model instead of throwing
if (request.to.isEmpty()) return@createTool EmailResponse(success = false, error = "Recipient email cannot be empty")
if (request.subject.isEmpty()) return@createTool EmailResponse(success = false, error = "Email subject cannot be empty")

runCatching {
val result = emailService.sendEmail(
to = request.to,
subject = request.subject,
body = request.body
)

EmailResponse(success = true, messageId = result.messageId)
}.getOrElse { error ->
EmailResponse(success = false, error = error.message)
}
}