Built-in Tools Reference

View Source

Prerequisites: Getting Started

Jido Action includes 25+ pre-built tools for common operations. All tools follow the same action patterns and can be used individually or composed into workflows.

Basic Tools

Sleep

Pause execution for a specified duration.

# Sleep for 1 second
{:ok, result} = Jido.Tools.Basic.Sleep.run(%{duration_ms: 1000}, %{})
# => {:ok, %{duration_ms: 1000}}

# Use in workflows for delays
plan = Jido.Plan.new()
|> Jido.Plan.add("process", MyApp.Actions.ProcessData, %{}, [])
|> Jido.Plan.add("wait", Jido.Tools.Basic.Sleep, %{duration_ms: 5000}, ["process"])
|> Jido.Plan.add("notify", MyApp.Actions.SendNotification, %{}, ["wait"])

Parameters:

  • duration_ms (non-negative integer, default: 1000): Milliseconds to sleep

Log

Log a message with a specified level.

{:ok, result} = Jido.Tools.Basic.Log.run(%{level: :info, message: "Hello"}, %{})
# => {:ok, %{level: :info, message: "Hello"}}

Parameters:

  • level (atom, default: :info): Log level (:debug, :info, :warning, :error)
  • message (string, required): Message to log

Todo

Log a todo item as a placeholder.

{:ok, result} = Jido.Tools.Basic.Todo.run(%{todo: "Implement this feature"}, %{})
# => {:ok, %{todo: "Implement this feature"}}

Parameters:

  • todo (string, required): Todo item description

RandomSleep

Introduce a random delay within a specified range.

{:ok, result} = Jido.Tools.Basic.RandomSleep.run(%{min_ms: 100, max_ms: 500}, %{})
# => {:ok, %{min_ms: 100, max_ms: 500, actual_delay: 342}}

Parameters:

  • min_ms (non-negative integer, required): Minimum sleep duration in milliseconds
  • max_ms (non-negative integer, required): Maximum sleep duration in milliseconds

Increment

Increment a value by 1.

{:ok, result} = Jido.Tools.Basic.Increment.run(%{value: 5}, %{})
# => {:ok, %{value: 6}}

Parameters:

  • value (integer, required): Value to increment

Decrement

Decrement a value by 1.

{:ok, result} = Jido.Tools.Basic.Decrement.run(%{value: 5}, %{})
# => {:ok, %{value: 4}}

Parameters:

  • value (integer, required): Value to decrement

Noop

No operation, returns input unchanged.

{:ok, result} = Jido.Tools.Basic.Noop.run(%{foo: "bar"}, %{})
# => {:ok, %{foo: "bar"}}

Inspect

Inspect a value using IO.inspect.

{:ok, result} = Jido.Tools.Basic.Inspect.run(%{value: [1, 2, 3]}, %{})
# => {:ok, %{value: [1, 2, 3]}}

Parameters:

  • value (any, required): Value to inspect

Today

Returns today's date in the specified format.

{:ok, result} = Jido.Tools.Basic.Today.run(%{format: :iso8601}, %{})
# => {:ok, %{format: :iso8601, date: "2024-01-15"}}

{:ok, result} = Jido.Tools.Basic.Today.run(%{format: :human}, %{})
# => {:ok, %{format: :human, date: "January 15, 2024"}}

Parameters:

  • format (atom, default: :iso8601): Format for the date (:iso8601, :basic, or :human)

Arithmetic Tools

Add

Add a value to a number.

{:ok, result} = Jido.Tools.Arithmetic.Add.run(%{value: 10, amount: 5}, %{})
# => {:ok, %{result: 15}}

Parameters:

  • value (number, required): Base value
  • amount (number, required): Amount to add

Subtract

Subtract a value from a number.

{:ok, result} = Jido.Tools.Arithmetic.Subtract.run(%{value: 10, amount: 3}, %{})
# => {:ok, %{result: 7}}

Multiply

Multiply two numbers.

{:ok, result} = Jido.Tools.Arithmetic.Multiply.run(%{value: 6, amount: 4}, %{})
# => {:ok, %{result: 24}}

Parameters:

  • value (integer, required): The first number to multiply
  • amount (integer, required): The second number to multiply

Divide

Divide one number by another.

{:ok, result} = Jido.Tools.Arithmetic.Divide.run(%{value: 20, amount: 4}, %{})
# => {:ok, %{result: 5.0}}

# Division by zero returns error
{:error, error} = Jido.Tools.Arithmetic.Divide.run(%{value: 10, amount: 0}, %{})
# => {:error, "Cannot divide by zero"}

Parameters:

  • value (integer, required): The number to be divided (dividend)
  • amount (integer, required): The number to divide by (divisor)

Square

Square a number.

{:ok, result} = Jido.Tools.Arithmetic.Square.run(%{value: 5.0}, %{})
# => {:ok, %{result: 25.0}}

Parameters:

  • value (float, required): The number to be squared

File Operations

Read File

Read contents from a file.

{:ok, result} = Jido.Tools.Files.ReadFile.run(%{path: "/tmp/data.txt"}, %{})
# => {:ok, %{path: "/tmp/data.txt", content: "file contents"}}

# Handle missing files
{:error, error} = Jido.Tools.Files.ReadFile.run(%{path: "/nonexistent.txt"}, %{})
# => {:error, "Failed to read file: :enoent"}

Parameters:

  • path (string, required): Path to the file to be read

Write File

Write content to a file.

{:ok, result} = Jido.Tools.Files.WriteFile.run(%{
  path: "/tmp/output.txt",
  content: "Hello, World!",
  create_dirs: true,
  mode: :write
}, %{})
# => {:ok, %{path: "/tmp/output.txt", bytes_written: 13}}

Parameters:

  • path (string, required): Path to the file to be written
  • content (string, required): Content to be written to the file
  • create_dirs (boolean, default: false): Create parent directories if they don't exist
  • mode (atom, default: :write): Write mode - :write overwrites, :append adds to end

Delete File

Delete a file or directory.

{:ok, result} = Jido.Tools.Files.DeleteFile.run(%{path: "/tmp/temp.txt", recursive: false, force: false}, %{})
# => {:ok, %{path: "/tmp/temp.txt"}}

# Recursive deletion
{:ok, result} = Jido.Tools.Files.DeleteFile.run(%{path: "/tmp/mydir", recursive: true}, %{})
# => {:ok, %{deleted: ["/tmp/mydir/file.txt", "/tmp/mydir"]}}

Parameters:

  • path (string, required): Path to delete
  • recursive (boolean, default: false): Recursively delete directories and contents
  • force (boolean, default: false): Force deletion even if file is read-only

Copy File

Copy a file from source to destination.

{:ok, result} = Jido.Tools.Files.CopyFile.run(%{source: "/tmp/a.txt", destination: "/tmp/b.txt"}, %{})
# => {:ok, %{source: "/tmp/a.txt", destination: "/tmp/b.txt", bytes_copied: 1234}}

Parameters:

  • source (string, required): Path to the source file
  • destination (string, required): Path to the destination file

Move File

Move/rename a file from source to destination.

{:ok, result} = Jido.Tools.Files.MoveFile.run(%{source: "/tmp/a.txt", destination: "/tmp/b.txt"}, %{})
# => {:ok, %{source: "/tmp/a.txt", destination: "/tmp/b.txt"}}

Parameters:

  • source (string, required): Path to the source file
  • destination (string, required): Path to the destination file

Make Directory

Create a new directory.

{:ok, result} = Jido.Tools.Files.MakeDirectory.run(%{path: "/tmp/newdir", recursive: true}, %{})
# => {:ok, %{path: "/tmp/newdir"}}

Parameters:

  • path (string, required): Path to the directory to create
  • recursive (boolean, default: false): Create parent directories if they don't exist

List Directory

List directory contents.

{:ok, result} = Jido.Tools.Files.ListDirectory.run(%{
  path: "/tmp",
  recursive: false
}, %{})
# => {:ok, %{entries: ["file1.txt", "file2.txt"]}}

# With pattern matching
{:ok, result} = Jido.Tools.Files.ListDirectory.run(%{
  path: "/tmp",
  pattern: "*.txt",
  recursive: true
}, %{})
# => {:ok, %{entries: ["/tmp/file1.txt", "/tmp/subdir/file2.txt"]}}

Parameters:

  • path (string, required): Path to the directory to list
  • pattern (string, optional): Glob pattern for filtering files
  • recursive (boolean, default: false): Include subdirectories recursively

HTTP Tools

ReqTool (HTTP Request Builder)

A behavior and macro for creating HTTP request actions using the Req library.

# Define a custom HTTP action module
defmodule MyApp.GetUser do
  use Jido.Tools.ReqTool,
    name: "get_user",
    description: "Fetch a user from the API",
    url: "https://api.example.com/users",
    method: :get,
    headers: %{"Authorization" => "Bearer token123"}
end

# Use the generated action
{:ok, response} = MyApp.GetUser.run(%{id: "123"}, %{})
# => {:ok, %{
#   request: %{url: "https://api.example.com/users", method: :get, params: %{id: "123"}},
#   response: %{status: 200, body: %{"id" => "123", "name" => "John"}, headers: [...]}
# }}

# POST with body
defmodule MyApp.CreateUser do
  use Jido.Tools.ReqTool,
    name: "create_user",
    description: "Create a new user",
    url: "https://api.example.com/users",
    method: :post,
    headers: %{"Content-Type" => "application/json"}
end

{:ok, response} = MyApp.CreateUser.run(%{name: "Jane", email: "jane@example.com"}, %{})

Configuration Options (in use statement):

  • url (string, required): The URL to make requests to
  • method (atom, required): HTTP method (:get, :post, :put, :delete)
  • headers (map, default: %{}): HTTP headers to include
  • json (boolean, default: true): Whether to parse the response as JSON

Optional Callback:

  • transform_result/1: Override to transform the HTTP response result

GitHub Tools

These tools use the Tentacat library to interact with the GitHub API. Requires a Tentacat client.

List Issues

List all issues from a GitHub repository.

client = Tentacat.Client.new(%{access_token: token})
{:ok, result} = Jido.Tools.Github.Issues.List.run(%{
  client: client,
  owner: "octocat",
  repo: "Hello-World"
}, %{})
# => {:ok, %{status: "success", data: [...], raw: [...]}}

Parameters:

  • client (any): The Tentacat client
  • owner (string): Repository owner
  • repo (string): Repository name

Create Issue

Create a new GitHub issue.

client = Tentacat.Client.new(%{access_token: token})
{:ok, result} = Jido.Tools.Github.Issues.Create.run(%{
  client: client,
  owner: "octocat",
  repo: "Hello-World",
  title: "Bug Report",
  body: "Description of the bug...",
  labels: ["bug", "priority-high"],
  assignee: "username",
  milestone: "v1.0"
}, %{})
# => {:ok, %{status: "success", data: {...}, raw: {...}}}

Parameters:

  • client (any): The Tentacat client
  • owner (string): Repository owner
  • repo (string): Repository name
  • title (string): Issue title
  • body (string): Issue body
  • assignee (string): Issue assignee
  • milestone (string): Issue milestone
  • labels (array): Issue labels

Update Issue

Update an existing GitHub issue.

client = Tentacat.Client.new(%{access_token: token})
{:ok, result} = Jido.Tools.Github.Issues.Update.run(%{
  client: client,
  owner: "octocat",
  repo: "Hello-World",
  number: 123,
  state: "closed",
  labels: ["bug", "resolved"]
}, %{})
# => {:ok, %{status: "success", data: {...}, raw: {...}}}

Parameters:

  • client (any): The Tentacat client
  • owner (string): Repository owner
  • repo (string): Repository name
  • number (integer): Issue number
  • title (string): New title
  • body (string): New body
  • assignee (string): New assignee
  • state (string): New state (open, closed)
  • milestone (string): New milestone
  • labels (array): New labels

Find Issue

Find a specific issue by number.

client = Tentacat.Client.new(%{access_token: token})
{:ok, result} = Jido.Tools.Github.Issues.Find.run(%{
  client: client,
  owner: "octocat",
  repo: "Hello-World",
  number: 123
}, %{})
# => {:ok, %{status: "success", data: {...}, raw: {...}}}

Parameters:

  • client (any): The Tentacat client
  • owner (string): Repository owner
  • repo (string): Repository name
  • number (integer): Issue number

Filter Issues

Filter repository issues by various criteria.

client = Tentacat.Client.new(%{access_token: token})
{:ok, result} = Jido.Tools.Github.Issues.Filter.run(%{
  client: client,
  owner: "octocat",
  repo: "Hello-World",
  state: "open",
  assignee: "username",
  labels: "bug,enhancement",
  sort: "created",
  direction: "desc"
}, %{})
# => {:ok, %{status: "success", data: [...], raw: [...]}}

Parameters:

  • client (any): The Tentacat client
  • owner (string): Repository owner
  • repo (string): Repository name
  • state (string): Issue state (open, closed, all)
  • assignee (string): Filter by assignee
  • creator (string): Filter by creator
  • labels (string): Filter by labels (comma-separated)
  • sort (string): Sort by (created, updated, comments)
  • direction (string): Sort direction (asc, desc)
  • since (string): Only show issues updated after this time

Weather Tools

Get Weather

Fetch weather forecast using the National Weather Service API (no API key required).

# Default format (text) - returns forecast string
{:ok, forecast} = Jido.Tools.Weather.run(%{
  location: "41.8781,-87.6298",  # Chicago coordinates
  periods: 5,
  format: :text
}, %{})
# => {:ok, "Tonight: Mostly Clear, Low: 45°F..."}

# Map format - returns structured data
{:ok, weather} = Jido.Tools.Weather.run(%{
  location: "34.0522,-118.2437",  # Los Angeles
  format: :map
}, %{})
# => {:ok, %{periods: [%{name: "Tonight", temperature: 65, ...}, ...]}}

# Detailed format - includes all NWS data
{:ok, weather} = Jido.Tools.Weather.run(%{
  location: "40.7128,-74.0060",  # New York
  format: :detailed,
  periods: 3
}, %{})

Parameters:

  • location (string, default: "41.8781,-87.6298"): Location as coordinates (lat,lng)
  • periods (integer, default: 5): Number of forecast periods to return
  • format (atom, default: :text): Output format (:text, :map, or :detailed)

Workflow Tools

ActionPlan

A behavior and macro for creating actions that execute Jido Plans (DAG-based workflows).

# Define a workflow action
defmodule MyApp.MyWorkflowAction do
  use Jido.Tools.ActionPlan,
    name: "my_workflow",
    description: "Executes a multi-step workflow"

  @impl Jido.Tools.ActionPlan
  def build(params, context) do
    Jido.Plan.new(context: context)
    |> Jido.Plan.add(:fetch, MyApp.FetchAction, params)
    |> Jido.Plan.add(:validate, MyApp.ValidateAction, depends_on: :fetch)
    |> Jido.Plan.add(:save, MyApp.SaveAction, depends_on: :validate)
  end

  # Optional: transform the result
  @impl Jido.Tools.ActionPlan
  def transform_result(result) do
    {:ok, %{workflow_result: result}}
  end
end

# Execute the workflow action
{:ok, results} = MyApp.MyWorkflowAction.run(%{input: "data"}, %{user_id: "123"})
# => {:ok, %{workflow_result: %{fetch: %{...}, validate: %{...}, save: %{...}}}}

Required Callback:

  • build/2: Build a Plan struct from params and context

Optional Callback:

  • transform_result/1: Transform the execution result

Workflow

A behavior and macro for creating actions that execute sequential workflow steps.

defmodule MyApp.MySequentialWorkflow do
  use Jido.Tools.Workflow,
    name: "my_sequential_workflow",
    description: "A workflow that performs multiple steps",
    workflow: [
      {:step, [name: "step_1"], [{LogAction, message: "Step 1"}]},
      {:branch, [name: "branch_1"], [
        true,  # Condition (can override execute_step/3 for dynamic)
        {:step, [name: "true_branch"], [{LogAction, message: "Condition true"}]},
        {:step, [name: "false_branch"], [{LogAction, message: "Condition false"}]}
      ]},
      {:step, [name: "final_step"], [{LogAction, message: "Completed"}]}
    ]
end

{:ok, result} = MyApp.MySequentialWorkflow.run(%{input: "start"}, %{})

Supported Step Types:

  • :step - Execute a single instruction
  • :branch - Conditional branching based on a boolean value
  • :converge - Converge branch paths
  • :parallel - Execute instructions in parallel

Advanced Tools

Simplebot

A collection of simple robot simulation actions for testing and examples.

Available actions:

  • Move - Move to a destination
  • Idle - Idle/wait
  • DoWork - Perform work (decreases battery)
  • Report - Report status
  • Recharge - Recharge battery to 100%
{:ok, result} = Jido.Tools.Simplebot.Move.run(%{destination: :warehouse}, %{})
# => {:ok, %{destination: :warehouse, location: :warehouse}}

{:ok, result} = Jido.Tools.Simplebot.DoWork.run(%{battery_level: 80}, %{})
# => {:ok, %{battery_level: 60}}  # Battery decreased by 15-25

{:ok, result} = Jido.Tools.Simplebot.Recharge.run(%{battery_level: 20}, %{})
# => {:ok, %{battery_level: 100}}

LuaEval

Execute Lua code in a sandboxed VM.

# Simple arithmetic
{:ok, result} = Jido.Tools.LuaEval.run(%{code: "return 2 + 2"}, %{})
# => {:ok, %{results: [4]}}

# With global variables
{:ok, result} = Jido.Tools.LuaEval.run(%{
  code: "return x + 5",
  globals: %{"x" => 10}
}, %{})
# => {:ok, %{results: [15]}}

# Return first value only
{:ok, result} = Jido.Tools.LuaEval.run(%{
  code: "return 1, 2, 3",
  return_mode: :first
}, %{})
# => {:ok, %{result: 1}}

Parameters:

  • code (string, required): Lua code to execute
  • globals (map, default: %{}): Global variables to inject
  • return_mode (atom, default: :list): :list returns all values, :first returns only first
  • enable_unsafe_libs (boolean, default: false): Enable unsafe libs (os/io/package)
  • timeout_ms (integer, default: 1000): Execution timeout in milliseconds
  • max_heap_bytes (integer, default: 0): Per-process heap limit (0 = disabled)

ZoiExample

A production-quality example demonstrating Zoi schema features. Use this as a reference for building actions with complex validation.

# Example with nested objects, transformations, and refinements
params = %{
  user: %{
    email: "  JOHN@EXAMPLE.COM  ",  # Will be trimmed and lowercased
    password: "SecurePass123!",
    name: "John Doe"
  },
  priority: :high
}

{:ok, result} = Jido.Exec.run(Jido.Tools.ZoiExample, params)
result.user.email  # => "john@example.com"
result.status      # => :approved

See the Schemas & Validation Guide for more on Zoi schemas.

Tool Composition

Chaining Tools

# Chain multiple tools together
{:ok, final_result} = Jido.Exec.Chain.chain([
  # Read data from file
  {Jido.Tools.Files.ReadFile, %{path: "/tmp/input.txt"}},
  
  # Process with custom action
  {MyApp.Actions.ProcessText, %{}},
  
  # Write result to new file
  {Jido.Tools.Files.WriteFile, %{
    path: "/tmp/output.txt", 
    create_dirs: true
  }}
], %{}, %{user_id: "123"})

Parallel Tool Execution

# Create a workflow action for parallel execution
defmodule MyApp.WeatherComparison do
  use Jido.Tools.ActionPlan,
    name: "weather_comparison",
    description: "Compare weather across cities"

  @impl Jido.Tools.ActionPlan
  def build(_params, _context) do
    Jido.Plan.new()
    |> Jido.Plan.add(:weather_sf, Jido.Tools.Weather, %{location: "41.8781,-87.6298"})
    |> Jido.Plan.add(:weather_ny, Jido.Tools.Weather, %{location: "40.7128,-74.0060"})
    |> Jido.Plan.add(:weather_la, Jido.Tools.Weather, %{location: "34.0522,-118.2437"})
    |> Jido.Plan.add(:compare, MyApp.Actions.CompareWeather, 
        depends_on: [:weather_sf, :weather_ny, :weather_la])
  end
end

{:ok, results} = MyApp.WeatherComparison.run(%{}, %{})

Conditional Tool Usage

defmodule MyApp.Actions.ConditionalFileOp do
  use Jido.Action,
    name: "conditional_file_op",
    description: "Read or delete a file based on operation",
    schema: [
      file_path: [type: :string, required: true],
      operation: [type: {:in, [:read, :delete]}, required: true]
    ]

  def run(params, context) do
    case params.operation do
      :read ->
        Jido.Tools.Files.ReadFile.run(%{path: params.file_path}, context)
      
      :delete ->
        Jido.Tools.Files.DeleteFile.run(%{path: params.file_path, recursive: false, force: false}, context)
    end
  end
end

Error Handling with Tools

All built-in tools follow consistent error handling patterns:

case Jido.Tools.Files.ReadFile.run(%{path: "/nonexistent.txt"}, %{}) do
  {:ok, result} -> 
    handle_success(result)
  
  {:error, %{type: :execution_error} = error} ->
    Logger.error("File operation failed: #{error.message}")
    handle_file_error(error)
  
  {:error, error} ->
    handle_other_error(error)
end

AI Integration

All tools automatically work with AI systems:

# Get tool definitions for AI
tools = [
  Jido.Tools.Weather.to_tool(),
  Jido.Tools.Files.ReadFile.to_tool(),
  Jido.Tools.Arithmetic.Add.to_tool()
]

# Tools are now available to AI for function calling
# The AI can invoke: weather, read_file, add

Best Practices

Tool Selection

  • Right Tool for Job: Choose the most specific tool available
  • Composition: Combine tools for complex operations
  • Error Handling: Always handle tool errors gracefully
  • Context Propagation: Pass context through tool chains

Performance

  • Parallel Execution: Use plans for independent operations
  • Resource Management: Be mindful of file handles and network connections
  • Caching: Cache expensive operations when appropriate
  • Timeouts: Set appropriate timeouts for external tools

Security

  • Path Validation: Validate file paths in file operations
  • Input Sanitization: Sanitize inputs to external services
  • Credential Management: Handle API keys and tokens securely
  • Access Control: Restrict tool usage based on user permissions

Next Steps

AI Integration - Using tools with AI systems
Instructions & Plans - Composing tools into workflows
Actions Guide - Creating your own tools


Security Guide | Next: AI Integration