Class: RCrewAI::Memory::SqliteStore
- Inherits:
-
Object
- Object
- RCrewAI::Memory::SqliteStore
- Defined in:
- lib/rcrewai/memory/sqlite_store.rb
Overview
Persistent vector store backed by SQLite. Vectors are packed as little-endian floats; metadata is JSON. Cosine is computed in Ruby over rows filtered by scope — adequate for the thousands-of-memories scale an agent produces; an ANN index is a later optimization.
The sqlite3 gem is required lazily so the rest of the library (and the in-memory store) works even if it isn't installed.
Constant Summary collapse
- DEFAULT_PATH =
File.join(Dir.home, '.rcrewai', 'memory.db')
Instance Method Summary collapse
- #add(id:, text:, vector:, scope:, metadata: {}) ⇒ Object
- #all(scope:) ⇒ Object
- #delete(scope:) ⇒ Object
- #delete_record(id:, scope:) ⇒ Object
-
#initialize(path: DEFAULT_PATH, max_candidates: 1000) ⇒ SqliteStore
constructor
max_candidates bounds how many (most-recent) rows a search cosines, so recall cost stays constant as total memory grows.
- #search(vector, k:, scope:) ⇒ Object
Constructor Details
#initialize(path: DEFAULT_PATH, max_candidates: 1000) ⇒ SqliteStore
max_candidates bounds how many (most-recent) rows a search cosines, so recall cost stays constant as total memory grows. nil = consider all.
20 21 22 23 24 25 26 27 |
# File 'lib/rcrewai/memory/sqlite_store.rb', line 20 def initialize(path: DEFAULT_PATH, max_candidates: 1000) require 'sqlite3' ensure_parent_dir(path) unless path == ':memory:' @db = SQLite3::Database.new(path) @db.results_as_hash = true @max_candidates = max_candidates create_schema end |
Instance Method Details
#add(id:, text:, vector:, scope:, metadata: {}) ⇒ Object
29 30 31 32 33 34 35 36 |
# File 'lib/rcrewai/memory/sqlite_store.rb', line 29 def add(id:, text:, vector:, scope:, metadata: {}) @db.execute( 'INSERT INTO memories (id, scope, text, vector, metadata) VALUES (?, ?, ?, ?, ?) ' \ 'ON CONFLICT(id) DO UPDATE SET scope=excluded.scope, text=excluded.text, ' \ 'vector=excluded.vector, metadata=excluded.metadata', [id, scope, text, pack_vector(vector), JSON.generate( || {})] ) end |
#all(scope:) ⇒ Object
38 39 40 |
# File 'lib/rcrewai/memory/sqlite_store.rb', line 38 def all(scope:) @db.execute('SELECT * FROM memories WHERE scope = ?', [scope]).map { |row| to_record(row) } end |
#delete(scope:) ⇒ Object
51 52 53 |
# File 'lib/rcrewai/memory/sqlite_store.rb', line 51 def delete(scope:) @db.execute('DELETE FROM memories WHERE scope = ?', [scope]) end |
#delete_record(id:, scope:) ⇒ Object
55 56 57 |
# File 'lib/rcrewai/memory/sqlite_store.rb', line 55 def delete_record(id:, scope:) @db.execute('DELETE FROM memories WHERE id = ? AND scope = ?', [id, scope]) end |
#search(vector, k:, scope:) ⇒ Object
42 43 44 45 46 47 48 49 |
# File 'lib/rcrewai/memory/sqlite_store.rb', line 42 def search(vector, k:, scope:) candidates(scope) .reject { |r| r[:vector].nil? } .map { |r| [r, Similarity.cosine(vector, r[:vector])] } .sort_by { |(_r, score)| -score } .first(k) .map(&:first) end |