Pass sdk.DefaultTools() in sdk.Config.Tools to get the full set of built-in tools:
| Tool | Description |
|---|
read | Read file contents with offset/limit support |
write | Create or overwrite files |
edit | Search-and-replace edits within files |
bash | Execute shell commands |
grep | Search file contents via regex |
ls | List directory contents |
find | Locate files using glob patterns |
bash, write, and edit are destructive. In --dry-run mode they preview what they would do without executing.
Implement sdk.Tool to create a custom tool:
type Tool interface {
Name() string
Description() string
Schema() json.RawMessage // JSON Schema for the input parameters
Execute(ctx context.Context, args json.RawMessage, update ToolUpdate) (*ToolResult, error)
IsReadOnly() bool // if true, tool is allowed in dry-run mode
}
ToolUpdate is a callback for streaming partial output while the tool runs:
type ToolUpdate func(content string)
type CountLinesTool struct{}
func (t *CountLinesTool) Name() string { return "count_lines" }
func (t *CountLinesTool) Description() string {
return "Count the number of lines in a file"
}
func (t *CountLinesTool) Schema() json.RawMessage {
return json.RawMessage(`{
"type": "object",
"properties": {
"path": {"type": "string", "description": "File path to count lines in"}
},
"required": ["path"]
}`)
}
func (t *CountLinesTool) IsReadOnly() bool { return true }
func (t *CountLinesTool) Execute(ctx context.Context, args json.RawMessage, update sdk.ToolUpdate) (*sdk.ToolResult, error) {
var input struct {
Path string `json:"path"`
}
if err := json.Unmarshal(args, &input); err != nil {
return nil, err
}
data, err := os.ReadFile(input.Path)
if err != nil {
return &sdk.ToolResult{Content: err.Error(), IsError: true}, nil
}
n := strings.Count(string(data), "\n") + 1
return &sdk.ToolResult{Content: fmt.Sprintf("%d lines", n)}, nil
}
Register alongside the built-in tools:
ag, _ := sdk.NewAgent(sdk.Config{
Provider: "ollama",
Model: "llama3.2",
Tools: append(sdk.DefaultTools(), &CountLinesTool{}),
})
Pass only the tools you want rather than the full default set:
tools := sdk.ToolsFor("read", "grep", "ls") // subset by name
Or build the list manually to include only read-only tools for a sandboxed agent.