Jido.Instruction (Jido v1.1.0-rc)

View Source

Instructions in Jido represent discrete units of work that can be planned, validated, and executed by agents. Think of them as "work orders" that tell agents exactly what needs to be done and how to do it.

Core Concepts

An Instruction wraps an Action module with everything it needs to execute:

  • The Action to perform (required)
  • Parameters for the action
  • Execution context
  • Runtime options

Structure

Each Instruction contains:

%Instruction{
  id: "inst_abc123",           # Unique identifier
  action: MyApp.Actions.DoTask, # The action module to execute
  params: %{value: 42},        # Parameters for the action
  context: %{user_id: "123"},  # Execution context
  opts: [retry: true],         # Runtime options
}

Creating Instructions

Instructions support multiple creation formats for convenience:

1. Full Struct (Most Explicit)

%Instruction{
  action: MyApp.Actions.ProcessOrder,
  params: %{order_id: "123"},
  context: %{tenant_id: "456"}
}

2. Action Module Only (Simplest)

MyApp.Actions.ProcessOrder

3. Action With Parameters (Common)

{MyApp.Actions.ProcessOrder, %{order_id: "123"}}

4. Factory Function

Instruction.new!(%{
  action: MyApp.Actions.ProcessOrder,
  params: %{order_id: "123"},
  context: %{tenant_id: "456"}
})

Working with Instructions

Normalization

Convert various input formats to standard instruction structs:

# Normalize a single instruction
{:ok, [instruction]} = Instruction.normalize(MyApp.Actions.ProcessOrder)

# Normalize with context
{:ok, instructions} = Instruction.normalize(
  [
    MyApp.Actions.ValidateOrder,
    {MyApp.Actions.ProcessOrder, %{priority: "high"}}
  ],
  %{tenant_id: "123"}  # Shared context
)

Validation

Ensure instructions use allowed actions:

allowed_actions = [
  MyApp.Actions.ValidateOrder,
  MyApp.Actions.ProcessOrder
]

:ok = Instruction.validate_allowed_actions(instructions, allowed_actions)

Common Patterns

1. Workflow Definition

instructions = [
  MyApp.Actions.ValidateInput,
  {MyApp.Actions.ProcessData, %{format: "json"}},
  MyApp.Actions.SaveResults
]

2. Conditional Execution

instructions = [
  MyApp.Actions.ValidateOrder,
  {MyApp.Actions.CheckInventory, %{strict: true}},
  # Add fulfillment only if in stock
  if has_stock? do
    {MyApp.Actions.FulfillOrder, %{warehouse: "main"}}
  end
]
|> Enum.reject(&is_nil/1)

3. Context Sharing

# All instructions share common context
{:ok, instructions} = Instruction.normalize(
  [ValidateUser, ProcessOrder, NotifyUser],
  %{
    request_id: "req_123",
    tenant_id: "tenant_456",
  }
)

See Also

Summary

Functions

Creates a new Instruction struct from a map or keyword list of attributes.

Creates a new Instruction struct from a map or keyword list of attributes. Returns the struct directly or raises an error.

Normalizes instruction shorthand input into instruction structs. Accepts a variety of input formats and returns a list of normalized instruction structs.

Validates that all instructions use allowed actions.

Types

action_module()

@type action_module() :: module()

action_params()

@type action_params() :: map()

action_tuple()

@type action_tuple() :: {action_module(), action_params()}

instruction()

@type instruction() :: action_module() | action_tuple() | t()

instruction_list()

@type instruction_list() :: [instruction()]

t()

@type t() :: %Jido.Instruction{
  action: module(),
  context: map(),
  id: String.t(),
  opts: keyword(),
  params: map()
}

Functions

new(attrs)

@spec new(map() | keyword()) ::
  {:ok, t()} | {:error, :missing_action | :invalid_action}

Creates a new Instruction struct from a map or keyword list of attributes.

Parameters

  • attrs - Map or keyword list containing instruction attributes:
    • :action - Action module (required)
    • :params - Map of parameters (optional, default: %{})
    • :context - Context map (optional, default: %{})
    • :opts - Keyword list of options (optional, default: [])
    • :id - String identifier (optional, defaults to UUID)

Returns

  • {:ok, %Instruction{}} - Successfully created instruction
  • {:error, :missing_action} - If action is not provided
  • {:error, :invalid_action} - If action is not a module

Examples

iex> Instruction.new(%{action: MyAction, params: %{value: 1}})
{:ok, %Instruction{action: MyAction, params: %{value: 1}}}

iex> Instruction.new(action: MyAction)
{:ok, %Instruction{action: MyAction}}

iex> Instruction.new(%{params: %{value: 1}})
{:error, :missing_action}

new!(attrs)

@spec new!(map() | keyword()) :: t() | no_return()

Creates a new Instruction struct from a map or keyword list of attributes. Returns the struct directly or raises an error.

Parameters

  • attrs - Map or keyword list containing instruction attributes:
    • :action - Action module (required)
    • :params - Map of parameters (optional, default: %{})
    • :context - Context map (optional, default: %{})
    • :opts - Keyword list of options (optional, default: [])

Returns

  • %Instruction{} - Successfully created instruction

Raises

Examples

iex> Instruction.new!(%{action: MyAction, params: %{value: 1}})
%Instruction{action: MyAction, params: %{value: 1}}

iex> Instruction.new!(action: MyAction)
%Instruction{action: MyAction}

iex> Instruction.new!(%{params: %{value: 1}})
** (Jido.Error) missing action

normalize(input, context \\ %{}, opts \\ [])

@spec normalize(instruction() | instruction_list(), map(), keyword()) ::
  {:ok, [t()]} | {:error, term()}
@spec normalize(instruction() | instruction_list(), map(), keyword()) :: [t()]

Normalizes instruction shorthand input into instruction structs. Accepts a variety of input formats and returns a list of normalized instruction structs.

Parameters

  • input - One of:
    • Single instruction struct (%Instruction{})
    • List of instruction structs
    • Single action module (MyApp.Actions.ProcessOrder)
    • Action tuple with params ({MyApp.Actions.ProcessOrder, %{order_id: "123"}})
    • Action tuple with empty params ({MyApp.Actions.ProcessOrder, %{}})
    • Action tuple with context ({MyApp.Actions.ProcessOrder, %{}, %{tenant_id: "123"}})
    • Action tuple with opts ({MyApp.Actions.ProcessOrder, %{}, %{}, [retry: true]})
    • List of any combination of the above formats
  • context - Optional context map to merge into all instructions (default: %{})
  • opts - Optional keyword list of options (default: [])

Returns

  • {:ok, [%Instruction{}]} - List of normalized instruction structs
  • {:error, term()} - If normalization fails

Examples

iex> Instruction.normalize(MyApp.Actions.ProcessOrder)
{:ok, [%Instruction{action: MyApp.Actions.ProcessOrder}]}

iex> Instruction.normalize({MyApp.Actions.ProcessOrder, %{order_id: "123"}})
{:ok, [%Instruction{action: MyApp.Actions.ProcessOrder, params: %{order_id: "123"}}]}

iex> Instruction.normalize([
...>   MyApp.Actions.ValidateOrder,
...>   {MyApp.Actions.ProcessOrder, %{priority: "high"}},
...>   {MyApp.Actions.NotifyUser, %{}, %{user_id: "123"}}
...> ])
{:ok, [%Instruction{...}, %Instruction{...}, %Instruction{...}]}

normalize!(instruction, context \\ nil, opts \\ [])

Same as normalize/3 but raises on error.

Parameters

  • instruction - Instruction to normalize
  • context - Optional context map to merge
  • opts - Optional options to merge

Returns

  • [t()] - List of normalized instructions

Raises

Examples

iex> Instruction.normalize!({MyAction, %{value: 42}})
[%Instruction{action: MyAction, params: %{value: 42}}]

iex> Instruction.normalize!(MyAction)
[%Instruction{action: MyAction, params: %{}}]

validate_allowed_actions(instruction, allowed_actions)

@spec validate_allowed_actions(t() | [t()], [module()]) :: :ok | {:error, term()}

Validates that all instructions use allowed actions.

Parameters

  • instructions - List of instruction structs
  • allowed_actions - List of allowed action modules

Returns

  • :ok - All actions are allowed
  • {:error, term()} - If any action is not allowed

Examples

iex> instructions = [%Instruction{action: MyAction}, %Instruction{action: OtherAction}]
iex> Instruction.validate_allowed_actions(instructions, [MyAction])
{:error, "Actions not allowed: OtherAction"}

iex> instructions = [%Instruction{action: MyAction}]
iex> Instruction.validate_allowed_actions(instructions, [MyAction])
:ok