Class: Engram::Adapters::PgvectorStore
- Inherits:
-
Object
- Object
- Engram::Adapters::PgvectorStore
- Includes:
- Ports::MemoryStore
- Defined in:
- lib/engram/adapters/pgvector_store.rb
Overview
MemoryStore backed by PostgreSQL + pgvector via the neighbor gem.
Requires the host app to provide ActiveRecord, the neighbor gem, and an AR model
(default: Engram::MemoryRecord) created by the install generator. These are NOT hard
dependencies of engram; this adapter only references them at call time.
Instance Method Summary collapse
- #add(record) ⇒ Object
- #all(scope:, limit: nil, offset: 0, after_id: nil) ⇒ Object
- #delete(scope:, id:) ⇒ Object
-
#initialize(model: nil) ⇒ PgvectorStore
constructor
A new instance of PgvectorStore.
- #search(embedding:, scope:, limit:, kinds: nil, embedding_metadata: nil) ⇒ Object
- #touch(scope:, id:, at: Time.now) ⇒ Object
- #update(scope:, id:, record:) ⇒ Object
Constructor Details
#initialize(model: nil) ⇒ PgvectorStore
Returns a new instance of PgvectorStore.
13 14 15 |
# File 'lib/engram/adapters/pgvector_store.rb', line 13 def initialize(model: nil) @model = model end |
Instance Method Details
#add(record) ⇒ Object
17 18 19 20 21 22 23 24 25 26 27 28 29 |
# File 'lib/engram/adapters/pgvector_store.rb', line 17 def add(record) validate_scope!(record.scope) row = model.create!( content: record.content, scope: record.scope, kind: record.kind.to_s, importance: record.importance, metadata: record., embedding: record. ) to_record(row) end |
#all(scope:, limit: nil, offset: 0, after_id: nil) ⇒ Object
44 45 46 47 48 49 50 |
# File 'lib/engram/adapters/pgvector_store.rb', line 44 def all(scope:, limit: nil, offset: 0, after_id: nil) query = model.where(scope: scope).order(:id) query = query.where("id > ?", after_id) if after_id query = query.limit(limit) if limit query = query.offset(offset) if offset > 0 query.map { |row| to_record(row) } end |
#delete(scope:, id:) ⇒ Object
70 71 72 |
# File 'lib/engram/adapters/pgvector_store.rb', line 70 def delete(scope:, id:) model.where(id: id, scope: scope).delete_all end |
#search(embedding:, scope:, limit:, kinds: nil, embedding_metadata: nil) ⇒ Object
31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/engram/adapters/pgvector_store.rb', line 31 def search(embedding:, scope:, limit:, kinds: nil, embedding_metadata: nil) Engram::EmbeddingMetadata.validate_query!(, ) query = model.where(scope: scope) normalized_kinds = normalize_kinds(kinds) query = query.where(kind: normalized_kinds) if normalized_kinds query .nearest_neighbors(:embedding, , distance: "cosine") .limit(limit) .map { |row| to_record(row) } .tap { |records| validate_query_records!(records, , ) } end |
#touch(scope:, id:, at: Time.now) ⇒ Object
74 75 76 |
# File 'lib/engram/adapters/pgvector_store.rb', line 74 def touch(scope:, id:, at: Time.now) model.where(id: id, scope: scope).update_all(last_accessed_at: at) end |
#update(scope:, id:, record:) ⇒ Object
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/engram/adapters/pgvector_store.rb', line 52 def update(scope:, id:, record:) raise Engram::Error, "cannot move memory across scopes" unless record.scope == scope model.transaction do row = model.lock.find_by!(id: id, scope: scope) row.update!( content: record.content, kind: record.kind.to_s, importance: record.importance, metadata: record., embedding: record. ) to_record(row) end rescue ActiveRecord::RecordNotFound raise Engram::Error, "no memory with id #{id.inspect} in scope #{scope.inspect}" end |