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

AI integration layer for the Jido ecosystem.

Jido.AI provides a unified interface for AI interactions, built on ReqLLM and
integrated with the Jido action framework.

## Features

- Model aliases for semantic model references
- Lightweight app-configured LLM defaults
- Thin ReqLLM generation facades
- Action-based AI workflows
- Splode-based error handling

## Model Aliases

Use semantic model aliases instead of hardcoded model strings:

    Jido.AI.resolve_model(:fast)      # => "provider:fast-model"
    Jido.AI.resolve_model(:capable)   # => "provider:capable-model"

Configure custom aliases in your config:

    config :jido_ai,
      model_aliases: %{
        fast: "provider:your-fast-model",
        capable: "provider:your-capable-model"
      }

Aliases can also point at full direct model specs when you need richer
ReqLLM metadata, such as a custom OpenAI-compatible `base_url`:

    config :jido_ai,
      model_aliases: %{
        capable: %{
          provider: :openai,
          id: "moonshotai.kimi-k2.5",
          base_url: "https://proxy.example.com/v1"
        }
      }

A broad list of provider/model IDs is available at: https://llmcatalog.dev

## LLM Defaults

Configure small, role-based defaults for top-level generation helpers:

    config :jido_ai,
      llm_defaults: %{
        text: %{model: :fast, temperature: 0.2, max_tokens: 1024},
        object: %{model: :thinking, temperature: 0.0, max_tokens: 1024},
        stream: %{model: :fast, temperature: 0.2, max_tokens: 1024}
      }

Then call the facade directly:

    {:ok, response} = Jido.AI.generate_text("Summarize this in one sentence.")
    {:ok, json} = Jido.AI.generate_object("Extract fields", schema)
    {:ok, stream} = Jido.AI.stream_text("Stream this response")

## Runtime Tool Management

Register and unregister tools dynamically with running agents:

    # Register a new tool
    {:ok, agent} = Jido.AI.register_tool(agent_pid, MyApp.Tools.Calculator)

    # Unregister a tool by name
    {:ok, agent} = Jido.AI.unregister_tool(agent_pid, "calculator")

    # List registered tools
    {:ok, tools} = Jido.AI.list_tools(agent_pid)

    # Check if a tool is registered
    {:ok, true} = Jido.AI.has_tool?(agent_pid, "calculator")

Tools must implement the `Jido.Action` behaviour (`name/0`, `schema/0`, `run/2`).

# `llm_generation_opts`

```elixir
@type llm_generation_opts() :: %{
  optional(:model) =&gt; model_input(),
  optional(:system_prompt) =&gt; String.t(),
  optional(:max_tokens) =&gt; non_neg_integer(),
  optional(:temperature) =&gt; number(),
  optional(:timeout) =&gt; pos_integer()
}
```

# `llm_kind`

```elixir
@type llm_kind() :: :text | :object | :stream
```

# `model_alias`

```elixir
@type model_alias() ::
  :fast
  | :capable
  | :thinking
  | :reasoning
  | :planning
  | :image
  | :embedding
  | atom()
```

# `model_input`

```elixir
@type model_input() :: model_alias() | ReqLLM.model_input()
```

# `model_spec`

```elixir
@type model_spec() :: String.t()
```

# `ask`

```elixir
@spec ask(term(), keyword()) :: {:ok, String.t()} | {:error, term()}
```

Convenience helper that returns extracted response text.

# `generate_object`

```elixir
@spec generate_object(term(), term(), keyword()) :: {:ok, term()} | {:error, term()}
```

Thin facade for `ReqLLM.Generation.generate_object/4`.

`opts` has the same behavior as `generate_text/2`.

# `generate_text`

```elixir
@spec generate_text(term(), keyword()) :: {:ok, term()} | {:error, term()}
```

Thin facade for `ReqLLM.Generation.generate_text/3`.

`opts` supports:

- `:model` - model alias or direct model spec
- `:system_prompt` - optional system prompt
- `:max_tokens`, `:temperature`, `:timeout`
- Any other ReqLLM options (e.g. `:tools`, `:tool_choice`) as pass-through options

# `get_strategy_config`

```elixir
@spec get_strategy_config(Jido.Agent.t()) :: map()
```

Returns the strategy config from an agent struct.

Convenience for reading strategy config without reaching into internal state.

# `get_strategy_context`

```elixir
@spec get_strategy_context(Jido.Agent.t()) :: map() | nil
```

Returns the active context (conversation history) from the strategy state.

Prefers `:run_context` while a request is in flight, otherwise falls back to
materialized `:context`. Returns nil if neither exists.

# `has_tool?`

```elixir
@spec has_tool?(Jido.Agent.t() | GenServer.server(), String.t()) ::
  boolean() | {:ok, boolean()} | {:error, term()}
```

Checks if a specific tool is registered with an agent.

Can be called with either an agent struct or an agent server (PID/name).

## Examples

    # With agent struct
    true = Jido.AI.has_tool?(agent, "calculator")

    # With agent server
    {:ok, true} = Jido.AI.has_tool?(agent_pid, "calculator")

# `inject`

```elixir
@spec inject(GenServer.server(), String.t(), keyword()) ::
  {:ok, Jido.Agent.t()} | {:error, term()}
```

Compatibility wrapper for `Jido.AI.Reasoning.ReAct.inject/3`.

# `list_tools`

```elixir
@spec list_tools(Jido.Agent.t() | GenServer.server()) ::
  [module()] | {:ok, [module()]} | {:error, term()}
```

Lists all currently registered tools for an agent.

Can be called with either an agent struct or an agent server (PID/name).

## Examples

    # With agent struct
    tools = Jido.AI.list_tools(agent)

    # With agent server
    {:ok, tools} = Jido.AI.list_tools(agent_pid)

# `llm_defaults`

```elixir
@spec llm_defaults() :: %{required(llm_kind()) =&gt; llm_generation_opts()}
```

Returns configured LLM generation defaults merged with built-in defaults.

Configure under `config :jido_ai, :llm_defaults`.

# `llm_defaults`

```elixir
@spec llm_defaults(llm_kind()) :: llm_generation_opts()
```

Returns defaults for a specific generation kind: `:text`, `:object`, or `:stream`.

# `model_aliases`

```elixir
@spec model_aliases() :: %{required(model_alias()) =&gt; ReqLLM.model_input()}
```

Returns all configured model aliases merged with defaults.

User overrides from `config :jido_ai, :model_aliases` are merged on top of built-in defaults.

## Examples

    iex> aliases = Jido.AI.model_aliases()
    iex> is_binary(aliases[:fast])
    true

# `model_label`

```elixir
@spec model_label(model_input()) :: String.t()
```

Returns a stable human-readable label for a model input.

# `register_tool`

```elixir
@spec register_tool(GenServer.server(), module(), keyword()) ::
  {:ok, Jido.Agent.t()} | {:error, term()}
```

Registers a tool module with a running agent.

The tool must implement the `Jido.Action` behaviour (have `name/0`, `schema/0`, and `run/2`).

## Options

  * `:timeout` - Call timeout in milliseconds (default: 5000)
  * `:validate` - Validate tool implements required callbacks (default: true)

## Examples

    {:ok, agent} = Jido.AI.register_tool(agent_pid, MyApp.Tools.Calculator)
    {:error, :not_a_tool} = Jido.AI.register_tool(agent_pid, NotATool)

# `register_tool_direct`

```elixir
@spec register_tool_direct(Jido.Agent.t(), module(), keyword()) ::
  {:ok, Jido.Agent.t()} | {:error, term()}
```

Registers a tool module directly on an agent struct.

This is the struct-level equivalent of `register_tool/3` — safe to call from
within the agent process or an action already executing inside the agent. It
updates the ReAct strategy tool config without sending an `AgentServer` signal.

## Options

  * `:validate` - Validate tool implements required callbacks (default: true)

# `resolve_model`

```elixir
@spec resolve_model(model_input()) :: ReqLLM.model_input()
```

Resolves a model alias or passes through a direct ReqLLM model input.

Model aliases are atoms like `:fast`, `:capable`, `:reasoning` that map
to full ReqLLM model specifications. Both alias values and direct model
inputs may be strings, ReqLLM tuples, inline maps, or `%LLMDB.Model{}`
structs.

## Arguments

  * `model` - Either a model alias atom or a direct ReqLLM model input

## Returns

  A resolved ReqLLM model input.

## Examples

    iex> String.contains?(Jido.AI.resolve_model(:fast), ":")
    true

    iex> Jido.AI.resolve_model("openai:gpt-4")
    "openai:gpt-4"

    iex> Jido.AI.resolve_model({:openai, "gpt-4.1", []})
    {:openai, "gpt-4.1", []}

    Jido.AI.resolve_model(:unknown_alias)
    # raises ArgumentError with unknown alias message

# `set_system_prompt`

```elixir
@spec set_system_prompt(GenServer.server(), String.t(), keyword()) ::
  {:ok, Jido.Agent.t()} | {:error, term()}
```

Updates the base ReAct system prompt for a running agent.

## Options

  * `:timeout` - Call timeout in milliseconds (default: 5000)

# `set_system_prompt_direct`

```elixir
@spec set_system_prompt_direct(Jido.Agent.t(), String.t()) :: Jido.Agent.t()
```

Sets the system prompt directly on the agent's strategy config.

This is the struct-level equivalent of `set_system_prompt/3` — safe to call
from within the agent process (e.g., `on_before_cmd`).

Also updates the system prompt in `:context` and `:run_context` if they
exist, so resumed conversations pick up the new prompt.

# `steer`

```elixir
@spec steer(GenServer.server(), String.t(), keyword()) ::
  {:ok, Jido.Agent.t()} | {:error, term()}
```

Compatibility wrapper for `Jido.AI.Reasoning.ReAct.steer/3`.

# `stream_text`

```elixir
@spec stream_text(term(), keyword()) :: {:ok, term()} | {:error, term()}
```

Thin facade for `ReqLLM.stream_text/3`.

Returns ReqLLM stream response directly.

# `unregister_tool`

```elixir
@spec unregister_tool(GenServer.server(), String.t(), keyword()) ::
  {:ok, Jido.Agent.t()} | {:error, term()}
```

Unregisters a tool from a running agent by name.

## Options

  * `:timeout` - Call timeout in milliseconds (default: 5000)

## Examples

    {:ok, agent} = Jido.AI.unregister_tool(agent_pid, "calculator")

# `unregister_tool_direct`

```elixir
@spec unregister_tool_direct(Jido.Agent.t(), String.t()) :: {:ok, Jido.Agent.t()}
```

Unregisters a tool directly from an agent struct by tool name.

This is the struct-level equivalent of `unregister_tool/3` — safe to call from
within the agent process or an action already executing inside the agent.

# `update_context_entries`

```elixir
@spec update_context_entries(Jido.Agent.t(), list()) :: Jido.Agent.t()
```

Updates the active context entries (conversation messages) in the strategy state.

If `:run_context` exists, it is treated as authoritative for the in-flight
turn and updated in isolation. Otherwise, updates materialized `:context`.

---

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