Tools DSL
Create and manage tools with the Spice DSL.
Inline Toolβ
Simple Execute (Recommended)β
The simplest way to create a tool with automatic result wrapping:
tool("my_tool") {
description = "My custom tool"
parameter("input", "string", "Input data", required = true)
parameter("format", "string", "Output format", required = false)
// Simple execute - returns String, automatically wrapped in ToolResult
execute(fun(params: Map<String, Any>): String {
val input = params["input"] as String
val format = params["format"] as? String ?: "json"
return "Processed: $input in $format"
})
}
Key Features:
- β Automatic parameter validation (checks required parameters)
- β
Auto-wraps return value in
ToolResult.success() - β
Catches exceptions and returns
ToolResult.error() - β Type-safe with explicit function syntax
Advanced Executeβ
For full control over the result:
tool("my_tool") {
description = "My custom tool"
parameter("input", "string", "Input data", required = true)
parameter("format", "string", "Output format", required = false)
execute { params ->
val input = params["input"] as String
val format = params["format"] as? String ?: "json"
SpiceResult.success(ToolResult.success("Processed: $input in $format"))
}
}
Parameter Validationβ
Parameters are automatically validated before execution:
tool("validated_tool") {
parameter("name", "string", "User name", required = true)
parameter("age", "number", "User age", required = true)
execute(fun(params: Map<String, Any>): String {
val name = params["name"] as String
val age = (params["age"] as Number).toInt()
return "Hello $name, you are $age years old"
})
}
// Missing required parameter returns error automatically
tool.execute(emptyMap()) // Error: "Parameter validation failed: Missing required parameter: name"
Custom Validationβ
Add custom validation logic:
tool("age_validator") {
parameter("age", "number", "User age")
canExecute { params ->
val age = (params["age"] as? Number)?.toInt() ?: 0
age >= 18 // Must be 18 or older
}
execute(fun(params: Map<String, Any>): String {
return "Access granted"
})
}
Error Handlingβ
Exceptions are automatically caught and wrapped:
tool("risky_tool") {
parameter("divisor", "number", "Divisor")
execute(fun(params: Map<String, Any>): String {
val divisor = (params["divisor"] as Number).toDouble()
if (divisor == 0.0) {
throw ArithmeticException("Division by zero!")
}
return "Result: ${100 / divisor}"
})
}
// Exception caught and returned as ToolResult.error()
tool.execute(mapOf("divisor" to 0))
// Returns: ToolResult(success = false, error = "Division by zero!")
AgentTool DSLβ
For advanced tools with metadata and tags:
val tool = agentTool("advanced") {
description = "Advanced tool with metadata"
tags = listOf("production", "v2")
parameter("data", "object", "Complex data")
metadata = mapOf(
"version" to "2.0",
"author" to "team"
)
implementation { params ->
// Implementation logic
SpiceResult.success(ToolResult.success("Done"))
}
}
Best Practicesβ
- Use Simple Execute for most tools - it's cleaner and safer
- Explicit Function Syntax - Use
fun(params: Map<String, Any>): Stringto avoid overload ambiguity - Validate Required Parameters - Mark parameters as
required = true - Throw Exceptions - They're caught automatically and returned as errors
- Return Strings - Simple string returns are automatically wrapped
- Type Safety - Cast parameters to their expected types early
Common Patternsβ
Calculator Toolβ
tool("calculate", "Simple calculator") {
parameter("a", "number", "First number", required = true)
parameter("b", "number", "Second number", required = true)
parameter("operation", "string", "Operation (+,-,*,/)", required = true)
execute(fun(params: Map<String, Any>): String {
val a = (params["a"] as Number).toDouble()
val b = (params["b"] as Number).toDouble()
val op = params["operation"] as String
val result = when (op) {
"+" -> a + b
"-" -> a - b
"*" -> a * b
"/" -> if (b != 0.0) a / b else throw ArithmeticException("Division by zero")
else -> throw IllegalArgumentException("Unknown operation: $op")
}
return result.toString()
})
}
Data Processor Toolβ
tool("process_data", "Process and transform data") {
parameter("data", "string", "Input data", required = true)
parameter("format", "string", "Output format", required = false)
execute(fun(params: Map<String, Any>): String {
val data = params["data"] as String
val format = params["format"] as? String ?: "json"
return when (format) {
"json" -> """{"data": "$data"}"""
"xml" -> "<data>$data</data>"
"text" -> data
else -> data
}
})
}