# `ALLM.Tool`
[🔗](https://github.com/cykod/ALLM/blob/v0.5.0/lib/allm/tool.ex#L1)

A tool the model may call — Layer A serializable data plus an optional
runtime `:handler`.

The struct itself is pure data (`:name`, `:description`, `:schema`,
`:metadata`, `:manual` are all serializable), but `:handler` may be an
anonymous function. A tool with a `fn` handler is **not** safe to
persist via `:erlang.term_to_binary/1`; persist either `:handler | nil`
and re-attach at load time, or use a `{Module, :function}` tuple.

## Per-tool manual mode

Setting `manual: true` declares this tool will not be auto-executed by
`ALLM.chat/3` even when the call uses `mode: :auto`. When the assistant
emits a tool call for a `manual: true` tool, the chat orchestrator halts
the loop with `halted_reason: :manual_tool_calls` and surfaces the call
in `metadata.manual_tool_calls`. The caller resolves the tool result
either via `ALLM.Session.submit_tool_result/3` (when running through the
`Session` API) or by appending a `:tool` message to the thread and
re-issuing `ALLM.chat/3` (raw stateless flow).

Default: `false` — the tool is auto-executed under `mode: :auto`. The
flag is silent under whole-loop `mode: :manual`; the whole-loop
short-circuit fires before the per-tool partition runs.

See also `guides/tools.md`.

# `handler`

```elixir
@type handler() ::
  (map() -&gt; handler_result()) | (map(), keyword() -&gt; handler_result())
```

Tool handler — called with parsed arguments (arity 1) or with arguments
plus a caller-supplied context keyword list (arity 2).

The arity-2 keyword list carries call context. Standard keys provided by
`ALLM.ToolExecutor.Default`:

| Key | Type | Notes |
|-----|------|-------|
| `:context` | `term()` | The opaque value passed via `ALLM.chat(engine, thread, context: ...)` or `Session.reply(session, msg, context: ...)`. Caller-defined shape. |
| `:session_id` | `String.t() \| nil` | The `%Session{}.id` when invoked through the Session API; `nil` for stateless `chat/3` / `step/3`. |
| `:tool_call` | `%ALLM.ToolCall{}` | The exact tool call the assistant emitted (`:id`, `:name`, `:arguments`). |
| `:engine` | `%ALLM.Engine{}` | The engine driving the call — handlers needing to issue downstream LLM calls reuse it via `ALLM.generate/3` etc. |
| `:request_id` | `String.t() \| nil` | Telemetry-correlation id from the parent span. |

Custom keys in `:context` are passed through unchanged. The arity-1 form
is preferred when handlers don't need context; arity-2 is detected at
dispatch time via `:erlang.fun_info(handler, :arity)`.

# `handler_result`

```elixir
@type handler_result() ::
  {:ok, term()}
  | {:error, term()}
  | {:ask_user, String.t()}
  | {:ask_user, String.t(), keyword()}
  | {:halt, atom(), term()}
```

Legal returns from a tool handler.

# `schema`

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

# `t`

```elixir
@type t() :: %ALLM.Tool{
  description: String.t(),
  handler: handler() | nil,
  manual: boolean(),
  metadata: map(),
  name: String.t(),
  schema: schema()
}
```

# `new`

```elixir
@spec new(keyword()) :: t()
```

Build a `%Tool{}` from keyword opts.

`:name`, `:description`, and `:schema` are required; omitting any raises
`ArgumentError` via `struct!/2`. `:handler` is optional — a tool may be
declared without a handler when the caller handles tool calls manually.

`:manual` is optional and defaults to `false`. It MUST be a boolean
passing `:manual` with a non-boolean value (including `nil`) raises
`ArgumentError`. The `defstruct` default protects against omission, but
`struct!/2` accepts an explicit `nil` (silently overwriting the default),
so this constructor adds an explicit guard.

## Examples

    iex> tool = ALLM.Tool.new(name: "weather", description: "weather by city", schema: %{"type" => "object"})
    iex> tool.name
    "weather"
    iex> tool.handler
    nil
    iex> tool.manual
    false

    iex> tool = ALLM.Tool.new(name: "charge", description: "charge a card", schema: %{"type" => "object"}, manual: true)
    iex> tool.manual
    true

---

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