Current section
Files
Jump to
Current section
Files
lib/anthropic/tools.ex
defmodule Anthropic.Tools do
@moduledoc """
Behaviour for user-defined tools, driving the native Anthropic `tools` API field (JSON
Schema `input_schema`) rather than a hand-rolled prompt-injection protocol.
## Example
defmodule MyApp.WeatherTool do
use Anthropic.Tools
@impl true
def name, do: "get_weather"
@impl true
def description, do: "Get the current weather for a given city."
@impl true
def input_schema do
%{
"type" => "object",
"properties" => %{
"location" => %{"type" => "string", "description" => "City and state, e.g. San Francisco, CA"}
},
"required" => ["location"]
}
end
@impl true
def execute(%{"location" => location}) do
{:ok, "72F and sunny in \#{location}"}
end
end
Register tools with `Anthropic.Messages.create/2` via the `:tools` option (either tool
modules or raw wire-shape maps), or drive a full agentic loop with `Anthropic.ToolRunner.run/4`.
"""
@callback name() :: String.t()
@callback description() :: String.t()
@callback input_schema() :: map()
@callback execute(input :: map()) :: {:ok, String.t() | map()} | {:error, String.t()}
defmacro __using__(_opts) do
quote do
@behaviour Anthropic.Tools
end
end
@doc "Serializes a tool module (or a raw wire-shape map, passed through unchanged) into a `tools` request param entry."
@spec to_param(module() | map()) :: map()
def to_param(tool_module) when is_atom(tool_module) do
%{
name: tool_module.name(),
description: tool_module.description(),
input_schema: tool_module.input_schema()
}
end
def to_param(%{} = raw_tool_map), do: raw_tool_map
end