Jido.AI.Agent (Jido AI v2.2.0)

Copy Markdown View Source

Base macro for Jido.AI agents with ReAct strategy implied.

Wraps use Jido.Agent with Jido.AI.Reasoning.ReAct.Strategy wired in, plus standard state fields and helper functions.

Usage

defmodule MyApp.WeatherAgent do
  use Jido.AI.Agent,
    name: "weather_agent",
    description: "Weather Q&A agent",
    tools: [MyApp.Actions.Weather, MyApp.Actions.Forecast],
    system_prompt: "You are a weather expert..."
end

Options

  • :name (required) - Agent name
  • :tools (required) - List of Jido.Action modules to use as tools
  • :description - Agent description (default: "AI agent #{name}")
  • :tags - Agent tags for discovery/classification (default: [])
  • :system_prompt - Custom system prompt for the LLM
  • :model - Model alias or direct model spec (default: :fast, resolved via Jido.AI.resolve_model/1)
  • :max_iterations - Maximum reasoning iterations (default: 10)
  • :max_tokens - Maximum tokens per LLM response (default: 4096)
  • :streaming - Whether to stream LLM responses (default: true)
  • :request_policy - Request concurrency policy (default: :reject)
  • :tool_timeout_ms - Per-attempt tool execution timeout in ms (default: 15_000)
  • :tool_max_retries - Number of retries for tool failures (default: 1)
  • :tool_retry_backoff_ms - Retry backoff in ms (default: 200)
  • :stream_timeout_ms - Stream consumer timeout in ms (default: auto-derived from tool_timeout_ms + 60s). How long to wait for events between coordinator updates. Increase for agents with slow LLM responses or long tool executions. :stream_receive_timeout_ms is accepted as a compatibility alias.
  • :effect_policy - Agent-level effect policy (default allow-list)
  • :strategy_effect_policy - Optional strategy-level narrowing policy (cannot broaden agent policy)
  • :runtime_adapter - Deprecated compatibility flag (delegated ReAct runtime is always enabled)
  • :runtime_task_supervisor - Optional Task.Supervisor used by delegated ReAct runtime
  • :observability - Observability options map
  • :req_http_options - Base Req HTTP options passed through to ReqLLM calls
  • :llm_opts - Additional ReqLLM generation options merged into ReAct LLM calls
  • :request_transformer - Module implementing per-turn ReAct request shaping
  • :output - Structured final-output config with an object-shaped Zoi or JSON Schema
  • :tool_context - Context map passed to all tool executions (e.g., %{actor: user, domain: MyDomain}). Must be literal data only — module aliases, atoms, strings, numbers, lists, and maps are permitted. Function calls, module attributes (@attr), and pinned variables (^var) raise CompileError. Runtime reserves :state (core Jido-compatible) for tool execution snapshots. User-provided values for that key are overwritten per request.
  • :skills - Additional skills to attach to the agent (TaskSupervisorSkill is auto-included)
  • :signal_routes - Additional agent-level signal routes forwarded to Jido.Agent. ReAct routes are still provided by the default strategy.

Generated Functions

  • ask/2,3 - Async: sends query, returns {:ok, %Request{}} for later awaiting
  • ask_stream/2,3 - Async: sends query and returns a request handle plus runtime event stream
  • await/1,2 - Awaits a specific request's completion
  • ask_sync/2,3 - Sync convenience: sends query and waits for result
  • on_before_cmd/2 - Captures request in state before processing
  • on_after_cmd/3 - Updates request result when done

Request Tracking

Each ask/2 call returns a Request struct that can be awaited:

{:ok, request} = MyAgent.ask(pid, "What is 2+2?")
{:ok, result} = MyAgent.await(request, timeout: 30_000)

Or use the synchronous convenience wrapper:

{:ok, result} = MyAgent.ask_sync(pid, "What is 2+2?", timeout: 30_000)

This pattern follows Elixir's Task.async/await idiom and enables safe concurrent request handling.

State Fields

The agent state includes:

  • :model - The LLM model being used
  • :requests - Map of request_id => request state (for concurrent tracking)
  • :last_request_id - ID of the most recent request
  • :last_query - The most recent query (backward compat)
  • :last_answer - The final answer from the last completed query (backward compat)
  • :completed - Boolean indicating if the last query is complete (backward compat)

Task Supervisor

Each agent instance gets its own Task.Supervisor automatically started via the Jido.AI.Plugins.TaskSupervisor. This supervisor is used for:

  • LLM streaming operations
  • Tool execution
  • Other async operations within the agent's lifecycle

The supervisor is stored in the skill's internal state (agent.state.__task_supervisor_skill__) and is accessible via Jido.AI.Directive.Helpers.get_task_supervisor/1. It is automatically cleaned up when the agent terminates.

Example

{:ok, pid} = Jido.AgentServer.start(agent: MyApp.WeatherAgent)

# Async pattern (preferred for concurrent requests)
{:ok, request} = MyApp.WeatherAgent.ask(pid, "What's the weather in Tokyo?")
{:ok, answer} = MyApp.WeatherAgent.await(request)

# Sync pattern (convenience for simple cases)
{:ok, answer} = MyApp.WeatherAgent.ask_sync(pid, "What's the weather in Tokyo?")

Per-Request Tool Context

You can pass per-request context that will be merged with the agent's base tool_context:

{:ok, request} = MyApp.WeatherAgent.ask(pid, "Get my preferences",
  tool_context: %{actor: current_user, tenant_id: "acme"})

ReAct and ToT tool execution contexts include a runtime-managed snapshot at :state (canonical, core-aligned). This key is reserved and overrides same-named values from tool_context.

Summary

Functions

Extract tool action modules from skills.

Functions

tools_from_skills(skill_modules)

@spec tools_from_skills([module()]) :: [module()]

Extract tool action modules from skills.

Useful when you want to use skill actions as agent tools.

Example

@skills [MyApp.WeatherSkill, MyApp.LocationSkill]

use Jido.AI.Agent,
  name: "weather_agent",
  tools: Jido.AI.Agent.tools_from_skills(@skills),
  skills: Enum.map(@skills, & &1.skill_spec(%{}))