Class: Engram::Adapters::InMemoryStore
- Inherits:
-
Object
- Object
- Engram::Adapters::InMemoryStore
- Includes:
- Ports::MemoryStore
- Defined in:
- lib/engram/adapters/in_memory_store.rb
Overview
In-process MemoryStore. Used as the zero-config default and in unit tests. Search is exact cosine similarity over the stored vectors.
Instance Method Summary collapse
- #add(record) ⇒ Object
- #all(scope:, limit: nil, offset: 0, after_id: nil) ⇒ Object
- #clear ⇒ Object
- #delete(scope:, id:) ⇒ Object
-
#initialize ⇒ InMemoryStore
constructor
A new instance of InMemoryStore.
- #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 ⇒ InMemoryStore
Returns a new instance of InMemoryStore.
10 11 12 13 |
# File 'lib/engram/adapters/in_memory_store.rb', line 10 def initialize @records = {} @sequence = 0 end |
Instance Method Details
#add(record) ⇒ Object
15 16 17 18 19 20 21 |
# File 'lib/engram/adapters/in_memory_store.rb', line 15 def add(record) validate_scope!(record.scope) record.id ||= (@sequence += 1) @records[record.id] = record record end |
#all(scope:, limit: nil, offset: 0, after_id: nil) ⇒ Object
39 40 41 42 43 44 45 |
# File 'lib/engram/adapters/in_memory_store.rb', line 39 def all(scope:, limit: nil, offset: 0, after_id: nil) records = @records.values.select { |r| r.scope == scope }.sort_by { |record| record.id } records = records.drop_while { |record| !after_id.nil? && record.id && record.id <= after_id } records = records.drop(offset) if offset > 0 records = records.take(limit) if limit records end |
#clear ⇒ Object
71 72 73 74 |
# File 'lib/engram/adapters/in_memory_store.rb', line 71 def clear @records.clear @sequence = 0 end |
#delete(scope:, id:) ⇒ Object
56 57 58 59 60 61 |
# File 'lib/engram/adapters/in_memory_store.rb', line 56 def delete(scope:, id:) return 0 unless @records[id]&.scope == scope @records.delete(id) 1 end |
#search(embedding:, scope:, limit:, kinds: nil, embedding_metadata: nil) ⇒ Object
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/engram/adapters/in_memory_store.rb', line 23 def search(embedding:, scope:, limit:, kinds: nil, embedding_metadata: nil) Engram::EmbeddingMetadata.validate_query!(, ) allowed_kinds = normalize_kinds(kinds) results = @records .values .select { |r| searchable?(r, scope, allowed_kinds) } .map { |r| [r, Engram::Math.cosine_similarity(, r.)] } .sort_by { |(_, score)| -score } .first(limit) .map { |(record, _)| record } results.each { |record| Engram::EmbeddingMetadata.validate_record!(record, , ) } results end |
#touch(scope:, id:, at: Time.now) ⇒ Object
63 64 65 66 67 68 69 |
# File 'lib/engram/adapters/in_memory_store.rb', line 63 def touch(scope:, id:, at: Time.now) record = @records[id] return 0 unless record&.scope == scope record.last_accessed_at = at 1 end |
#update(scope:, id:, record:) ⇒ Object
47 48 49 50 51 52 53 54 |
# File 'lib/engram/adapters/in_memory_store.rb', line 47 def update(scope:, id:, record:) existing = @records[id] raise Engram::Error, "no memory with id #{id.inspect} in scope #{scope.inspect}" unless existing&.scope == scope raise Engram::Error, "cannot move memory across scopes" unless record.scope == scope record.id = id @records[id] = record end |