> ## Documentation Index
> Fetch the complete documentation index at: https://hastekit.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Function Tools

Tool calling agents can execute custom functions to interact with external systems, databases, APIs, or perform computations. The agent decides when to call tools based on the user's request and uses the results to provide better responses.

## Creating a Custom Tool

To create a tool, you need to implement the `agents.Tool` interface:

```go theme={null}
type CustomTool struct {
	*agents.BaseTool
}

func NewCustomTool() *CustomTool {
	return &CustomTool{
		BaseTool: &agents.BaseTool{
			ToolUnion: responses.ToolUnion{
				OfFunction: &responses.FunctionTool{
					Name:        "get_user_name",
					Description: utils.Ptr("Returns the user's name"),
					Parameters: map[string]any{
						"type": "object",
						"properties": map[string]any{
							"user_id": map[string]any{
								"type":        "string",
								"description": "The user ID to look up",
							},
						},
						"required": []string{"user_id"},
					},
				},
			},
		},
	}
}

func (t *CustomTool) Execute(ctx context.Context, params *agents.ToolCall) (*agents.ToolCallResponse, error) {
    // Parse arguments
    args := map[string]interface{}{}
    if err := json.Unmarshal([]byte(params.Arguments), &args); err != nil {
        return nil, err
    }

    userID := args["user_id"].(string)
    
    // Your custom logic here
    userName := lookupUserName(userID)  // Example function
    
    // Return the result
    return &agents.ToolCallResponse{
        FunctionCallOutputMessage: &responses.FunctionCallOutputMessage{
            ID:     params.ID,
            CallID: params.CallID,
            Output: responses.FunctionCallOutputContentUnion{
                OfString: utils.Ptr(userName),
            },
        },
        StateUpdates: map[string]string{},
    }, nil
}
```

***

## The `hastekit.NewTool` Helper

If you don't need the full control of `agents.BaseTool`, `hastekit.NewTool` turns any
`func(ctx, In) (Out, error)` into a tool. The input JSON schema is derived from the
argument struct, and arguments/results are marshalled for you:

```go theme={null}
type UserArgs struct {
    UserID string `json:"user_id" jsonschema_description:"The user ID to look up"`
}

type UserName struct {
    Name string `json:"name"`
}

func getUserName(ctx context.Context, args UserArgs) (UserName, error) {
    return UserName{Name: lookupUserName(args.UserID)}, nil
}

userTool := hastekit.NewTool(getUserName,
    hastekit.WithName("get_user_name"), // optional; defaults to the function name
    hastekit.WithDescription[UserArgs, UserName]("Returns the user's name"),
)
```

> `WithDescription`, `WithNeedsApproval`, and `WithDeferred` take explicit
> `[ArgsType, ReturnType]` type parameters; `WithName` does not.

Both `agents.BaseTool`-based tools and `hastekit.NewTool` tools implement
`hastekit.Tool` and can be mixed into the same `Tools` slice.

***

## Basic Example

Here's a simple example of an agent with a custom tool:

```go theme={null}
func main() {
    // Create agent with tool
    agent := hastekit.NewAgent(&hastekit.AgentConfig{
        Name:        "Assistant",
        Instruction: hastekit.NewPrompt("You are a helpful assistant. Use the get_user_name tool to get the user's name and greet them."),
        LLM:         client.Model("OpenAI/gpt-4o-mini"),
        Tools: []hastekit.Tool{
            NewGetUserNameTool(),
        },
    })

    handle, err := agent.Execute(context.Background(), &agents.AgentInput{
        Message: history.Message{
            Messages: []responses.InputMessageUnion{
                responses.UserMessage("Hello! Can you get my name for user_id '123'?"),
            },
        },
    })
    if err != nil {
        log.Fatal(err)
    }
}
```
