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

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.
- `:tool_heartbeat_ms` - Tool-execution keepalive interval in ms (default: 0 =
  off). When `> 0`, the runner emits a `:keepalive` event every interval while
  tools execute, keeping a short-`stream_event_timeout_ms` consumer alive
  through long-running tool calls.
- `: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)
- `:agent_skills` - Agent Skills integration. Pass `true` to trust and discover
  standard roots, a list of trusted roots, discovery options with an explicit
  `:trust` policy, or `specs: [%Jido.AI.Skill.Spec{}]` with optional
  `resource_provider:` for host-backed runtime resources. The agent
  automatically receives the compact catalog and native skill-loading tools
  after strict validation at initialization.
- `: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
- `before_tool_call/2` - Optional argument transformation before agent tool execution
- `after_tool_call/3` - Optional canonical result transformation after agent tool execution

## 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`.

# `tools_from_skills`

```elixir
@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(%{}))

---

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