Class: RailsConsoleAi::Tools::MemoryTools
- Inherits:
-
Object
- Object
- RailsConsoleAi::Tools::MemoryTools
- Defined in:
- lib/rails_console_ai/tools/memory_tools.rb
Constant Summary collapse
- MEMORIES_DIR =
'memories'
Class Method Summary collapse
-
.parse(content) ⇒ Object
Public: parse a raw .md (YAML frontmatter + body) string into a hash.
Instance Method Summary collapse
- #delete_memory(name:) ⇒ Object
-
#initialize(storage = nil) ⇒ MemoryTools
constructor
A new instance of MemoryTools.
- #load_all_memories ⇒ Object
- #memory_summaries ⇒ Object
- #recall_memories(query: nil, tag: nil) ⇒ Object
- #recall_memory(name:) ⇒ Object
-
#save_memory(name:, description:, tags: [], target: :db, edited_by: nil, change_note: nil) ⇒ Object
target: :db (default) | :file Falls back to :file (with a notice in the return string) if DB tables aren’t set up.
Constructor Details
#initialize(storage = nil) ⇒ MemoryTools
Returns a new instance of MemoryTools.
9 10 11 |
# File 'lib/rails_console_ai/tools/memory_tools.rb', line 9 def initialize(storage = nil) @storage = storage || RailsConsoleAi.storage end |
Class Method Details
.parse(content) ⇒ Object
Public: parse a raw .md (YAML frontmatter + body) string into a hash. For memories, the body is stored under the ‘description’ key (memories don’t have a separate description vs body — the markdown IS the memory).
205 206 207 208 209 210 211 212 |
# File 'lib/rails_console_ai/tools/memory_tools.rb', line 205 def self.parse(content) return nil unless content =~ /\A---\s*\n(.*?\n)---\s*\n(.*)/m frontmatter = YAML.safe_load($1, permitted_classes: [Time, Date]) || {} description = $2.strip frontmatter.merge('description' => description) rescue Psych::SyntaxError nil end |
Instance Method Details
#delete_memory(name:) ⇒ Object
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/rails_console_ai/tools/memory_tools.rb', line 55 def delete_memory(name:) if Storage::DatabaseStorage.delete_memory_by_name(name) return "Memory deleted (db): \"#{name}\"" end key = memory_key(name) unless @storage.exists?(key) found_key = find_memory_key_by_name(name) return "No memory found: \"#{name}\"" unless found_key key = found_key end memory = load_memory_file(key) @storage.delete(key) "Memory deleted: \"#{memory ? memory['name'] : name}\"" rescue Storage::StorageError => e "FAILED to delete memory (#{e.})." end |
#load_all_memories ⇒ Object
130 131 132 133 134 135 136 |
# File 'lib/rails_console_ai/tools/memory_tools.rb', line 130 def load_all_memories db = Storage::DatabaseStorage.all_memories file = load_all_file_memories names = db.map { |m| m['name'].to_s.downcase } file.reject! { |m| names.include?(m['name'].to_s.downcase) } (db + file).sort_by { |m| m['name'].to_s.downcase } end |
#memory_summaries ⇒ Object
119 120 121 122 123 124 125 126 127 128 |
# File 'lib/rails_console_ai/tools/memory_tools.rb', line 119 def memory_summaries memories = load_all_memories return nil if memories.empty? memories.map { |m| = Array(m['tags']) tag_str = .empty? ? '' : " [#{.join(', ')}]" "- #{m['name']}#{tag_str}" } end |
#recall_memories(query: nil, tag: nil) ⇒ Object
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/rails_console_ai/tools/memory_tools.rb', line 85 def recall_memories(query: nil, tag: nil) memories = load_all_memories return "No memories stored yet." if memories.empty? results = memories if tag && !tag.empty? results = results.select { |m| Array(m['tags']).any? { |t| t.downcase.include?(tag.downcase) } } end if query && !query.empty? words = query.downcase.split(/\s+/) results = results.select { |m| searchable = [ m['name'].to_s.downcase, m['description'].to_s.downcase, Array(m['tags']).map(&:downcase).join(' ') ].join(' ') words.all? { |w| searchable.include?(w) } } end return "No memories matching your search." if results.empty? # Every memory in the result set was loaded into the AI's context. results.each { |m| record_use(m) } results.map { |m| line = "**#{m['name']}**\n#{m['description']}" line += "\nTags: #{m['tags'].join(', ')}" if m['tags'] && !m['tags'].empty? line }.join("\n\n---\n\n") end |
#recall_memory(name:) ⇒ Object
74 75 76 77 78 79 80 81 82 83 |
# File 'lib/rails_console_ai/tools/memory_tools.rb', line 74 def recall_memory(name:) memory = load_all_memories.find { |m| m['name'].to_s.downcase == name.to_s.downcase } return "No memory found: \"#{name}\"" unless memory record_use(memory) line = "**#{memory['name']}**\n#{memory['description']}" line += "\nTags: #{memory['tags'].join(', ')}" if memory['tags'] && !memory['tags'].empty? line end |
#save_memory(name:, description:, tags: [], target: :db, edited_by: nil, change_note: nil) ⇒ Object
target: :db (default) | :file Falls back to :file (with a notice in the return string) if DB tables aren’t set up.
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/rails_console_ai/tools/memory_tools.rb', line 15 def save_memory(name:, description:, tags: [], target: :db, edited_by: nil, change_note: nil) target = (target || :db).to_sym db_fell_back = false if target == :db && !Storage::DatabaseStorage.memories_available? target = :file db_fell_back = true end if target == :file result = save_memory_to_file(name: name, description: description, tags: ) if db_fell_back result += "\nNOTE: DB storage was requested but the rails_console_ai_memories table does not exist. " \ "Run `ai_db_setup` in your Rails console to enable the versioned DB store. " \ "Saved to a file instead." end result else record, was_new = Storage::DatabaseStorage.save_memory( name: name, description: description, tags: , edited_by: edited_by || 'ai', change_note: change_note ) if was_new "Memory saved (db): \"#{record.name}\" (id=#{record.id})" else "Memory updated (db): \"#{record.name}\" (id=#{record.id})" end end rescue Storage::StorageError => e if target == :file # Preserve the original behaviour: include a hint with the raw frontmatter # so the user (or AI) can paste it manually when the filesystem is read-only. "FAILED to save (#{e.}). Add this manually to .rails_console_ai/#{memory_key(name)}:\n" \ "---\nname: #{name}\ntags: #{Array().inspect}\n---\n\n#{description}" else "FAILED to save (#{e.})." end rescue ::ActiveRecord::RecordInvalid => e "FAILED to save (#{e.})." end |