# AshJido: Ash Resources as Jido Tools

```elixir
Mix.install([
  {:ash, "~> 3.12"},
  {:ash_jido, path: "."},
  {:jido, path: "../jido"}
])
```

## Overview

This livebook demonstrates how **AshJido** bridges Ash Framework resources with Jido agents. The key insight: every Ash action becomes a Jido tool automatically.

You'll learn:

1. How to define an Ash resource with the `AshJido` extension
2. How AshJido generates `Jido.Action` modules from Ash actions
3. How to use those generated actions in a Jido agent via `cmd/2`

## Step 1: Define the Domain and Resource

We'll create a simple `Task` resource with CRUD actions, using ETS for in-memory storage.

```elixir
defmodule Demo.Domain do
  use Ash.Domain, validate_config_inclusion?: false

  resources do
    resource(Demo.Task)
  end
end

defmodule Demo.Task do
  use Ash.Resource,
    domain: Demo.Domain,
    extensions: [AshJido],
    data_layer: Ash.DataLayer.Ets

  ets do
    private?(true)
  end

  attributes do
    uuid_primary_key(:id)
    attribute(:title, :string, allow_nil?: false)
    attribute(:status, :atom, default: :pending)
    timestamps()
  end

  actions do
    defaults([:read, :destroy])

    create :create do
      description("Create a new task")
      argument(:title, :string, allow_nil?: false)
      change(set_attribute(:title, arg(:title)))
    end

    update :complete do
      description("Mark a task as complete")
      change(set_attribute(:status, :complete))
    end
  end

  jido do
    action(:create, name: "create_task", output_map?: true)
    action(:read, name: "list_tasks")
    action(:complete, name: "complete_task", output_map?: true)
    action(:destroy, name: "delete_task")
  end
end
```

## Step 2: Explore the Generated Jido Actions

AshJido automatically generates `Jido.Action` modules at compile time. Let's inspect them:

```elixir
IO.puts("Generated modules:")
IO.puts("  - Demo.Task.Jido.Create")
IO.puts("  - Demo.Task.Jido.Read")
IO.puts("  - Demo.Task.Jido.Complete")
IO.puts("  - Demo.Task.Jido.Destroy")

IO.puts("\nCreate action:")
IO.puts("  name: #{Demo.Task.Jido.Create.name()}")
IO.puts("  schema: #{inspect(Demo.Task.Jido.Create.schema())}")
```

## Step 3: Use Generated Actions Directly

The generated actions work like any `Jido.Action` - call `run/2` with params and context:

```elixir
context = %{domain: Demo.Domain}

{:ok, task1} = Demo.Task.Jido.Create.run(%{title: "Write documentation"}, context)
IO.inspect(task1, label: "Created task")

{:ok, task2} = Demo.Task.Jido.Create.run(%{title: "Review PR"}, context)
IO.inspect(task2, label: "Created another task")

{:ok, tasks} = Demo.Task.Jido.Read.run(%{}, context)
IO.inspect(tasks, label: "All tasks")
```

## Step 4: Update and Delete

```elixir
task_id = task1[:id]

{:ok, completed} = Demo.Task.Jido.Complete.run(%{id: task_id}, context)
IO.inspect(completed[:status], label: "Status after complete")

{:ok, _} = Demo.Task.Jido.Destroy.run(%{id: task_id}, context)

{:ok, remaining} = Demo.Task.Jido.Read.run(%{}, context)
IO.inspect(length(remaining), label: "Remaining tasks")
```

## Step 5: Using Actions in a Jido Agent

Now let's build a Jido agent that uses these Ash-backed tools:

```elixir
defmodule Demo.TaskAgent do
  use Jido.Agent,
    name: "task_agent",
    description: "Manages tasks using Ash-backed storage",
    schema: [
      last_task: [type: :map, default: nil],
      task_count: [type: :integer, default: 0]
    ]
end

defmodule Demo.TaskAgent.CreateTask do
  use Jido.Action,
    name: "agent_create_task",
    description: "Create a task via AshJido",
    schema: [title: [type: :string, required: true]]

  def run(params, context) do
    case Demo.Task.Jido.Create.run(params, %{domain: Demo.Domain}) do
      {:ok, task} ->
        current_count = context.state[:task_count] || 0
        {:ok, %{last_task: task, task_count: current_count + 1}}

      {:error, error} ->
        {:error, error}
    end
  end
end

defmodule Demo.TaskAgent.GetTaskCount do
  use Jido.Action,
    name: "agent_get_count",
    description: "Get task count from Ash",
    schema: []

  def run(_params, _context) do
    case Demo.Task.Jido.Read.run(%{}, %{domain: Demo.Domain}) do
      {:ok, tasks} -> {:ok, %{task_count: length(tasks)}}
      {:error, error} -> {:error, error}
    end
  end
end
```

## Step 6: Drive the Agent with cmd/2

```elixir
alias Demo.TaskAgent
alias Demo.TaskAgent.{CreateTask, GetTaskCount}

agent = TaskAgent.new()
IO.inspect(agent.state, label: "Initial state")

{agent, _} = TaskAgent.cmd(agent, {CreateTask, %{title: "First task from agent"}})
IO.inspect(agent.state, label: "After first create")

{agent, _} = TaskAgent.cmd(agent, {CreateTask, %{title: "Second task from agent"}})
IO.inspect(agent.state, label: "After second create")

{agent, _} = TaskAgent.cmd(agent, GetTaskCount)
IO.inspect(agent.state, label: "After count refresh")
```

## How It Works

```
┌─────────────────────────────────────────────────────────────┐
│                      Jido Agent                              │
│  TaskAgent.cmd(agent, {CreateTask, %{title: "..."}})        │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                    Agent Action                              │
│  CreateTask.run(params, context)                            │
│  - Calls AshJido-generated action                           │
│  - Transforms result to agent state                         │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                 AshJido Generated                            │
│  Demo.Task.Jido.Create.run(params, %{domain: Domain})       │
│  - Type-safe schema from Ash action                         │
│  - Automatic error mapping                                  │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                      Ash Framework                           │
│  Ash.Changeset.for_create → Ash.create!                     │
│  - Validation, policies, data layer                         │
└─────────────────────────────────────────────────────────────┘
```

The key value: **you never write the bridge code**. AshJido generates type-safe `Jido.Action` modules from your Ash resource definitions automatically.

## Next Steps

- Add more Ash actions (filters, complex validations)
- Use `all_actions` DSL to expose everything at once
- Run agents under `AgentServer` for signal-based workflows
- Add actors/tenants for authorization
