Jido.Action

View Source

Hex.pm Hex Docs CI License Coverage Status

Composable, validated actions for Elixir applications with built-in AI tool integration

Jido.Action is part of the Jido project. Learn more about Jido at agentjido.xyz.

Overview

Jido.Action is a framework for building composable, validated actions in Elixir. It provides a standardized way to define discrete units of functionality that can be composed into complex workflows, validated at compile and runtime using NimbleOptions schemas, and seamlessly integrated with AI systems through automatic tool generation.

Whether you're building microservices that need structured operations, implementing agent-based systems, or creating AI-powered applications that require reliable function calling, Jido.Action provides the foundation for robust, traceable, and scalable action-driven architecture.

Why Do I Need Actions?

Structured Operations in Elixir's Dynamic World

Elixir excels at building fault-tolerant, concurrent systems, but as applications grow, you often need:

  • Standardized Operation Format: Raw function calls lack structure, validation, and metadata
  • AI Tool Integration: Converting functions to LLM-compatible tool definitions manually
  • Workflow Composition: Building complex multi-step processes from smaller units
  • Parameter Validation: Ensuring inputs are correct before expensive operations
  • Error Handling: Consistent error reporting across different operation types
  • Runtime Introspection: Understanding what operations are available and how they work
# Traditional Elixir functions
def process_order(order_id, user_id, options) do
  # No validation, no metadata, no AI integration
  # Error handling is inconsistent
end

# With Jido.Action
defmodule ProcessOrder do
  use Jido.Action,
    name: "process_order",
    description: "Processes a customer order with validation and tracking",
    schema: [
      order_id: [type: :string, required: true],
      user_id: [type: :string, required: true],
      priority: [type: {:in, [:low, :normal, :high]}, default: :normal]
    ]

  def run(params, context) do
    # Params are pre-validated, action is AI-ready, errors are structured
    {:ok, %{status: "processed", order_id: params.order_id}}
  end
end

# Use directly or convert to AI tool
ProcessOrder.to_tool()  # Ready for LLM integration

Jido.Action transforms ad-hoc functions into structured, validated, AI-compatible operations that scale from simple tasks to complex agent workflows.

Key Features

Structured Action Definition

  • Compile-time configuration validation
  • Runtime parameter validation with NimbleOptions or Zoi schemas
  • Rich metadata including descriptions, categories, and tags
  • Automatic JSON serialization support

AI Tool Integration

  • Automatic conversion to LLM-compatible tool format
  • OpenAI function calling compatible
  • Parameter schemas with validation and documentation
  • Seamless integration with AI agent frameworks

Robust Execution Engine

  • Synchronous and asynchronous execution via Jido.Exec
  • Automatic retries with exponential backoff
  • Timeout handling and cancellation
  • Comprehensive error handling and compensation

Workflow Composition

  • Instruction-based workflow definition via Jido.Instruction
  • Parameter normalization and context sharing
  • Action chaining and conditional execution
  • Built-in workflow primitives

Comprehensive Tool Library

  • 25+ pre-built actions for common operations
  • File system operations, HTTP requests, arithmetic
  • Weather APIs, GitHub integration, workflow primitives
  • Robot simulation tools for testing and examples

Installation

Add jido_action to your list of dependencies in mix.exs:

def deps do
  [
    {:jido_action, "~> 1.0"}
  ]
end

Then run:

mix deps.get

Quick Start

1. Define Your First Action

defmodule MyApp.Actions.GreetUser do
  use Jido.Action,
    name: "greet_user",
    description: "Greets a user with a personalized message",
    category: "communication",
    tags: ["greeting", "user"],
    vsn: "1.0.0",
    schema: [
      name: [type: :string, required: true, doc: "User's name"],
      language: [type: {:in, ["en", "es", "fr"]}, default: "en", doc: "Greeting language"]
    ]

  @impl true
  def run(params, _context) do
    greeting = case params.language do
      "en" -> "Hello"
      "es" -> "Hola" 
      "fr" -> "Bonjour"
    end
    
    {:ok, %{message: "#{greeting}, #{params.name}!"}}
  end
end

2. Execute Actions with Jido.Exec

# Synchronous execution
{:ok, result} = Jido.Exec.run(MyApp.Actions.GreetUser, %{name: "Alice"})
# => {:ok, %{message: "Hello, Alice!"}}

# With validation error handling
{:error, reason} = Jido.Exec.run(MyApp.Actions.GreetUser, %{invalid: "params"})
# => {:error, %Jido.Action.Error{type: :validation_error, ...}}

# Asynchronous execution
async_ref = Jido.Exec.run_async(MyApp.Actions.GreetUser, %{name: "Bob"})
{:ok, result} = Jido.Exec.await(async_ref)

3. Create Workflows with Jido.Instruction

# Define a sequence of actions
instructions = [
  MyApp.Actions.ValidateUser,
  {MyApp.Actions.GreetUser, %{name: "Alice", language: "es"}},
  MyApp.Actions.LogActivity
]

# Normalize with shared context
{:ok, workflow} = Jido.Instruction.normalize(instructions, %{
  request_id: "req_123",
  tenant_id: "tenant_456"
})

# Execute the workflow
Enum.each(workflow, fn instruction ->
  Jido.Exec.run(instruction.action, instruction.params, instruction.context)
end)

4. AI Tool Integration

# Convert action to AI tool format
tool_definition = MyApp.Actions.GreetUser.to_tool()

# Returns LangChain-compatible tool definition:
%{
  name: "greet_user",
  description: "Greets a user with a personalized message",
  function: #Function<...>,  # Executes the action
  parameters_schema: %{
    "type" => "object",
    "properties" => %{
      "name" => %{"type" => "string", "description" => "User's name"},
      "language" => %{
        "type" => "string", 
        "enum" => ["en", "es", "fr"],
        "description" => "Greeting language"
      }
    },
    "required" => ["name"]
  }
}

# Use with AI frameworks - the function can be called directly
# or convert to OpenAI format for function calling

Core Components

Jido.Action

The foundational behavior for defining structured, validated actions. Provides:

  • Compile-time configuration validation
  • Parameter and output schemas with validation
  • Lifecycle hooks for customization
  • Automatic AI tool format generation
  • JSON serialization support

Jido.Exec

The execution engine for running actions reliably. Features:

  • Synchronous and asynchronous execution
  • Automatic retries with exponential backoff
  • Timeout handling and process monitoring
  • Comprehensive error handling
  • Telemetry integration for monitoring

Jido.Instruction

The workflow composition system for building complex operations. Enables:

  • Multiple input formats (modules, tuples, structs)
  • Parameter normalization and validation
  • Context sharing across actions
  • Action allowlist validation
  • Flexible workflow definition patterns

Jido.Plan

DAG-based execution planning for complex workflows. Features:

  • Directed acyclic graph of action dependencies
  • Parallel execution phases based on dependency analysis
  • Builder pattern for constructing plans
  • Cycle detection and validation
  • Keyword list and programmatic plan construction

Bundled Tools

Jido.Action comes with a comprehensive library of pre-built tools organized by category:

Core Utilities (Jido.Tools.Basic)

ToolDescriptionUse Case
SleepPauses execution for specified durationDelays, rate limiting
LogLogs messages with configurable levelsDebugging, monitoring
TodoLogs TODO items as placeholdersDevelopment workflow
RandomSleepRandom delay within specified rangeChaos testing, natural delays
Increment/DecrementNumeric operationsCounters, calculations
NoopNo operation, returns input unchangedPlaceholder actions
TodayReturns current date in specified formatDate operations

Arithmetic Operations (Jido.Tools.Arithmetic)

ToolDescriptionUse Case
AddAdds two numbersMathematical operations
SubtractSubtracts one number from anotherCalculations
MultiplyMultiplies two numbersMath workflows
DivideDivides with zero-division handlingSafe arithmetic
SquareSquares a numberMathematical functions

File System Operations (Jido.Tools.Files)

ToolDescriptionUse Case
WriteFileWrite content to files with optionsFile creation, logging
ReadFileRead file contentsData processing
CopyFileCopy files between locationsBackup, deployment
MoveFileMove/rename filesFile organization
DeleteFileDelete files/directories (recursive)Cleanup operations
MakeDirectoryCreate directories (recursive)Setup operations
ListDirectoryList directory contents with filteringFile discovery

HTTP Operations (Jido.Tools.ReqTool)

ReqTool is a specialized action that provides a behavior and macro for creating HTTP request actions using the Req library. It offers a standardized way to build HTTP-based actions with configurable URLs, methods, headers, and response processing.

ToolDescriptionUse Case
HTTP ActionsGET, POST, PUT, DELETE requests with Req libraryAPI integration, webhooks
JSON SupportAutomatic JSON parsing and response handlingREST API clients
Custom HeadersConfigurable HTTP headers per actionAuthentication, API keys
Response TransformCustom response transformation via callbacksData mapping, filtering
Action GenerationMacro-based HTTP action creationRapid API client development

External API Integration

ToolDescriptionUse Case
WeatherNational Weather Service API integrationWeather data, forecasts
Github.IssuesGitHub Issues API (create, list, filter)Issue management

Workflow & Simulation

ToolDescriptionUse Case
WorkflowMulti-step workflow executionComplex processes
SimplebotRobot simulation actionsTesting, examples

Specialized Tools

ToolDescriptionUse Case
Branch/ParallelConditional and parallel executionComplex workflows
Error HandlingCompensation and retry mechanismsFault tolerance

Advanced Features

Error Handling and Compensation

Actions support sophisticated error handling with optional compensation:

defmodule RobustAction do
  use Jido.Action,
    name: "robust_action",
    compensation: [
      enabled: true,
      max_retries: 3,
      timeout: 5000
    ]

  def run(params, context) do
    # Main action logic
    {:ok, result}
  end

  # Called when errors occur if compensation is enabled
  def on_error(failed_params, error, context, opts) do
    # Perform rollback/cleanup operations
    {:ok, %{compensated: true, original_error: error}}
  end
end

Lifecycle Hooks

Customize action behavior with lifecycle hooks:

defmodule CustomAction do
  use Jido.Action, name: "custom_action"

  def on_before_validate_params(params) do
    # Transform params before validation
    {:ok, transformed_params}
  end

  def on_after_validate_params(params) do
    # Enrich params after validation
    {:ok, enriched_params}
  end

  def on_after_run({:ok, result}) do
    # Post-process successful results
    {:ok, enhanced_result}
  end
  
  def on_after_run({:error, _} = error), do: error
end

Telemetry Integration

Actions emit telemetry events for monitoring:

# Attach telemetry handlers
:telemetry.attach("action-handler", [:jido, :action, :stop], fn event, measurements, metadata, config ->
  # Handle action completion events
  Logger.info("Action completed: #{metadata.action}")
end, %{})

Testing

Test actions directly or within the execution framework:

defmodule MyActionTest do
  use ExUnit.Case

  test "action validates parameters" do
    assert {:error, _} = MyAction.validate_params(%{invalid: "params"})
    assert {:ok, _} = MyAction.validate_params(%{valid: "params"})
  end

  test "action execution" do
    assert {:ok, result} = Jido.Exec.run(MyAction, %{valid: "params"})
    assert result.status == "success"
  end

  test "async action execution" do
    async_ref = Jido.Exec.run_async(MyAction, %{valid: "params"})
    assert {:ok, result} = Jido.Exec.await(async_ref, 5000)
  end
end

Configuration

Configure defaults in your application:

# config/config.exs
config :jido_action,
  default_timeout: 10_000,
  default_max_retries: 3,
  default_backoff: 500

Contributing

We welcome contributions! Please see our GitHub repository for details.

License

Copyright 2024-2025 Mike Hostetler

Licensed under the Apache License, Version 2.0. See LICENSE for details.

For information about dependency licenses, see the LICENSE file.