Packages

A LiveView-native library for building agentic systems in Elixir, built on ReqLLM.

Current section

Files

Jump to
agentix guides installation.md
Raw

guides/installation.md

# Installation

Agentix requires **Elixir 1.20+**. It installs in three tiers: a host adds **only the
dependencies its use case needs** — the LiveView and durable-persistence layers are
`optional: true` *and* compile-gated, so an unused layer is neither fetched nor compiled. Two
runnable example apps in this repo prove each end of the range:

- [`examples/agentix_api`](https://github.com/hawkyre/agentix/tree/main/examples/agentix_api)
  — Tier 1, headless, no LiveView and no database.
- [`examples/agentix_demo`](https://github.com/hawkyre/agentix/tree/main/examples/agentix_demo)
  — Tier 3, LiveView + Postgres + Oban.

## Tier 1 — Headless / API-only (no LiveView, no database)

The core runtime needs no web framework and no database. The Agentix OTP application boots its
own registry, task supervisor, ETS persistence, and `Phoenix.PubSub` (the live-event backbone).

```elixir
# mix.exs
{:agentix, "~> 0.1"}      # pulls req_llm + phoenix_pubsub (both light)
```

No configuration is required to start — ETS persistence and an `Agentix.PubSub` server start
automatically. Override only what differs from the defaults (see the config table below),
e.g. to reuse a `Phoenix.PubSub` your app already supervises:

```elixir
# config/config.exs
config :agentix, pubsub: MyApp.PubSub
```

### Configure a model provider

Agentix talks to LLMs through [ReqLLM](https://hexdocs.pm/req_llm). Choose a model with a
`"<provider>:<model>"` string (per conversation, via `Agentix.Conversation.Config`), and give
ReqLLM the provider credential — an `ANTHROPIC_API_KEY`-style env var (`.env` is loaded via
dotenvy), inline config, or `ReqLLM.put_key/2`:

```elixir
# config/runtime.exs  — or just export ANTHROPIC_API_KEY
config :req_llm, anthropic_api_key: System.get_env("ANTHROPIC_API_KEY")

# starting a conversation with that provider:
Agentix.Conversation.ensure_started("conv-1",
  config: Agentix.Conversation.Config.new(model: "anthropic:claude-haiku-4-5"))
```

Drive conversations through `Agentix.Conversation.*` and `Agentix.resolve/4`, and stream
output to clients off the **live-event union** over any transport you write (SSE, channel,
JSON polling) by subscribing to `Agentix.Events.Publisher.topic(conversation_id)`.

In this tier `Agentix.Chat`, the Ecto adapter, and the Oban worker are **never compiled** —
`Code.ensure_loaded?(Agentix.Chat) == false`. See `examples/agentix_api` for a working
headless conversation (streaming + a `:server` tool) on ETS.

## Tier 2 — + LiveView

Add `phoenix_live_view` (most Phoenix apps already have it) to light up the rendering layer:

```elixir
{:phoenix_live_view, "~> 1.2"}
```

`use Agentix.Chat` in a host LiveView installs an `on_mount` hook that projects the
conversation onto assigns (`:messages`, `:streaming_message`, `:state`, `:streaming?`,
`:in_flight_tools`, `:pending`) and imports the verbs (`send_message/3`, `resolve/4`,
`cancel/1`, `load_older/1`). Render the assigns yourself, or:

```bash
mix agentix.gen.components lib/my_app_web/components
```

copies an ownable set of default components (`message_list`, `composer`, `tool`, `pending`,
…) into your project. The streaming text and composer hooks ship at
`priv/static/agentix_stream_hook.js`.

## Tier 3 — + Durable persistence

Add the host-provided Ecto/Oban stack to make conversations and suspension expiry survive a
restart:

```elixir
{:ecto_sql, "~> 3.14"}, {:postgrex, "~> 0.22"}, {:oban, "~> 2.20"}
```

```elixir
# config/config.exs
config :agentix, persistence: {Agentix.Persistence.Ecto, repo: MyApp.Repo}

config :my_app, Oban, repo: MyApp.Repo, queues: [agentix_expiry: 10]
```

You own the `Repo` and the `Oban` instance. Oban needs its own migration, and it must run
**before** the Agentix migration (the expiry worker references Oban's jobs table) — give it
an earlier timestamp:

```elixir
# priv/repo/migrations/<EARLIER_TIMESTAMP>_add_oban_jobs.exs
defmodule MyApp.Repo.Migrations.AddObanJobs do
  use Ecto.Migration

  def up, do: Oban.Migration.up()
  def down, do: Oban.Migration.down(version: 1)
end
```

Then generate the Agentix tables migration and run both:

```bash
mix agentix.gen.migration         # writes priv/repo/migrations/*_create_agentix_tables.exs
mix ecto.migrate
```

The template creates the tables once, at install time — it is not re-run on upgrades. If
you ran it on a version before `tenant_key` existed (0.3.x and earlier), add the column
with your own migration (the exact snippet is in the CHANGELOG's 0.4.0 Breaking section).

Durable expiry is scheduled as Oban jobs. The audit log of model calls is off by default;
enable it with `config :agentix, audit: true`. See `examples/agentix_demo` for the full
wiring, including a Postgres-backed `Phoenix.LiveViewTest` that drives a HITL elicitation
end-to-end.

## Config keys

Application config — `config :agentix, …` (all tiers):

| key            | meaning                                                                 |
| -------------- | ----------------------------------------------------------------------- |
| `:persistence` | adapter module or `{module, opts}` (default `Agentix.Persistence.ETS`)  |
| `:notifier`    | live-event notifier (default `Agentix.Notifier.PubSub`; or `…None`)     |
| `:pubsub`      | the `Phoenix.PubSub` server name (default `Agentix.PubSub`)             |
| `:provider`    | LLM provider module (default `Agentix.Provider.ReqLLM`)                 |
| `:tokenizer`   | tokenizer module (default `Agentix.Tokenizer.Heuristic`)               |
| `:audit`       | record per-turn model-call audit rows (default `false`)                |

Per-conversation options are passed to `Agentix.Conversation.Config.new/1` (**not**
application config): `:model`, `:system_prompt`, `:tools`, `:hooks`, `:working_budget`
(default 30k tokens), `:default_timeout` (suspension expiry, default `300_000` ms), and more
— see `Agentix.Conversation.Config`.