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

A tool the model may call. See spec §5.2 and §15.

Layer A — 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 (Phase 18)

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 `chat/3` (raw stateless flow).

Default: `false` — the tool is auto-executed under `mode: :auto` (today's
behaviour). The flag is silent under `mode: :manual` whole-loop manual
(spec §12); the whole-loop short-circuit fires before the per-tool
partition runs.

See spec §12.4 (per-tool manual) and Phase 18 design.

# `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).

# `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. See spec §5.2 and §12.3 (ask-user).

# `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*
