PhoenixKitAgent.Migrations (PhoenixKitAgent v0.1.0)

Copy Markdown View Source

Module-owned versioned migrations for phoenix_kit_agent — the protocol core's mix phoenix_kit.update discovers through PhoenixKitAgent.migration_module/0 (current_version/0, migrated_version_runtime/1, up/1, down/1). Same shape as PhoenixKitDashboards.Migrations: two version readers, up/1 re-reading the version before it changes anything, the SQL kept as data (up_statements/2, down_statements/2).

Tables (V1)

  • phoenix_kit_agent_conversations — a user's chats; the chat list reads them by (user_uuid, status, last_message_at DESC).
  • phoenix_kit_agent_messages — every message of a chat, the tool calls and their outcomes included; ai_request_uuid links the phoenix_kit_ai_requests row of a model call.
  • phoenix_kit_agent_attachments — files attached to a message; the bytes live in Storage (file_uuid).
  • phoenix_kit_agent_user_settings — one row per user, NULL meaning "the module default"; also the per-user "turn in flight" lock.
  • phoenix_kit_agent_limit_events — one limit notice per user, kind and period.

V2 — the confirmation of a write (spec §5.2, I6)

  • phoenix_kit_agent_messages.tool_outcome also takes expired, changed and failed (the outcomes of a confirmation card, kept on its notice);
  • assistant_message_uuid — on a tool message, the assistant message whose tool call it answers (the arguments a confirmation is redeemed with). No foreign key: both rows are in the same chat and go with it;
  • confirmation_uuid — the confirmation core holds the write in (PhoenixKit.API.Confirm), on the tool message that asks for it and on the notice that says how it ended; partial index phoenix_kit_agent_messages_confirmation_uuid_index, through which the chat panel finds the cards still waiting. No foreign key: core deletes its rows on its own schedule.

down/1 to V1 drops the two columns and the index, and clears an outcome V1 cannot hold (the notice stays, without it).

Deleting a user deletes their rows of every table (ON DELETE CASCADE); a deleted phoenix_kit_ai_requests row, AI endpoint or Storage file leaves the link NULL and never blocks the delete. Money is in micro-dollars (*_micro_usd, $1 = 1_000_000); the AI journal keeps dollars (phoenix_kit_ai_requests.cost), turned into micro-dollars by PhoenixKitAgent.Config.cost_to_micro/1.

Version marker

COMMENT ON TABLE phoenix_kit_agent_conversations IS 'pk_agent_schema:<N>'. No table, or one without a pk_agent_schema: comment, reads as version 0.

Idempotency and rollback

Every statement guards itself (IF NOT EXISTS / IF EXISTS), so the chain can be re-run. These tables belong to this module alone: down/1 to version 0 drops them with every chat, message, attachment link and per-user setting in them (the Storage files of the attachments stay). Back up the database first.

Ordering

The foreign keys reach core's phoenix_kit_users, phoenix_kit_files, phoenix_kit_ai_endpoints and phoenix_kit_ai_requests, so this chain runs after core's (mix phoenix_kit.update generates the module migrations after core's own).

Summary

Functions

The version this code expects the schema to be at.

Rolls back to opts[:version] (default 0). Migration context only. To 0 it drops every table of the module — see the moduledoc.

The SQL down/1 runs, as data. To 0 it drops every table of the module; to a version still in the chain it undoes every later version (each statement guards itself) and re-stamps the marker.

The installed version, read inside a migration through Ecto.Migration's repo(). No rescue: a version that cannot be read aborts the migration.

The installed version, read outside a migration (what mix phoenix_kit.update calls) through PhoenixKit's configured repo. An invalid prefix raises; a database that cannot be reached reads as 0, which only costs a redundant migration file because up/1 re-reads the version before it changes anything.

Applies the chain up to opts[:version] (default current_version/0). Migration context only. Re-reads the installed version first: a database already at (or past) the target is left alone.

The SQL up/1 runs, as data. target is how far to go (default current_version/0); 0 is nothing. Every version from V1 on is in it: each statement guards itself, so the versions already applied change nothing.

The table carrying the pk_agent_schema:<N> marker.

Functions

current_version()

@spec current_version() :: pos_integer()

The version this code expects the schema to be at.

down(opts \\ [])

@spec down(keyword() | map()) :: :ok

Rolls back to opts[:version] (default 0). Migration context only. To 0 it drops every table of the module — see the moduledoc.

down_statements(prefix \\ "public", target \\ 0)

@spec down_statements(String.t(), non_neg_integer()) :: [String.t()]

The SQL down/1 runs, as data. To 0 it drops every table of the module; to a version still in the chain it undoes every later version (each statement guards itself) and re-stamps the marker.

migrated_version(opts \\ [])

@spec migrated_version(keyword() | map()) :: non_neg_integer()

The installed version, read inside a migration through Ecto.Migration's repo(). No rescue: a version that cannot be read aborts the migration.

migrated_version_runtime(opts \\ [])

@spec migrated_version_runtime(keyword() | map()) :: non_neg_integer()

The installed version, read outside a migration (what mix phoenix_kit.update calls) through PhoenixKit's configured repo. An invalid prefix raises; a database that cannot be reached reads as 0, which only costs a redundant migration file because up/1 re-reads the version before it changes anything.

up(opts \\ [])

@spec up(keyword() | map()) :: :ok

Applies the chain up to opts[:version] (default current_version/0). Migration context only. Re-reads the installed version first: a database already at (or past) the target is left alone.

up_statements(prefix \\ "public", target \\ 2)

@spec up_statements(String.t(), non_neg_integer()) :: [String.t()]

The SQL up/1 runs, as data. target is how far to go (default current_version/0); 0 is nothing. Every version from V1 on is in it: each statement guards itself, so the versions already applied change nothing.

version_table()

@spec version_table() :: String.t()

The table carrying the pk_agent_schema:<N> marker.