# `Jido.AI.ToolAdapter`
[🔗](https://github.com/agentjido/jido_ai/blob/v2.4.0/lib/jido_ai/tool_adapter.ex#L1)

Adapts Jido Actions into ReqLLM.Tool structs for LLM consumption.

This module bridges Jido domain concepts (actions with schemas) to ReqLLM's
tool representation.

## Design

- **Schema-focused**: Tools use a noop callback; Jido owns execution via `Directive.ToolExec`
- **Adapter pattern**: Converts `Jido.Action` behaviour → `ReqLLM.Tool` struct
- **Single source of truth**: All action→tool conversion goes through this module

## Usage

    # Convert action modules to ReqLLM tools
    tools = Jido.AI.ToolAdapter.from_actions([
      MyApp.Actions.Calculator,
      MyApp.Actions.Search
    ])

    # With options
    tools = Jido.AI.ToolAdapter.from_actions(actions,
      prefix: "myapp_",
      filter: fn mod -> mod.category() == :search end
    )

    # Use in LLM call
    ReqLLM.stream_text(model, messages, tools: tools)

# `from_action`

```elixir
@spec from_action(module(), keyword()) :: ReqLLM.Tool.t()
```

Converts a single Jido.Action module into a ReqLLM.Tool struct.

## Arguments

  * `action_module` - A module implementing the `Jido.Action` behaviour
  * `opts` - Optional keyword list of options

## Options

  * `:prefix` - String prefix to add to the tool name (e.g., `"myapp_"`)
  * `:strict` - Whether to enable strict mode on the tool. When not set,
    auto-detects based on the action's `strict?/0` callback (defaults to `false`).

## Returns

  A `ReqLLM.Tool` struct

## Example

    tool = Jido.AI.ToolAdapter.from_action(MyApp.Actions.Calculator, prefix: "v2_")
    # => %ReqLLM.Tool{name: "v2_calculator", ...}

# `from_actions`

```elixir
@spec from_actions([module()], keyword()) :: [ReqLLM.Tool.t()]
```

Converts a list of Jido.Action modules into ReqLLM.Tool structs.

The returned tools use a noop callback—they're purely for describing available
actions to the LLM. Actual execution happens via `Jido.AI.Directive.ToolExec`.

## Arguments

  * `action_modules` - List of modules implementing the `Jido.Action` behaviour
  * `opts` - Optional keyword list of options

## Options

  * `:prefix` - String prefix to add to all tool names (e.g., `"myapp_"`)
  * `:filter` - Function `(module -> boolean)` to filter which actions to include
  * `:strict` - Whether to enable strict mode on the tools. When not set,
    auto-detects based on each action's `strict?/0` callback (defaults to `false`).

## Returns

  A list of `ReqLLM.Tool` structs

## Examples

    # Basic usage
    tools = Jido.AI.ToolAdapter.from_actions([MyApp.Actions.Add, MyApp.Actions.Search])

    # With prefix
    tools = Jido.AI.ToolAdapter.from_actions(actions, prefix: "calc_")
    # Tool names become "calc_add", "calc_search", etc.

    # With filter
    tools = Jido.AI.ToolAdapter.from_actions(actions,
      filter: fn mod -> mod.category() == :math end
    )

# `lookup_action`

```elixir
@spec lookup_action(String.t(), [module()], keyword()) ::
  {:ok, module()} | {:error, :not_found}
```

Looks up an action module by tool name from a list of action modules.

Useful for finding which action module corresponds to a tool name returned
by an LLM.

## Arguments

  * `tool_name` - The name of the tool to look up
  * `action_modules` - List of action modules to search

## Returns

  * `{:ok, module}` - If found
  * `{:error, :not_found}` - If no action module has that tool name

## Example

    {:ok, module} = ToolAdapter.lookup_action("calculator", [Calculator, Search])
    # => {:ok, Calculator}

    {:error, :not_found} = ToolAdapter.lookup_action("unknown", [Calculator])
    # => {:error, :not_found}

# `to_action_map`

```elixir
@spec to_action_map(nil | map() | [module()] | module()) :: %{
  required(String.t()) =&gt; module()
}
```

Normalizes tool input into an action lookup map (`%{name => module}`).

Accepts any of the common tool container shapes used by actions/skills:

- `nil` -> `%{}`
- `%{"tool_name" => MyAction}` -> unchanged
- `%{tool_name: MyAction}` -> `%{"tool_name" => MyAction}` when values are modules
- `[MyAction, OtherAction]` -> `%{"my_action" => MyAction, "other_action" => OtherAction}`
- `MyAction` -> `%{"my_action" => MyAction}`

# `validate_actions`

```elixir
@spec validate_actions([module()]) ::
  :ok | {:error, {:invalid_action, module(), atom()}}
```

Validates that all modules in the list implement the Jido.Action behaviour.

Returns `:ok` if all modules are valid, or `{:error, {:invalid_action, module, reason}}`
for the first invalid module found.

## Example

    :ok = ToolAdapter.validate_actions([Calculator, Search])
    {:error, {:invalid_action, BadModule, :missing_name}} = ToolAdapter.validate_actions([BadModule])

---

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