Skip to content

Tools

Tools are how the model reaches out of text generation and does useful work. In godantic, a tool is a JSON-schema declaration plus a Go function.

The model sees the schema. Your Go process executes the callable.

type FunctionDeclaration struct {
Name string
Description string
Parameters models.Parameters
Callable interface{}
}
FieldWhat it does
NameStable name the model uses in a function call. Prefer snake case.
DescriptionThe model’s main clue for when to use the tool. Be specific.
ParametersJSON schema object describing arguments.
CallableGo function that returns (string, error).

Supported shapes:

func() (string, error)
func(city string) (string, error)
func(query string, limit int) (string, error)

For multi-argument functions, Parameters.Required must match the Go parameter order.

func SearchTickets(query string, limit int) (string, error) {
return "[]", nil
}
tool := models.FunctionDeclaration{
Name: "search_tickets",
Description: "Search support tickets by text query.",
Parameters: models.Parameters{
Type: "object",
Properties: map[string]interface{}{
"query": map[string]interface{}{"type": "string"},
"limit": map[string]interface{}{"type": "integer"},
},
Required: []string{"query", "limit"},
},
Callable: SearchTickets,
}

Bad descriptions make models guess. Good descriptions say when the tool should be used and what it returns.

Weak:

Get user.

Better:

Look up an internal user profile by email address. Returns JSON with id, name, department, and account status.

Include constraints in the parameter descriptions:

"email": map[string]interface{}{
"type": "string",
"description": "User email address. Must be a full email, not a display name.",
}

Return strings. JSON strings are usually best because the model can reliably inspect fields.

func LookupUser(email string) (string, error) {
return `{"id":"u_123","name":"Ada","active":true}`, nil
}

If the function returns an error, godantic still creates a tool result payload containing the error. This lets the model explain or recover.

func LookupCustomer(email string) (string, error) {
if email == "" {
return "", fmt.Errorf("email is required")
}
return `{"name":"Ada Lovelace","plan":"enterprise"}`, nil
}
customerTool := models.FunctionDeclaration{
Name: "lookup_customer",
Description: "Look up a customer by email address. Returns name and subscription plan as JSON.",
Parameters: models.Parameters{
Type: "object",
Properties: map[string]interface{}{
"email": map[string]interface{}{
"type": "string",
"description": "Customer email address",
},
},
Required: []string{"email"},
},
Callable: LookupCustomer,
}
agent := godantic.Create_Agent(model, []models.FunctionDeclaration{customerTool})

common_tools.DefaultTools() returns a local-agent toolbox:

DeclarationCallablePurpose
WebSearchTool()Brave_SearchSearch the web with Brave.
WebFetchTool()Web_FetchFetch and extract readable URL content.
ReadFileTool()ReadFileRead a file with offset/limit support.
WriteFileTool()WriteFileWrite a file and create parents.
EditFileTool()EditFileExact text replacement.
ListDirectoryTool()ListDirectoryList files and directories.
ShellExecTool()ShellExecExecute shell commands with timeout.
ImageAnalysisTool()AnalyzeImageAnalyze images.
tools := common_tools.DefaultTools()
agent := godantic.Create_Agent(model, tools)

Some built-ins have generated schemas in schemas/cached_schemas. Register them with Create_Tools:

tools, err := godantic.Create_Tools([]interface{}{
common_tools.Brave_Search,
common_tools.Web_Fetch,
common_tools.Execute_TypeScript,
})

Use Create_Tools for functions shipped with godantic. For app-specific tools, directly create models.FunctionDeclaration so the schema is explicit in your code.

Current Tool_Approver auto-approves tools. Treat that as development behavior. In a product, decide which tools can run without confirmation.

Suggested policy:

Tool typeApproval policy
Pure read-only lookupAuto-approve after validation.
Web search/fetchUsually auto-approve.
File readRestrict to allowed workspace, optionally auto-approve.
File write/editAsk the user unless the action is clearly scoped.
Shell executionRequire trusted operator or explicit approval.
External side effectsRequire approval and audit logging.

You can execute a tool directly through the agent:

resultJSON, err := agent.ExecuteTool("lookup_customer", map[string]interface{}{
"email": "ada@example.com",
}, "conversation-1")

This is useful in tests or custom tool loops.

SymptomCheck
Tool never calledImprove Description; make the user request require external data.
Missing argument errorEnsure Required names match schema property names.
Wrong argument orderFor multi-arg callables, order Required to match function params.
Tool output too largeReturn a summarized JSON payload instead of raw data.
Model loops on tool callsMake the tool return final enough information and add system instructions about when to stop.