# `ALLM.ToolExecutor.Default`
[🔗](https://github.com/cykod/ALLM/blob/v0.3.0/lib/allm/tool_executor/default.ex#L1)

Default `ALLM.ToolExecutor` — invokes the tool's `:handler` function
directly, dispatching on arity (1 or 2). Converts raises / exits /
throws / invalid returns / nil handlers to `%ALLM.Error.ToolError{}`;
passes handler-returned values (`{:ok, _}`, `{:error, _}`,
`{:ask_user, _}`, `{:ask_user, _, _}`, `{:halt, _, _}`) through
unchanged.

## Handler-originated vs. executor-originated errors

This distinction is load-bearing for the orchestrator's
`on_tool_error` policy (see spec §12.3 / §30). A handler that returns
`{:error, :user_not_found}` has *reported* a failure — the
orchestrator may surface that verbatim to the model. A handler that
raises `RuntimeError` has *crashed* — the orchestrator wraps it in
`%ALLM.Error.ToolError{reason: :handler_raised}` and applies its
retry / abort policy. Converting every failure into the same
`%ToolError{}` would erase the distinction; this executor deliberately
does not.

## Arity dispatch

  * arity 1 — `handler.(arguments)`
  * arity 2 — `handler.(arguments, opts)` where `opts` is the call
    context keyword list (`:context`, `:session_id`, `:request_id`,
    `:tool_call`, `:engine`; missing keys read as `nil`).

Handlers of other arities raise `ArgumentError`; non-function handlers
(e.g., `{Module, :function}` MFA tuples, reserved for a future
enhancement) raise `FunctionClauseError` — the honest failure mode
until v0.3 extends the dispatch.

## Usage

Used automatically when `engine.tool_executor` is `nil`; the call
site resolves to this module via
`engine.tool_executor || ALLM.ToolExecutor.Default`.

## Scope

Synchronous, no retries, no timeouts. Phase 6 adds parallel execution
(`ALLM.ToolRunner`) and per-tool timeouts.

# `execute`

```elixir
@spec execute(ALLM.Tool.t(), map(), keyword()) :: ALLM.Tool.handler_result()
```

Invoke a tool's handler and return its result.

See the module doc for the handler-originated-vs-executor-originated
error distinction and the arity dispatch rules.

## Examples

    iex> tool = ALLM.Tool.new(name: "echo", description: "", schema: %{}, handler: fn args -> {:ok, args} end)
    iex> ALLM.ToolExecutor.Default.execute(tool, %{"x" => 1}, [])
    {:ok, %{"x" => 1}}

---

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