|
1 | 1 | # frozen_string_literal: true |
2 | 2 |
|
3 | | -module RubyLLM |
4 | | - module ActiveRecord |
5 | | - # Adds chat and message persistence capabilities to ActiveRecord models. |
6 | | - module ActsAs |
7 | | - extend ActiveSupport::Concern |
8 | | - |
9 | | - # When ActsAs is included, ensure models are loaded from database |
10 | | - def self.included(base) |
11 | | - super |
12 | | - # Monkey-patch Models to use database when ActsAs is active |
13 | | - RubyLLM::Models.class_eval do |
14 | | - def self.load_models |
15 | | - read_from_database |
16 | | - rescue StandardError => e |
17 | | - RubyLLM.logger.debug "Failed to load models from database: #{e.message}, falling back to JSON" |
18 | | - read_from_json |
19 | | - end |
20 | | - |
21 | | - def self.read_from_database |
22 | | - model_class = RubyLLM.config.model_registry_class |
23 | | - model_class = model_class.constantize if model_class.is_a?(String) |
24 | | - model_class.all.map(&:to_llm) |
25 | | - end |
26 | | - |
27 | | - def load_from_database! |
28 | | - @models = self.class.read_from_database |
| 3 | +if defined?(ActiveRecord::Base) |
| 4 | + module RubyLLM |
| 5 | + module ActiveRecord |
| 6 | + # Adds chat and message persistence capabilities to ActiveRecord models. |
| 7 | + module ActsAs |
| 8 | + extend ActiveSupport::Concern |
| 9 | + |
| 10 | + # When ActsAs is included, ensure models are loaded from database |
| 11 | + def self.included(base) |
| 12 | + super |
| 13 | + # Monkey-patch Models to use database when ActsAs is active |
| 14 | + RubyLLM::Models.class_eval do |
| 15 | + def self.load_models |
| 16 | + read_from_database |
| 17 | + rescue StandardError => e |
| 18 | + RubyLLM.logger.debug "Failed to load models from database: #{e.message}, falling back to JSON" |
| 19 | + read_from_json |
| 20 | + end |
| 21 | + |
| 22 | + def self.read_from_database |
| 23 | + model_class = RubyLLM.config.model_registry_class |
| 24 | + model_class = model_class.constantize if model_class.is_a?(String) |
| 25 | + model_class.all.map(&:to_llm) |
| 26 | + end |
| 27 | + |
| 28 | + def load_from_database! |
| 29 | + @models = self.class.read_from_database |
| 30 | + end |
29 | 31 | end |
30 | 32 | end |
31 | | - end |
32 | | - |
33 | | - class_methods do # rubocop:disable Metrics/BlockLength |
34 | | - def acts_as_chat(messages: :messages, message_class: nil, messages_foreign_key: nil, # rubocop:disable Metrics/ParameterLists |
35 | | - model: :model, model_class: nil, model_foreign_key: nil) |
36 | | - include RubyLLM::ActiveRecord::ChatMethods |
37 | | - |
38 | | - class_attribute :messages_association_name, :model_association_name, :message_class, :model_class |
39 | | - |
40 | | - self.messages_association_name = messages |
41 | | - self.model_association_name = model |
42 | | - self.message_class = (message_class || messages.to_s.classify).to_s |
43 | | - self.model_class = (model_class || model.to_s.classify).to_s |
44 | | - |
45 | | - has_many messages, |
46 | | - -> { order(created_at: :asc) }, |
47 | | - class_name: self.message_class, |
48 | | - foreign_key: messages_foreign_key, |
49 | | - dependent: :destroy |
50 | | - |
51 | | - belongs_to model, |
52 | | - class_name: self.model_class, |
53 | | - foreign_key: model_foreign_key, |
54 | | - optional: true |
55 | | - |
56 | | - delegate :add_message, to: :to_llm |
57 | | - |
58 | | - define_method :messages_association do |
59 | | - send(messages_association_name) |
60 | | - end |
61 | | - |
62 | | - define_method :model_association do |
63 | | - send(model_association_name) |
64 | | - end |
65 | | - |
66 | | - define_method :'model_association=' do |value| |
67 | | - send("#{model_association_name}=", value) |
| 33 | + |
| 34 | + class_methods do # rubocop:disable Metrics/BlockLength |
| 35 | + def acts_as_chat(messages: :messages, message_class: nil, messages_foreign_key: nil, # rubocop:disable Metrics/ParameterLists |
| 36 | + model: :model, model_class: nil, model_foreign_key: nil) |
| 37 | + include RubyLLM::ActiveRecord::ChatMethods |
| 38 | + |
| 39 | + class_attribute :messages_association_name, :model_association_name, :message_class, :model_class |
| 40 | + |
| 41 | + self.messages_association_name = messages |
| 42 | + self.model_association_name = model |
| 43 | + self.message_class = (message_class || messages.to_s.classify).to_s |
| 44 | + self.model_class = (model_class || model.to_s.classify).to_s |
| 45 | + |
| 46 | + has_many messages, |
| 47 | + -> { order(created_at: :asc) }, |
| 48 | + class_name: self.message_class, |
| 49 | + foreign_key: messages_foreign_key, |
| 50 | + dependent: :destroy |
| 51 | + |
| 52 | + belongs_to model, |
| 53 | + class_name: self.model_class, |
| 54 | + foreign_key: model_foreign_key, |
| 55 | + optional: true |
| 56 | + |
| 57 | + delegate :add_message, to: :to_llm |
| 58 | + |
| 59 | + define_method :messages_association do |
| 60 | + send(messages_association_name) |
| 61 | + end |
| 62 | + |
| 63 | + define_method :model_association do |
| 64 | + send(model_association_name) |
| 65 | + end |
| 66 | + |
| 67 | + define_method :'model_association=' do |value| |
| 68 | + send("#{model_association_name}=", value) |
| 69 | + end |
68 | 70 | end |
69 | | - end |
70 | | - |
71 | | - def acts_as_model(chats: :chats, chat_class: nil, chats_foreign_key: nil) |
72 | | - include RubyLLM::ActiveRecord::ModelMethods |
73 | | - |
74 | | - class_attribute :chats_association_name, :chat_class |
75 | | - |
76 | | - self.chats_association_name = chats |
77 | | - self.chat_class = (chat_class || chats.to_s.classify).to_s |
78 | | - |
79 | | - validates :model_id, presence: true, uniqueness: { scope: :provider } |
80 | | - validates :provider, presence: true |
81 | | - validates :name, presence: true |
82 | | - |
83 | | - has_many chats, class_name: self.chat_class, foreign_key: chats_foreign_key |
84 | | - |
85 | | - define_method :chats_association do |
86 | | - send(chats_association_name) |
| 71 | + |
| 72 | + def acts_as_model(chats: :chats, chat_class: nil, chats_foreign_key: nil) |
| 73 | + include RubyLLM::ActiveRecord::ModelMethods |
| 74 | + |
| 75 | + class_attribute :chats_association_name, :chat_class |
| 76 | + |
| 77 | + self.chats_association_name = chats |
| 78 | + self.chat_class = (chat_class || chats.to_s.classify).to_s |
| 79 | + |
| 80 | + validates :model_id, presence: true, uniqueness: { scope: :provider } |
| 81 | + validates :provider, presence: true |
| 82 | + validates :name, presence: true |
| 83 | + |
| 84 | + has_many chats, class_name: self.chat_class, foreign_key: chats_foreign_key |
| 85 | + |
| 86 | + define_method :chats_association do |
| 87 | + send(chats_association_name) |
| 88 | + end |
87 | 89 | end |
88 | | - end |
89 | | - |
90 | | - def acts_as_message(chat: :chat, chat_class: nil, chat_foreign_key: nil, touch_chat: false, # rubocop:disable Metrics/ParameterLists |
91 | | - tool_calls: :tool_calls, tool_call_class: nil, tool_calls_foreign_key: nil, |
92 | | - model: :model, model_class: nil, model_foreign_key: nil) |
93 | | - include RubyLLM::ActiveRecord::MessageMethods |
94 | | - |
95 | | - class_attribute :chat_association_name, :tool_calls_association_name, :model_association_name, |
96 | | - :chat_class, :tool_call_class, :model_class |
97 | | - |
98 | | - self.chat_association_name = chat |
99 | | - self.tool_calls_association_name = tool_calls |
100 | | - self.model_association_name = model |
101 | | - self.chat_class = (chat_class || chat.to_s.classify).to_s |
102 | | - self.tool_call_class = (tool_call_class || tool_calls.to_s.classify).to_s |
103 | | - self.model_class = (model_class || model.to_s.classify).to_s |
104 | | - |
105 | | - belongs_to chat, |
106 | | - class_name: self.chat_class, |
107 | | - foreign_key: chat_foreign_key, |
108 | | - touch: touch_chat |
109 | | - |
110 | | - has_many tool_calls, |
111 | | - class_name: self.tool_call_class, |
112 | | - foreign_key: tool_calls_foreign_key, |
113 | | - dependent: :destroy |
114 | | - |
115 | | - belongs_to :parent_tool_call, |
| 90 | + |
| 91 | + def acts_as_message(chat: :chat, chat_class: nil, chat_foreign_key: nil, touch_chat: false, # rubocop:disable Metrics/ParameterLists |
| 92 | + tool_calls: :tool_calls, tool_call_class: nil, tool_calls_foreign_key: nil, |
| 93 | + model: :model, model_class: nil, model_foreign_key: nil) |
| 94 | + include RubyLLM::ActiveRecord::MessageMethods |
| 95 | + |
| 96 | + class_attribute :chat_association_name, :tool_calls_association_name, :model_association_name, |
| 97 | + :chat_class, :tool_call_class, :model_class |
| 98 | + |
| 99 | + self.chat_association_name = chat |
| 100 | + self.tool_calls_association_name = tool_calls |
| 101 | + self.model_association_name = model |
| 102 | + self.chat_class = (chat_class || chat.to_s.classify).to_s |
| 103 | + self.tool_call_class = (tool_call_class || tool_calls.to_s.classify).to_s |
| 104 | + self.model_class = (model_class || model.to_s.classify).to_s |
| 105 | + |
| 106 | + belongs_to chat, |
| 107 | + class_name: self.chat_class, |
| 108 | + foreign_key: chat_foreign_key, |
| 109 | + touch: touch_chat |
| 110 | + |
| 111 | + has_many tool_calls, |
116 | 112 | class_name: self.tool_call_class, |
117 | | - foreign_key: ActiveSupport::Inflector.foreign_key(tool_calls.to_s.singularize), |
118 | | - optional: true |
119 | | - |
120 | | - has_many :tool_results, |
121 | | - through: tool_calls, |
122 | | - source: :result, |
123 | | - class_name: name |
124 | | - |
125 | | - belongs_to model, |
126 | | - class_name: self.model_class, |
127 | | - foreign_key: model_foreign_key, |
128 | | - optional: true |
129 | | - |
130 | | - delegate :tool_call?, :tool_result?, to: :to_llm |
131 | | - |
132 | | - define_method :chat_association do |
133 | | - send(chat_association_name) |
134 | | - end |
135 | | - |
136 | | - define_method :tool_calls_association do |
137 | | - send(tool_calls_association_name) |
138 | | - end |
139 | | - |
140 | | - define_method :model_association do |
141 | | - send(model_association_name) |
142 | | - end |
143 | | - end |
144 | | - |
145 | | - def acts_as_tool_call(message: :message, message_class: nil, message_foreign_key: nil, # rubocop:disable Metrics/ParameterLists |
146 | | - result: :result, result_class: nil, result_foreign_key: nil) |
147 | | - class_attribute :message_association_name, :result_association_name, :message_class, :result_class |
148 | | - |
149 | | - self.message_association_name = message |
150 | | - self.result_association_name = result |
151 | | - self.message_class = (message_class || message.to_s.classify).to_s |
152 | | - self.result_class = (result_class || self.message_class).to_s |
153 | | - |
154 | | - belongs_to message, |
155 | | - class_name: self.message_class, |
156 | | - foreign_key: message_foreign_key |
157 | | - |
158 | | - has_one result, |
159 | | - class_name: self.result_class, |
160 | | - foreign_key: result_foreign_key, |
161 | | - dependent: :nullify |
162 | | - |
163 | | - define_method :message_association do |
164 | | - send(message_association_name) |
| 113 | + foreign_key: tool_calls_foreign_key, |
| 114 | + dependent: :destroy |
| 115 | + |
| 116 | + belongs_to :parent_tool_call, |
| 117 | + class_name: self.tool_call_class, |
| 118 | + foreign_key: ActiveSupport::Inflector.foreign_key(tool_calls.to_s.singularize), |
| 119 | + optional: true |
| 120 | + |
| 121 | + has_many :tool_results, |
| 122 | + through: tool_calls, |
| 123 | + source: :result, |
| 124 | + class_name: name |
| 125 | + |
| 126 | + belongs_to model, |
| 127 | + class_name: self.model_class, |
| 128 | + foreign_key: model_foreign_key, |
| 129 | + optional: true |
| 130 | + |
| 131 | + delegate :tool_call?, :tool_result?, to: :to_llm |
| 132 | + |
| 133 | + define_method :chat_association do |
| 134 | + send(chat_association_name) |
| 135 | + end |
| 136 | + |
| 137 | + define_method :tool_calls_association do |
| 138 | + send(tool_calls_association_name) |
| 139 | + end |
| 140 | + |
| 141 | + define_method :model_association do |
| 142 | + send(model_association_name) |
| 143 | + end |
165 | 144 | end |
166 | | - |
167 | | - define_method :result_association do |
168 | | - send(result_association_name) |
| 145 | + |
| 146 | + def acts_as_tool_call(message: :message, message_class: nil, message_foreign_key: nil, # rubocop:disable Metrics/ParameterLists |
| 147 | + result: :result, result_class: nil, result_foreign_key: nil) |
| 148 | + class_attribute :message_association_name, :result_association_name, :message_class, :result_class |
| 149 | + |
| 150 | + self.message_association_name = message |
| 151 | + self.result_association_name = result |
| 152 | + self.message_class = (message_class || message.to_s.classify).to_s |
| 153 | + self.result_class = (result_class || self.message_class).to_s |
| 154 | + |
| 155 | + belongs_to message, |
| 156 | + class_name: self.message_class, |
| 157 | + foreign_key: message_foreign_key |
| 158 | + |
| 159 | + has_one result, |
| 160 | + class_name: self.result_class, |
| 161 | + foreign_key: result_foreign_key, |
| 162 | + dependent: :nullify |
| 163 | + |
| 164 | + define_method :message_association do |
| 165 | + send(message_association_name) |
| 166 | + end |
| 167 | + |
| 168 | + define_method :result_association do |
| 169 | + send(result_association_name) |
| 170 | + end |
169 | 171 | end |
170 | 172 | end |
171 | 173 | end |
|
0 commit comments