Build tool-using Elixir agents with explicit reasoning strategies and production-ready request orchestration.
Hex | HexDocs | Jido Ecosystem | Discord
jido_ai is the AI runtime layer for Jido. You define tools and agents as Elixir modules, then run synchronous or asynchronous requests with built-in model routing, retries, and observability.
defmodule MyApp.Actions.AddNumbers do
use Jido.Action,
name: "add_numbers",
schema: Zoi.object(%{a: Zoi.integer(), b: Zoi.integer()}),
description: "Add two numbers."
@impl true
def run(%{a: a, b: b}, _context), do: {:ok, %{sum: a + b}}
end
defmodule MyApp.MathAgent do
use Jido.AI.Agent,
name: "math_agent",
model: :fast,
tools: [MyApp.Actions.AddNumbers],
system_prompt: "Solve accurately. Use tools for arithmetic."
end
{:ok, pid} = Jido.AgentServer.start(agent: MyApp.MathAgent)
{:ok, answer} = MyApp.MathAgent.ask_sync(pid, "What is 19 + 23?")jido_ai is a core package in the Jido ecosystem:
- jido: agent runtime, process model, and signal lifecycle
- jido_action: typed tool/action contract used by
jido_ai - req_llm: provider abstraction for Anthropic, OpenAI, Google, and others
Use jido_ai when you need long-lived agents, tool-calling loops, or explicit reasoning strategies. You can also use it without a running agent process via Jido.AI.generate_text/2, Jido.AI.ask/2, or Jido.Exec.run/3 with any action module.
For cross-package tutorials and the package map, see jido.run/ecosystem.
In jido_ai, tool actions are allowed to be effectful. They often perform HTTP, LLM, database, or file I/O because the model needs the result back in the same ReAct loop.
The purity boundary lives around agent strategy decisions and runtime orchestration, not necessarily inside each tool action. Use a tool action when the next reasoning step needs the result now. Use directives, signals, or runtime integrations when an outbound effect has already been decided and the runtime should own delivery, retry, and observability.
The fastest way to get started is with Igniter:
mix igniter.install jido_aiThis automatically:
- Adds
jido_aito your dependencies - Configures default model aliases
- Reminds you to set up API keys
Add jido_ai to your list of dependencies in mix.exs:
def deps do
[
{:jido, "~> 2.0"},
{:jido_ai, "~> 2.0.0-rc.0"}
]
endmix deps.getConfigure model aliases and at least one provider credential:
# config/config.exs
config :jido_ai,
model_aliases: %{
fast: "provider:fast-model",
capable: "provider:capable-model"
}
config :req_llm,
anthropic_api_key: System.get_env("ANTHROPIC_API_KEY"),
openai_api_key: System.get_env("OPENAI_API_KEY")- Define one
Jido.Actiontool. - Define one
Jido.AI.Agentwith that tool. - Start the agent and call
ask_sync/3orask/3+await/2.
defmodule MyApp.Actions.Multiply do
use Jido.Action,
name: "multiply",
schema: Zoi.object(%{a: Zoi.integer(), b: Zoi.integer()})
@impl true
def run(%{a: a, b: b}, _context), do: {:ok, %{product: a * b}}
end
defmodule MyApp.Agent do
use Jido.AI.Agent,
name: "my_agent",
model: :fast,
tools: [MyApp.Actions.Multiply]
end
{:ok, pid} = Jido.AgentServer.start(agent: MyApp.Agent)
# Sync convenience path
{:ok, result} = MyApp.Agent.ask_sync(pid, "What is 15 * 23?")
# Async path with explicit request handle
{:ok, request} = MyApp.Agent.ask(pid, "What is 144 * 12?")
{:ok, result2} = MyApp.Agent.await(request, timeout: 15_000)ask/3 and ask_sync/3 can narrow or override the active tool registry for a single run:
{:ok, result} =
MyApp.Agent.ask_sync(pid, "Multiply 15 by 23",
allowed_tools: ["multiply"],
tool_context: %{tenant_id: "acme"},
llm_opts: [reasoning_effort: :medium]
)allowed_tools:filters the agent's configured tools by name for one request.tools:replaces the tool registry for one request.request_transformer:lets you reshape each LLM turn, including dynamic tool gating and structured-output schemas.
After a ReAct run, snapshot.result is the final assistant answer. Completed
tool outputs are available separately through
snapshot.details[:tool_results], so callers do not need to parse conversation
messages or request traces to recover structured tool data.
For retrieval or classification flows, prefer having tools write StateOp.SetState updates and let a request_transformer read context[:state] to constrain the next turn. That keeps tool exposure, runtime state, and output schemas aligned without scraping message history. See Standalone ReAct Runtime for the pattern.
Need one-shot text generation without an agent process?
{:ok, text} = Jido.AI.ask("Summarize Phoenix PubSub in one paragraph.", model: :fast)| If you need | Use | Why |
|---|---|---|
| Tool-using agent loops | Jido.AI.Agent |
ReAct strategy with request tracking and tool orchestration |
| Fixed reasoning strategy | Jido.AI.CoDAgent, Jido.AI.CoTAgent, Jido.AI.AoTAgent, Jido.AI.ToTAgent, Jido.AI.GoTAgent, Jido.AI.TRMAgent, Jido.AI.AdaptiveAgent |
Strategy-specific control over reasoning behavior |
| AI inside existing workflows/jobs | Jido.AI.Actions.* |
Run via Jido.Exec.run/3 without defining an agent module |
| Streaming + checkpoint/resume | Jido.AI.Reasoning.ReAct |
Standalone ReAct runtime with event streams and checkpoint tokens |
| Thin model facade helpers | Jido.AI.generate_text/2, generate_object/3, stream_text/2, ask/2 |
Fast path for direct LLM calls with alias/default support |
- ReAct (
Jido.AI.Agent): default for tool/API calls. - CoD (
Jido.AI.CoDAgent): concise reasoning with lower latency/cost. - Chain-of-Thought (CoT) (
Jido.AI.CoTAgent): asks the model to reason through a problem in explicit intermediate steps before the final answer; useful for math, logic, and other multi-step tasks. - AoT (
Jido.AI.AoTAgent): one-pass algorithmic exploration with explicit final answer extraction. - ToT / GoT (
Jido.AI.ToTAgent,Jido.AI.GoTAgent): branching or graph-style exploration for complex tasks. - TRM (
Jido.AI.TRMAgent): iterative recursive refinement. - Adaptive (
Jido.AI.AdaptiveAgent): mixed workloads where strategy selection varies per task.
Full tradeoff matrix: Strategy Selection Playbook
Unknown model alias: :my_model
- Add the alias under
config :jido_ai, model_aliases: ... - Or pass a direct model string (for example
"provider:exact-model-id")
{:error, :not_a_tool} when registering or calling tools
- Ensure your tool module implements
name/0,schema/0, andrun/2 - Validate with
Jido.AI.register_tool(pid, MyToolModule)
- HexDocs — Full API reference and guides
- Jido Ecosystem — Ecosystem overview and cross-package tutorials
- Discord — Community discussion
Start here:
Strategy guides:
Integration and runtime guides:
- LLM Facade Quickstart
- Tool Calling With Actions
- Context And Message Projection
- Turn And Tool Results
- Request Lifecycle And Concurrency
- Retrieval And Quota
- Observability Basics
- Standalone ReAct Runtime
- CLI Workflows
Upgrading:
Deep reference:
- Actions Catalog
- Configuration Reference
- Architecture And Runtime Flow
- Thread-Context Projection Model
- HexDocs
The runnable demos now live in the top-level examples/
folder and are loaded on demand, so they stay out of the core jido_ai compile path.
mix run examples/scripts/demo/actions_llm_runtime_demo.exs
mix run examples/scripts/demo/actions_tool_calling_runtime_demo.exs
mix run examples/scripts/demo/actions_reasoning_runtime_demo.exs
mix run examples/scripts/demo/weather_multi_turn_context_demo.exsAdditional examples:
examples/lib/agents/weather_agent.exexamples/lib/agents/react_demo_agent.exexamples/lib/tools/weather_by_location.ex
- ReAct-first agent runtime with explicit request handles —
ask/awaitprevents concurrent result overwrites - Eight built-in reasoning strategy families (ReAct, CoD, CoT, AoT, ToT, GoT, TRM, Adaptive)
- Unified tool contract via
Jido.Actionmodules with compile-time safety - Strategy-independent
ActionsAPI for direct integration withJido.Exec - Stable telemetry event names via
Jido.AI.Observefor production dashboards - Policy and quota plugins rewrite unsafe or over-budget requests deterministically
See CONTRIBUTING.md.
Apache-2.0. See LICENSE.md.