The tools package provides a comprehensive framework for registering, managing, and executing tools in the Dojo Genesis Go backend.
- Type-safe tool definitions with JSON schema parameter validation
- Thread-safe global registry for tool management
- Context-aware execution with configurable timeouts
- Comprehensive helper functions for parameter extraction
- 94.7% test coverage with extensive unit tests
Defines the structure of a tool:
type ToolDefinition struct {
Name string `json:"name"`
Description string `json:"description"`
Parameters map[string]interface{} `json:"parameters"`
Function ToolFunc `json:"-"`
}Function signature for all tools:
type ToolFunc func(context.Context, map[string]interface{}) (map[string]interface{}, error)Register a new tool in the global registry:
def := &ToolDefinition{
Name: "echo_tool",
Description: "Echoes the input message",
Parameters: map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"message": map[string]interface{}{
"type": "string",
},
},
"required": []interface{}{"message"},
},
Function: func(ctx context.Context, params map[string]interface{}) (map[string]interface{}, error) {
message := GetStringParam(params, "message", "")
return map[string]interface{}{
"success": true,
"echo": message,
}, nil
},
}
if err := RegisterTool(def); err != nil {
log.Fatal(err)
}Retrieve a tool by name:
tool, err := GetTool("echo_tool")
if err != nil {
log.Fatal(err)
}Get all registered tools:
tools := GetAllTools()
for _, tool := range tools {
fmt.Printf("Tool: %s - %s\n", tool.Name, tool.Description)
}Execute a tool with default 30-second timeout:
result, err := InvokeTool(context.Background(), "echo_tool", map[string]interface{}{
"message": "Hello, World!",
})Execute a tool with custom timeout:
result, err := InvokeToolWithTimeout(
context.Background(),
"slow_tool",
params,
2*time.Minute,
)The framework automatically validates parameters against the JSON schema defined in the tool's Parameters field.
stringnumberintegerbooleanarrayobject
Parameters: map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"name": map[string]interface{}{
"type": "string",
},
"age": map[string]interface{}{
"type": "integer",
},
"enabled": map[string]interface{}{
"type": "boolean",
},
},
"required": []interface{}{"name"},
}The package provides type-safe parameter extraction helpers:
message := GetStringParam(params, "message", "default")count := GetIntParam(params, "count", 10)enabled := GetBoolParam(params, "enabled", false)threshold := GetFloat64Param(params, "threshold", 0.5)items := GetStringSliceParam(params, "items", []string{})metadata := GetMapParam(params, "metadata", map[string]interface{}{})timeout := GetDurationParam(params, "timeout", 30*time.Second)The registry is fully thread-safe and can be accessed concurrently from multiple goroutines. All registry operations use read-write locks to ensure data consistency.
Run tests with:
go test -v ./tools/...Check coverage:
go test -cover ./tools/...Generate coverage report:
go test -coverprofile=coverage.out ./tools/...
go tool cover -html=coverage.outAll functions return descriptive errors:
- Tool registration errors (nil definition, empty name, nil function, duplicate)
- Tool retrieval errors (not found)
- Parameter validation errors (missing required, type mismatch)
- Execution errors (timeout, context cancellation, function errors)
- Lock-free reads when multiple goroutines read from the registry
- Parallel tool execution supported via goroutines
- Context-based cancellation for efficient resource management
- Configurable timeouts to prevent hanging operations