Jido.AI.Agent (Jido AI v0.5.2)
View SourceGeneral purpose AI agent powered by Jido
Summary
Functions
Validates, plans and executes instructions for the agent with enhanced error handling and state management.
Removes a previously registered action module from the Agent.
Callback implementation for Jido.Agent.handle_signal/2
.
Callback implementation for Jido.Agent.mount/2
.
Creates a new agent instance with an optional ID and initial state.
Callback implementation for Jido.Agent.on_after_run/3
.
Callback implementation for Jido.Agent.on_after_validate_state/1
.
Callback implementation for Jido.Agent.on_before_plan/3
.
Callback implementation for Jido.Agent.on_before_run/1
.
Callback implementation for Jido.Agent.on_before_validate_state/1
.
Callback implementation for Jido.Agent.on_error/2
.
Returns the number of pending actions in the agent's pending_instructions queue.
Plans one or more actions by adding them to the agent's pending instruction queue.
Actions must be registered and valid for the agent. Planning updates the dirty_state?
flag and triggers the on_before_plan
callback.
Registers a new action module with the Agent at server.
Returns all action modules currently registered with the Agent.
Resets the agent's pending action queue.
Executes pending instructions in the agent's queue through a multi-phase process.
Updates the agent's state by deep merging the provided attributes. The update process
Callback implementation for Jido.Agent.shutdown/2
.
Callback implementation for Jido.Agent.transform_result/3
.
Validates the agent's state through a three-phase process
Types
@type agent_result() :: Jido.Agent.agent_result()
@type agent_result_with_directives() :: Jido.Agent.agent_result_with_directives()
@type instruction() :: Jido.Agent.instruction()
@type instructions() :: Jido.Agent.instructions()
@type map_result() :: Jido.Agent.map_result()
@type t() :: Jido.Agent.t()
Functions
@spec cmd(t() | Jido.server(), instructions(), map(), keyword()) :: agent_result_with_directives()
Validates, plans and executes instructions for the agent with enhanced error handling and state management.
Parameters
agent
- The agent struct to act oninstructions
- One of:- Single action module
- Single action tuple {module, params}
- List of action modules
- List of {action_module, params} tuples
- Mixed list of modules and tuples (e.g. [ValidateAction, {ProcessAction, %{file: "data.csv"}}])
context
- Map of execution context data (default: %{})opts
- Keyword list of execution options::runner
- Custom runner module (default: agent's configured runner):strict_validation
- Enable/disable param validation (default: false)
Command Flow
- Optional parameter validation
- Instruction normalization
- State preparation and merging
- Action planning with context
- Execution with configured runner
- Result processing and state application through directives
Returns
{:ok, updated_agent, directives}
- Command executed successfully- State modifications are handled through directives
- Result stored in agent.result field
{:error, Error.t()}
- Detailed error with context
Examples
# Basic command with single action
{:ok, agent, directives} = MyAgent.cmd(agent, ProcessAction)
# Single action with params
{:ok, agent, directives} = MyAgent.cmd(agent, {ProcessAction, %{file: "data.csv"}})
# Multiple actions with context
{:ok, agent, directives} = MyAgent.cmd(
agent,
[
ValidateAction,
{ProcessAction, %{file: "data.csv"}},
StoreAction
],
%{user_id: "123"}
)
# With custom options
{:ok, agent, directives} = MyAgent.cmd(
agent,
{ProcessAction, %{file: "data.csv"}},
%{user_id: "123"},
runner: CustomRunner
)
# Error handling
case MyAgent.cmd(agent, ProcessAction, %{}) do
{:ok, updated_agent, directives} ->
# Success case - state updated through directives
updated_agent.state
{:error, %Error{type: :validation_error}} ->
# Handle validation failure
{:error, %Error{type: :execution_error}} ->
# Handle execution error
end
@spec deregister_action(t(), module()) :: agent_result()
Removes a previously registered action module from the Agent.
Parameters
agent
- The Agent struct to updateaction_module
- The action module to remove
Returns
{:ok, updated_agent}
- Action successfully deregistered{:error, term()}
- Deregistration failed
Example
{:ok, agent} = MyAgent.deregister_action(agent, MyApp.Actions.OldAction)
@spec handle_signal(Jido.Signal.t(), t()) :: {:ok, Jido.Signal.t()} | {:error, any()}
Callback implementation for Jido.Agent.handle_signal/2
.
@spec mount(Jido.Agent.Server.State.t(), opts :: keyword()) :: agent_result()
Callback implementation for Jido.Agent.mount/2
.
Creates a new agent instance with an optional ID and initial state.
Initialization
The new agent is initialized with:
- A unique identifier (provided or auto-generated)
- Default state values from schema
- Empty instruction queue
- Clean state flag (dirty_state?: false)
- Configured actions from compile-time options
- Empty result field
ID Generation
If no ID is provided, a UUIDv4 is generated using namespace-based deterministic generation
via Jido.Util.generate_id/0
. The generated ID is guaranteed to be:
- Unique within the current server
- Cryptographically secure
- URL-safe string format
State Initialization
The initial state is constructed using default values from the compile-time schema:
- Fields with defaults use their specified values
- Required fields without defaults are initialized as nil
- Optional fields without defaults are omitted
- Unknown fields are ignored
- Initial state map is merged and validated if provided
Parameters
id
- Optional string ID for the agent. When provided:- Must be unique within your system
- Should be URL-safe
- Should not exceed 255 characters
- Is used-as-is without validation
initial_state
- Optional map of initial state values to merge with defaults
Returns
t()
- A new agent struct containing::id
- String, provided or generated identifier:state
- Map, initialized with schema defaults and initial_state:dirty_state?
- Boolean, set to false:pending_instructions
- Queue, empty :queue.queue():actions
- List, configured action modules from compile-time:result
- Term, initialized as nil
Examples
# Create with auto-generated ID
agent = MyAgent.new()
agent.id #=> "c4b3f-..." (UUID format)
agent.dirty_state? #=> false
# Create with custom ID and initial state
agent = MyAgent.new("custom_id_123", %{status: :ready})
agent.id #=> "custom_id_123"
agent.state.status #=> :ready
# Schema defaults are applied
defmodule AgentWithDefaults do
use Jido.Agent,
name: "test",
schema: [
status: [type: :atom, default: :pending],
retries: [type: :integer, default: 3],
optional_field: [type: :string]
]
end
agent = AgentWithDefaults.new()
agent.state #=> %{
status: :pending, # From default
retries: 3, # From default
optional_field: nil # No default
}
Warning
While IDs are guaranteed unique when auto-generated, the function does not validate uniqueness of provided IDs. When supplying custom IDs, you must ensure uniqueness within your system's context.
See Jido.Util.generate_id/0
for details on ID generation.
@spec on_after_run(t(), map(), [Jido.Agent.Directive.t()]) :: agent_result()
Callback implementation for Jido.Agent.on_after_run/3
.
@spec on_after_validate_state(t()) :: agent_result()
Callback implementation for Jido.Agent.on_after_validate_state/1
.
@spec on_before_plan(t(), Jido.Instruction.instruction_list(), map()) :: agent_result()
Callback implementation for Jido.Agent.on_before_plan/3
.
@spec on_before_run(t()) :: agent_result()
Callback implementation for Jido.Agent.on_before_run/1
.
@spec on_before_validate_state(t()) :: agent_result()
Callback implementation for Jido.Agent.on_before_validate_state/1
.
@spec on_error(t(), any()) :: agent_result()
Callback implementation for Jido.Agent.on_error/2
.
@spec pending?(t()) :: non_neg_integer()
Returns the number of pending actions in the agent's pending_instructions queue.
Parameters
- agent: The agent struct to check
Returns
- Integer count of pending actions
@spec plan(t() | Jido.server(), instructions(), map()) :: agent_result()
Plans one or more actions by adding them to the agent's pending instruction queue.
Actions must be registered and valid for the agent. Planning updates the dirty_state?
flag and triggers the on_before_plan
callback.
Action Registration
- Actions must be registered via
register_action/2
- Invalid or unregistered actions fail planning
Parameters
agent
- The agent struct to plan actions forinstructions
- One of (seeInstruction.normalize/2
for details):- Single action module
- Single action tuple {module, params}
- List of action modules
- List of {action_module, params} tuples
- Mixed list of modules and tuples (e.g. [ValidateAction, {ProcessAction, %{file: "data.csv"}}])
context
- Optional map of context data to include in instructions (default: %{})
Planning Process
- Normalizes instructions into consistent [{module, params}] format
- Validates action registration
- Builds
Instruction
structs with params and provided context - Executes on_before_plan callback
- Adds instructions to pending queue
- Sets dirty_state? flag
Returns
{:ok, updated_agent}
- Agent with updated pending_instructions and dirty_state?{:error, reason}
- Planning failed
Examples
# Plan single action
{:ok, agent} = MyAgent.plan(agent, ProcessAction)
# Plan single action with params and context
{:ok, agent} = MyAgent.plan(agent, {ProcessAction, %{file: "data.csv"}}, %{user_id: "123"})
# Plan multiple actions with shared context
{:ok, agent} = MyAgent.plan(agent, [
ValidateAction,
{ProcessAction, %{file: "data.csv"}},
{SaveAction, %{path: "/tmp"}}
], %{request_id: "abc123"})
# Validation failures
{:error, reason} = MyAgent.plan(agent, UnregisteredAction)
{:error, reason} = MyAgent.plan(agent, [{InvalidAction, %{}}])
Error Handling
- Unregistered actions return execution error with affected action details
- Invalid instruction format returns error with expected format details
- Failed callbacks return error with callback context
- All errors include agent_id and relevant debugging information
See registered_actions/1
for checking available actions and run/2
for executing planned actions.
@spec register_action(t(), module()) :: agent_result()
Registers a new action module with the Agent at server.
The action module must implement the Jido.Action
behavior and will be
validated before registration.
Parameters
agent
- The Agent struct to updateaction_module
- The action module to register
Returns
{:ok, updated_agent}
- Action successfully registered{:error, term()}
- Registration failed (invalid module)
Example
{:ok, agent} = MyAgent.register_action(agent, MyApp.Actions.NewAction)
Returns all action modules currently registered with the Agent.
This includes both compile-time configured actions and server registered ones. Actions are returned in registration order (most recently registered first).
Parameters
agent
- The Agent struct to inspect
Returns
[module()]
- List of registered action modules, empty if none
Example
actions = MyAgent.registered_actions(agent)
# Returns: [MyAction1, MyAction2]
@spec reset(t()) :: agent_result()
Resets the agent's pending action queue.
Parameters
- agent: The agent struct to reset
Returns
{:ok, updated_agent}
- Queue was reset successfully
@spec run( t() | Jido.server(), keyword() ) :: agent_result_with_directives()
Executes pending instructions in the agent's queue through a multi-phase process.
Instructions are executed with the help of a runner. Review Jido.Runner
for more information.
Each phase can modify the agent's state and trigger callbacks.
Execution Flow
- Pre-execution callback (
on_before_run/1
) - Runner execution of pending instructions
- Post-execution callback (
on_after_run/3
) - Return agent with updated state and result
Parameters
agent
- The agent struct containing pending instructionsopts
- Keyword list of options::runner
- Module implementing the Runner behavior (default: agent's configured runner)
State Management
State modifications are handled through StateModification directives:
:set
- Set a value at a path:%StateModification{op: :set, path: [:config, :mode], value: :active}
:update
- Update with function:%StateModification{op: :update, path: [:counter], value: &(&1 + 1)}
:delete
- Remove value at path:%StateModification{op: :delete, path: [:temp_data]}
:reset
- Set path to nil:%StateModification{op: :reset, path: [:cache]}
Directives
- Directives are applied after runner execution
- Directives can modify agent state and result, such as adding or removing actions or enqueuing new instructions
- Review
Jido.Agent.Directive
for more information
Returns
{:ok, updated_agent, directives}
- Execution completed successfully{:error, %Error{}}
- Execution failed with specific error type::execution_error
- Runner execution failed- Any other error wrapped as execution_error
Examples
# Set up your agent, register and plan some actions to fill the instruction queue
agent = MyAgent.new()
{:ok, agent} = MyAgent.plan(agent, [BasicAction, {NoSchema, %{value: 2}}])
# Basic execution with state modification directives
{:ok, agent, directives} = MyAgent.run(agent)
# Using custom runner
{:ok, agent, directives} = MyAgent.run(agent, runner: CustomRunner)
# Error handling
case MyAgent.run(agent) do
{:ok, agent, directives} ->
# Success - state updated through directives
agent.state
{:error, %Error{type: :validation_error}} ->
# Handle validation failure
{:error, %Error{type: :execution_error}} ->
# Handle execution failure
end
Callbacks
on_before_run/1
- Pre-execution preparationon_after_run/3
- Post-execution processing
See Jido.Runner
for implementing custom runners and plan/2
for queueing actions.
@spec set(t() | Jido.server(), keyword() | map(), keyword()) :: agent_result()
Updates the agent's state by deep merging the provided attributes. The update process:
- Deep merges new attributes with existing state
- Validates the merged state against schema
- Sets dirty_state? flag for tracking changes
- Triggers validation callbacks
Parameters
agent
- The agent struct to updateattrs
- Map or keyword list of attributes to merge into stateopts
- Optional keyword list of options:strict_validation
- Boolean, whether to perform strict validation (default: false)
Returns
{:ok, updated_agent}
- Agent with merged state and dirty_state? = true{:error, reason}
- If validation fails or callbacks return error
State Management
- Empty updates return success without changes
- Updates trigger
on_before_validate_state
andon_after_validate_state
callbacks - Unknown fields are preserved during deep merge
- Nested updates are supported via deep merging
Field Validation
Only fields defined in the schema are validated. Unknown fields are preserved during deep merge.
Examples
# Simple update
{:ok, agent} = MyAgent.set(agent, status: :running)
# Deep merge update
{:ok, agent} = MyAgent.set(agent, %{
config: %{retries: 3},
metadata: %{started_at: DateTime.utc_now()}
})
# Validation failure
{:error, "Invalid status value"} = MyAgent.set(agent, status: :invalid)
See validate/1
for validation details and Jido.Agent
callbacks for lifecycle hooks.
@spec shutdown(Jido.Agent.Server.State.t(), reason :: any()) :: agent_result()
Callback implementation for Jido.Agent.shutdown/2
.
@spec transform_result(Jido.Signal.t(), term() | {:ok, term()} | {:error, any()}, t()) :: {:ok, term()} | {:error, any()}
Callback implementation for Jido.Agent.transform_result/3
.
@spec validate( t() | Jido.server(), keyword() ) :: agent_result()
Validates the agent's state through a three-phase process:
- Executes pre-validation callback (
on_before_validate_state/1
) - Validates known fields against schema using NimbleOptions
- Executes post-validation callback (
on_after_validate_state/1
)
Validation Process
- Only schema-defined fields are validated
- Unknown fields are preserved unchanged
- NimbleOptions performs type and constraint checking
Parameters
agent
- The agent struct to validateopts
- Optional keyword list of options:strict_validation
- Boolean, whether to perform strict validation (default: false)
Returns
{:ok, validated_agent}
- Agent with validated state{:error, reason}
- Validation failed with reason
Examples
# Successful validation with schema
defmodule MyAgent do
use Jido.Agent,
name: "my_agent",
schema: [
status: [type: :atom, values: [:pending, :running]],
retries: [type: :integer, minimum: 0]
]
# Optional validation hooks
def on_before_validate_state(agent) do
# Pre-validation logic
{:ok, agent}
end
end
{:ok, agent} = MyAgent.validate(agent)
# Failed validation
{:error, "Invalid status value"} = MyAgent.validate(%{
agent | state: %{status: :invalid}
})
# Unknown fields preserved
{:ok, agent} = MyAgent.validate(%{
agent | state: %{status: :pending, custom_field: "preserved"}
})
Validation Flow
on_before_validate_state
- Preprocess state- Schema validation via NimbleOptions
on_after_validate_state
- Postprocess validated state
See NimbleOptions
documentation for supported validation rules.