# `Nous.Tool.Behaviour`
[🔗](https://github.com/nyo16/nous/blob/v0.17.1/lib/nous/tool/behaviour.ex#L1)

Behaviour for tool implementations.

Allows tools to be defined as modules for better testability and organization.
Module-based tools can inject dependencies via the context, making them
easy to test with mocks.

## Example

    defmodule MyApp.Tools.Search do
      @behaviour Nous.Tool.Behaviour

      @impl true
      def metadata do
        %{
          name: "search",
          description: "Search the web for information",
          parameters: %{
            "type" => "object",
            "properties" => %{
              "query" => %{
                "type" => "string",
                "description" => "The search query"
              }
            },
            "required" => ["query"]
          }
        }
      end

      @impl true
      def execute(ctx, %{"query" => query}) do
        # Inject http_client via deps for testing
        http_client = ctx.deps[:http_client] || Nous.HTTP
        api_key = ctx.deps[:search_api_key]

        case http_client.get("https://api.search.com", query: query, key: api_key) do
          {:ok, results} -> {:ok, format_results(results)}
          {:error, _} = err -> err
        end
      end

      defp format_results(results), do: Enum.map(results, & &1["title"])
    end

## Testing

    defmodule MyApp.Tools.SearchTest do
      use ExUnit.Case

      test "search returns formatted results" do
        mock_http = %{
          get: fn _url, _opts ->
            {:ok, [%{"title" => "Result 1"}, %{"title" => "Result 2"}]}
          end
        }

        ctx = Nous.RunContext.new(%{http_client: mock_http, search_api_key: "test"})

        assert {:ok, ["Result 1", "Result 2"]} =
          MyApp.Tools.Search.execute(ctx, %{"query" => "elixir"})
      end
    end

## Usage with Agent

    agent = Nous.Agent.new("openai:gpt-4",
      tools: [Nous.Tool.from_module(MyApp.Tools.Search)]
    )

# `execute`

```elixir
@callback execute(ctx :: Nous.RunContext.t(), args :: map()) ::
  {:ok, any()} | {:ok, any(), Nous.Tool.ContextUpdate.t()} | {:error, term()}
```

Execute the tool with context and arguments.

The context provides access to dependencies and execution metadata.
Arguments are a map of the parameters passed by the LLM.

## Return Values

- `{:ok, result}` - Success with the result to return to the LLM
- `{:ok, result, context_update}` - Success with context updates (see `Nous.Tool.ContextUpdate`)
- `{:error, reason}` - Failure with error reason

# `metadata`
*optional* 

```elixir
@callback metadata() :: map()
```

Return tool metadata (name, description, parameters).

This callback is optional. If not implemented, the tool name will be
derived from the module name.

## Return Value

    %{
      name: "tool_name",
      description: "What the tool does",
      parameters: %{
        "type" => "object",
        "properties" => %{...},
        "required" => [...]
      }
    }

# `schema`
*optional* 

```elixir
@callback schema() :: map()
```

Return the tool's schema definition for introspection.

This callback is optional. When using `Nous.Tool.Schema`, it is
generated automatically as `__tool_schema__/0`.

## Return Value

    %{
      name: "tool_name",
      description: "...",
      category: :read,
      tags: [:file],
      params: [
        %{name: :path, type: :string, required: true, doc: "..."},
        ...
      ]
    }

# `get_metadata`

```elixir
@spec get_metadata(module()) :: map()
```

Get metadata from a module, using defaults if metadata/0 is not implemented.

# `implements?`

```elixir
@spec implements?(module()) :: boolean()
```

Check if a module implements the Tool.Behaviour.

# `module_to_name`

```elixir
@spec module_to_name(module()) :: String.t()
```

Convert a module name to a tool name.

## Examples

    iex> Nous.Tool.Behaviour.module_to_name(MyApp.Tools.SearchDatabase)
    "search_database"

---

*Consult [api-reference.md](api-reference.md) for complete listing*
