feat(captain-memory): create captain_contact_memories table with pgvector index

This commit is contained in:
Rodribm10 2026-04-18 23:38:23 -03:00
parent 2bf68e5be8
commit cae1ae36d6
2 changed files with 97 additions and 1 deletions

View File

@ -0,0 +1,64 @@
class CreateCaptainContactMemories < ActiveRecord::Migration[7.1]
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
def change
create_table :captain_contact_memories do |t|
t.references :account, null: false, foreign_key: true
t.references :contact, null: false, foreign_key: true
t.string :memory_type, null: false
t.text :content, null: false
t.text :evidence, null: false
t.float :confidence, null: false
t.string :scope, null: false, default: 'global'
t.vector :embedding, limit: 1536
t.bigint :source_conversation_id
t.bigint :source_unit_id
t.bigint :source_inbox_id
t.datetime :expires_at
t.datetime :last_verified_at, null: false
t.datetime :superseded_at
t.bigint :superseded_by_id
t.datetime :deleted_at
t.jsonb :metadata, null: false, default: {}
t.timestamps
end
add_index :captain_contact_memories,
[:account_id, :contact_id],
where: 'deleted_at IS NULL AND superseded_at IS NULL',
name: 'idx_ccm_recall'
add_index :captain_contact_memories,
[:source_unit_id, :memory_type, :created_at],
name: 'idx_ccm_analytics'
add_index :captain_contact_memories,
:deleted_at,
where: 'deleted_at IS NOT NULL',
name: 'idx_ccm_hard_delete'
add_index :captain_contact_memories,
:superseded_by_id,
where: 'superseded_at IS NOT NULL',
name: 'idx_ccm_superseded'
add_index :captain_contact_memories,
:source_conversation_id,
name: 'idx_ccm_source_conversation'
reversible do |dir|
dir.up do
execute <<~SQL.squish
CREATE INDEX idx_ccm_embedding
ON captain_contact_memories
USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100);
SQL
end
dir.down do
execute 'DROP INDEX IF EXISTS idx_ccm_embedding;'
end
end
end
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
end

View File

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.1].define(version: 2026_04_15_040957) do
ActiveRecord::Schema[7.1].define(version: 2026_04_19_023642) do
# These extensions should be enabled to support this database
enable_extension "pg_stat_statements"
enable_extension "pg_trgm"
@ -367,6 +367,36 @@ ActiveRecord::Schema[7.1].define(version: 2026_04_15_040957) do
t.index ["account_id"], name: "index_captain_configurations_on_account_id"
end
create_table "captain_contact_memories", force: :cascade do |t|
t.bigint "account_id", null: false
t.bigint "contact_id", null: false
t.string "memory_type", null: false
t.text "content", null: false
t.text "evidence", null: false
t.float "confidence", null: false
t.string "scope", default: "global", null: false
t.vector "embedding", limit: 1536
t.bigint "source_conversation_id"
t.bigint "source_unit_id"
t.bigint "source_inbox_id"
t.datetime "expires_at"
t.datetime "last_verified_at", null: false
t.datetime "superseded_at"
t.bigint "superseded_by_id"
t.datetime "deleted_at"
t.jsonb "metadata", default: {}, null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["account_id", "contact_id"], name: "idx_ccm_recall", where: "((deleted_at IS NULL) AND (superseded_at IS NULL))"
t.index ["account_id"], name: "index_captain_contact_memories_on_account_id"
t.index ["contact_id"], name: "index_captain_contact_memories_on_contact_id"
t.index ["deleted_at"], name: "idx_ccm_hard_delete", where: "(deleted_at IS NOT NULL)"
t.index ["embedding"], name: "idx_ccm_embedding", opclass: :vector_cosine_ops, using: :ivfflat
t.index ["source_conversation_id"], name: "idx_ccm_source_conversation"
t.index ["source_unit_id", "memory_type", "created_at"], name: "idx_ccm_analytics"
t.index ["superseded_by_id"], name: "idx_ccm_superseded", where: "(superseded_at IS NOT NULL)"
end
create_table "captain_conversation_insights", force: :cascade do |t|
t.bigint "account_id", null: false
t.bigint "captain_unit_id"
@ -2074,6 +2104,8 @@ ActiveRecord::Schema[7.1].define(version: 2026_04_15_040957) do
add_foreign_key "captain_assets", "captain_suites"
add_foreign_key "captain_brands", "accounts"
add_foreign_key "captain_configurations", "accounts"
add_foreign_key "captain_contact_memories", "accounts"
add_foreign_key "captain_contact_memories", "contacts"
add_foreign_key "captain_conversation_insights", "accounts"
add_foreign_key "captain_conversation_insights", "captain_units"
add_foreign_key "captain_conversation_insights", "inboxes", name: "fk_rails_inbox_id"