Module: RailsConsoleAi::Storage::DatabaseStorage
- Defined in:
- lib/rails_console_ai/storage/database_storage.rb
Overview
Thin facade over the AR-backed Skill / Memory tables.
Not a drop-in Storage::Base adapter: the loaders read & write structured records, not opaque Markdown blobs, so we expose a small typed API instead. All methods are safe to call before ‘ai_db_setup` has run — they detect missing tables and return empty results / nil rather than raising.
Class Method Summary collapse
- .active_record_connection ⇒ Object
- .agents_available? ⇒ Boolean
-
.all_agents ⇒ Object
— Agents —.
-
.all_memories ⇒ Object
— Memories —.
-
.all_skills ⇒ Object
— Skills —.
- .available? ⇒ Boolean
- .delete_agent_by_name(name) ⇒ Object
- .delete_memory_by_name(name) ⇒ Object
- .delete_skill_by_name(name) ⇒ Object
- .ensure_tables!(kind) ⇒ Object
- .find_agent_by_name(name) ⇒ Object
- .find_memory_by_name(name) ⇒ Object
- .find_skill_by_name(name) ⇒ Object
- .memories_available? ⇒ Boolean
- .save_agent(name:, description:, body:, max_rounds: nil, model: nil, tools: [], edited_by: nil, change_note: nil) ⇒ Object
- .save_memory(name:, description:, tags: [], edited_by: nil, change_note: nil) ⇒ Object
- .save_skill(name:, description:, body:, tags: [], bypass_guards_for_methods: [], edited_by: nil, change_note: nil) ⇒ Object
-
.table_exists?(table_name) ⇒ Boolean
Ask the connection directly so we don’t depend on the AR model being autoloaded yet.
- .warn_failure(method, error) ⇒ Object
Class Method Details
.active_record_connection ⇒ Object
37 38 39 40 41 42 43 44 45 |
# File 'lib/rails_console_ai/storage/database_storage.rb', line 37 def active_record_connection klass = RailsConsoleAi.configuration.connection_class if klass klass = Object.const_get(klass) if klass.is_a?(String) klass.connection else ::ActiveRecord::Base.connection end end |
.agents_available? ⇒ Boolean
20 21 22 |
# File 'lib/rails_console_ai/storage/database_storage.rb', line 20 def agents_available? table_exists?('rails_console_ai_agents') end |
.all_agents ⇒ Object
— Agents —
136 137 138 139 140 141 142 |
# File 'lib/rails_console_ai/storage/database_storage.rb', line 136 def all_agents return [] unless agents_available? RailsConsoleAi::Agent.alphabetical.map(&:to_hash) rescue => e warn_failure(:all_agents, e) [] end |
.all_memories ⇒ Object
— Memories —
93 94 95 96 97 98 99 |
# File 'lib/rails_console_ai/storage/database_storage.rb', line 93 def all_memories return [] unless memories_available? RailsConsoleAi::Memory.alphabetical.map(&:to_hash) rescue => e warn_failure(:all_memories, e) [] end |
.all_skills ⇒ Object
— Skills —
49 50 51 52 53 54 55 |
# File 'lib/rails_console_ai/storage/database_storage.rb', line 49 def all_skills return [] unless available? RailsConsoleAi::Skill.alphabetical.map(&:to_hash) rescue => e warn_failure(:all_skills, e) [] end |
.available? ⇒ Boolean
12 13 14 |
# File 'lib/rails_console_ai/storage/database_storage.rb', line 12 def available? table_exists?('rails_console_ai_skills') end |
.delete_agent_by_name(name) ⇒ Object
170 171 172 173 174 175 176 |
# File 'lib/rails_console_ai/storage/database_storage.rb', line 170 def delete_agent_by_name(name) return false unless agents_available? record = RailsConsoleAi::Agent.where('LOWER(name) = ?', name.to_s.downcase).first return false unless record record.destroy true end |
.delete_memory_by_name(name) ⇒ Object
126 127 128 129 130 131 132 |
# File 'lib/rails_console_ai/storage/database_storage.rb', line 126 def delete_memory_by_name(name) return false unless memories_available? record = RailsConsoleAi::Memory.where('LOWER(name) = ?', name.to_s.downcase).first return false unless record record.destroy true end |
.delete_skill_by_name(name) ⇒ Object
83 84 85 86 87 88 89 |
# File 'lib/rails_console_ai/storage/database_storage.rb', line 83 def delete_skill_by_name(name) return false unless available? record = RailsConsoleAi::Skill.where('LOWER(name) = ?', name.to_s.downcase).first return false unless record record.destroy true end |
.ensure_tables!(kind) ⇒ Object
178 179 180 181 182 183 184 185 186 187 |
# File 'lib/rails_console_ai/storage/database_storage.rb', line 178 def ensure_tables!(kind) ready = case kind when :skills then available? when :memories then memories_available? when :agents then agents_available? else false end return if ready raise StorageError, "rails_console_ai_#{kind} table does not exist. Run `ai_db_setup` in your console." end |
.find_agent_by_name(name) ⇒ Object
144 145 146 147 148 149 150 151 |
# File 'lib/rails_console_ai/storage/database_storage.rb', line 144 def find_agent_by_name(name) return nil unless agents_available? record = RailsConsoleAi::Agent.where('LOWER(name) = ?', name.to_s.downcase).first record&.to_hash rescue => e warn_failure(:find_agent_by_name, e) nil end |
.find_memory_by_name(name) ⇒ Object
101 102 103 104 105 106 107 108 |
# File 'lib/rails_console_ai/storage/database_storage.rb', line 101 def find_memory_by_name(name) return nil unless memories_available? record = RailsConsoleAi::Memory.where('LOWER(name) = ?', name.to_s.downcase).first record&.to_hash rescue => e warn_failure(:find_memory_by_name, e) nil end |
.find_skill_by_name(name) ⇒ Object
57 58 59 60 61 62 63 64 |
# File 'lib/rails_console_ai/storage/database_storage.rb', line 57 def find_skill_by_name(name) return nil unless available? record = RailsConsoleAi::Skill.where('LOWER(name) = ?', name.to_s.downcase).first record&.to_hash rescue => e warn_failure(:find_skill_by_name, e) nil end |
.memories_available? ⇒ Boolean
16 17 18 |
# File 'lib/rails_console_ai/storage/database_storage.rb', line 16 def memories_available? table_exists?('rails_console_ai_memories') end |
.save_agent(name:, description:, body:, max_rounds: nil, model: nil, tools: [], edited_by: nil, change_note: nil) ⇒ Object
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/rails_console_ai/storage/database_storage.rb', line 153 def save_agent(name:, description:, body:, max_rounds: nil, model: nil, tools: [], edited_by: nil, change_note: nil) ensure_tables!(:agents) record = RailsConsoleAi::Agent.where('LOWER(name) = ?', name.to_s.downcase).first record ||= RailsConsoleAi::Agent.new was_new = record.new_record? content = RailsConsoleAi::AgentLoader.dump( name: name, description: description, body: body, max_rounds: max_rounds, model: model, tools: tools ) record.update_with_version!( { content: content }, edited_by: edited_by, change_note: change_note ) [record, was_new] end |
.save_memory(name:, description:, tags: [], edited_by: nil, change_note: nil) ⇒ Object
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/rails_console_ai/storage/database_storage.rb', line 110 def save_memory(name:, description:, tags: [], edited_by: nil, change_note: nil) ensure_tables!(:memories) record = RailsConsoleAi::Memory.where('LOWER(name) = ?', name.to_s.downcase).first record ||= RailsConsoleAi::Memory.new was_new = record.new_record? content = RailsConsoleAi::Tools::MemoryTools.dump( name: name, description: description, tags: ) record.update_with_version!( { content: content }, edited_by: edited_by, change_note: change_note ) [record, was_new] end |
.save_skill(name:, description:, body:, tags: [], bypass_guards_for_methods: [], edited_by: nil, change_note: nil) ⇒ Object
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/rails_console_ai/storage/database_storage.rb', line 66 def save_skill(name:, description:, body:, tags: [], bypass_guards_for_methods: [], edited_by: nil, change_note: nil) ensure_tables!(:skills) record = RailsConsoleAi::Skill.where('LOWER(name) = ?', name.to_s.downcase).first record ||= RailsConsoleAi::Skill.new was_new = record.new_record? content = RailsConsoleAi::SkillLoader.dump( name: name, description: description, body: body, tags: , bypass_guards_for_methods: bypass_guards_for_methods ) record.update_with_version!( { content: content }, edited_by: edited_by, change_note: change_note ) [record, was_new] end |
.table_exists?(table_name) ⇒ Boolean
Ask the connection directly so we don’t depend on the AR model being autoloaded yet. In a Rails console, the models in app/models are autoloaded lazily — the constant is ‘defined?`-false until first reference. Going through the connection avoids that timing trap.
28 29 30 31 32 33 34 35 |
# File 'lib/rails_console_ai/storage/database_storage.rb', line 28 def table_exists?(table_name) return false unless defined?(::ActiveRecord) conn = active_record_connection return false unless conn conn.table_exists?(table_name) rescue ::ActiveRecord::ActiveRecordError, ::ActiveRecord::NoDatabaseError, NoMethodError false end |
.warn_failure(method, error) ⇒ Object
189 190 191 192 |
# File 'lib/rails_console_ai/storage/database_storage.rb', line 189 def warn_failure(method, error) return unless defined?(RailsConsoleAi.logger) && RailsConsoleAi.logger RailsConsoleAi.logger.warn("RailsConsoleAi::Storage::DatabaseStorage##{method} failed: #{error.class}: #{error.}") end |