Legion. Store. Postgres
(Legion v0.5.0)
View Source
A ready-made Legion.Store backed by Postgres, through your existing Ecto repo.
The generated store uses Ecto for its schema, reads, and partial upserts.
Legion depends on ecto_sql and postgrex, so this adapter needs nothing
extra in your mix.exs - only an Ecto.Repo backed by
Ecto.Adapters.Postgres.
Usage
Define a Postgres-backed Ecto repo and a store module that uses it:
defmodule MyApp.AgentStore do
use Legion.Store.Postgres, repo: MyApp.Repo
endCreate the table in a migration with Legion.Store.Postgres.Migration:
defmodule MyApp.Repo.Migrations.AddLegionAgents do
use Ecto.Migration
def up, do: Legion.Store.Postgres.Migration.up()
def down, do: Legion.Store.Postgres.Migration.down()
endThe Store migration also creates the ratelimit_metadata column and GIN index used
by Legion.RateLimiter.Postgres; no additional migration is needed.
Then start agents with it:
{:ok, pid} = Legion.start_link(AssistantAgent, store: MyApp.AgentStore, agent_id: "user_42")Options
:repo(required) - your Ecto repo module:table- the table name, defaults to"legion_agents":persistence_frequency-:turn(default) or:step
To persist intermediate eval results and recoverable errors:
defmodule MyApp.AgentStore do
use Legion.Store.Postgres,
repo: MyApp.Repo,
persistence_frequency: :step
endAgent ids must be valid UTF-8 strings. Snapshots are stored as compressed
:erlang.term_to_binary/2 blobs - readable only from Elixir, one row
per conversation, upserted on every save. Step snapshots therefore require
no additional migration.
save/1 performs partial upserts, so a row carries the conversation state
and identity. Omitted payload fields preserve their existing values. The
updated_at timestamp is automatically set to the current UTC time on every save.
Only agent_id and inserted_at are never updated.
The row's status flips to 'running' when a turn starts and back to
'idle' when it completes. Step writes update only the conversation state,
leaving the running status unchanged.
Usage is stored as a jsonb[]: each element contains one complete,
string-keyed LLM usage map.
list/1 and get/1 read persisted conversations back from the same table.
The migration also installs a trigger that pg_notifys the table's channel
(the table name) with the agent_id on every insert or update, so
consumers can follow store changes live without polling.