Skip to main content

priv/templates/migration/create_agentix_tables.exs

defmodule Agentix.Repo.Migrations.CreateAgentixTables do
  @moduledoc """
  Creates the five Agentix tables for the Ecto/Postgres persistence adapter.

  Copy this file into your repo's `priv/repo/migrations/` with a timestamp prefix
  (e.g. `20260101000000_create_agentix_tables.exs`) and run `mix ecto.migrate`. The
  Ecto-backed suspension expiry additionally needs Oban's own migration.

  Conversation ids are host-chosen strings (the Registry key), so conversation id
  columns are `:text`, not `uuid`. Internal row ids are `uuid`; `tool_calls.id` is the
  provider-supplied tool_call_id (`:text`).
  """
  use Ecto.Migration

  def change do
    create table(:agentix_conversations, primary_key: false) do
      add(:id, :text, primary_key: true)
      add(:settings, :map, null: false, default: %{})
      add(:fsm_state, :map, null: false, default: %{})
      add(:status, :text, null: false, default: "active")
      timestamps(type: :utc_datetime_usec)
    end

    create(
      constraint(:agentix_conversations, :agentix_conversations_status,
        check: "status IN ('active','suspended','idle','ended')"
      )
    )

    create table(:agentix_events, primary_key: false) do
      add(:id, :binary_id, primary_key: true)

      add(:conversation_id, references(:agentix_conversations, type: :text, on_delete: :delete_all),
        null: false
      )

      add(:seq, :bigint, null: false)
      add(:type, :text, null: false)
      add(:content, :map, null: false)
      add(:inserted_at, :utc_datetime_usec, null: false)
    end

    create(unique_index(:agentix_events, [:conversation_id, :seq]))

    create(
      constraint(:agentix_events, :agentix_events_type,
        check:
          "type IN ('user_msg','assistant_msg','tool_call','tool_result','suspension','resolution')"
      )
    )

    create table(:agentix_summaries, primary_key: false) do
      add(:id, :binary_id, primary_key: true)

      add(:conversation_id, references(:agentix_conversations, type: :text, on_delete: :delete_all),
        null: false
      )

      add(:from_seq, :bigint, null: false)
      add(:to_seq, :bigint, null: false)
      add(:content, :map, null: false)
      add(:version, :text, null: false)
      add(:inserted_at, :utc_datetime_usec, null: false)
    end

    create(index(:agentix_summaries, [:conversation_id, "to_seq DESC"]))

    create(
      constraint(:agentix_summaries, :agentix_summaries_seq_range, check: "to_seq >= from_seq")
    )

    create table(:agentix_tool_calls, primary_key: false) do
      add(:id, :text, primary_key: true)

      add(:conversation_id, references(:agentix_conversations, type: :text, on_delete: :delete_all),
        null: false
      )

      add(:name, :text)
      add(:executor, :text, null: false)
      add(:status, :text, null: false, default: "pending")
      add(:args, :map)
      add(:result, :map)
      add(:inserted_at, :utc_datetime_usec, null: false)
      add(:resolved_at, :utc_datetime_usec)
    end

    create(index(:agentix_tool_calls, [:conversation_id, :status]))

    create(
      constraint(:agentix_tool_calls, :agentix_tool_calls_executor,
        check: "executor IN ('server','human','client','provider')"
      )
    )

    create(
      constraint(:agentix_tool_calls, :agentix_tool_calls_status,
        check: "status IN ('pending','resolved','errored','expired')"
      )
    )

    create table(:agentix_model_calls, primary_key: false) do
      add(:id, :binary_id, primary_key: true)

      add(:conversation_id, references(:agentix_conversations, type: :text, on_delete: :delete_all),
        null: false
      )

      add(:turn_ref, :bigint, null: false)
      add(:rendered_context, :map, null: false)
      add(:model, :text)
      add(:usage, :map)
      add(:latency_ms, :integer)
      add(:summary_version, :text)
      add(:evictions, {:array, :map})
      add(:inserted_at, :utc_datetime_usec, null: false)
    end

    create(index(:agentix_model_calls, [:conversation_id, :turn_ref]))
    create(index(:agentix_model_calls, [:inserted_at]))
  end
end