Module: RubyLLM::ActiveRecord::ChatMethods

Extended by:
ActiveSupport::Concern
Defined in:
lib/ruby_llm/active_record/chat_methods.rb

Overview

Methods mixed into chat models.

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#assume_model_existsObject

Returns the value of attribute assume_model_exists.



15
16
17
# File 'lib/ruby_llm/active_record/chat_methods.rb', line 15

def assume_model_exists
  @assume_model_exists
end

#contextObject

Returns the value of attribute context.



15
16
17
# File 'lib/ruby_llm/active_record/chat_methods.rb', line 15

def context
  @context
end

Instance Method Details

#add_message(message_or_attributes) ⇒ Object



199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/ruby_llm/active_record/chat_methods.rb', line 199

def add_message(message_or_attributes)
  llm_message = message_or_attributes.is_a?(RubyLLM::Message) ? message_or_attributes : RubyLLM::Message.new(message_or_attributes)
  content_text, attachments, content_raw = prepare_content_for_storage(llm_message.content)

  attrs = { role: llm_message.role, content: content_text }
  parent_tool_call_assoc = messages_association.klass.reflect_on_association(:parent_tool_call)
  if parent_tool_call_assoc && llm_message.tool_call_id
    tool_call_id = find_tool_call_id(llm_message.tool_call_id)
    attrs[parent_tool_call_assoc.foreign_key] = tool_call_id if tool_call_id
  end

  message_record = messages_association.create!(attrs)
  message_record.update!(content_raw:) if message_record.respond_to?(:content_raw=)

  persist_content(message_record, attachments) if attachments.present?
  persist_tool_calls(llm_message.tool_calls, message_record:) if llm_message.tool_calls.present?

  message_record
end

#after_messageObject



174
175
176
177
# File 'lib/ruby_llm/active_record/chat_methods.rb', line 174

def after_message(...)
  to_llm.after_message(...)
  self
end

#after_tool_resultObject



184
185
186
187
# File 'lib/ruby_llm/active_record/chat_methods.rb', line 184

def after_tool_result(...)
  to_llm.after_tool_result(...)
  self
end

#ask(message = nil, with: nil) ⇒ Object Also known as: say



227
228
229
230
# File 'lib/ruby_llm/active_record/chat_methods.rb', line 227

def ask(message = nil, with: nil, &)
  add_message(role: :user, content: build_content(message, with))
  complete(&)
end

#before_messageObject



169
170
171
172
# File 'lib/ruby_llm/active_record/chat_methods.rb', line 169

def before_message(...)
  to_llm.before_message(...)
  self
end

#before_tool_callObject



179
180
181
182
# File 'lib/ruby_llm/active_record/chat_methods.rb', line 179

def before_tool_call(...)
  to_llm.before_tool_call(...)
  self
end

#completeObject



234
235
236
237
238
239
240
# File 'lib/ruby_llm/active_record/chat_methods.rb', line 234

def complete(...)
  to_llm.complete(...)
rescue RubyLLM::Error => e
  cleanup_failed_messages if @message&.persisted? && @message.content.blank?
  cleanup_orphaned_tool_results
  raise e
end

#costObject



219
220
221
# File 'lib/ruby_llm/active_record/chat_methods.rb', line 219

def cost
  RubyLLM::Cost.aggregate(messages_association.map(&:cost))
end

#create_user_message(content, with: nil) ⇒ Object



223
224
225
# File 'lib/ruby_llm/active_record/chat_methods.rb', line 223

def create_user_message(content, with: nil)
  add_message(role: :user, content: build_content(content, with))
end

#model=(value) ⇒ Object



17
18
19
20
21
22
23
24
25
26
# File 'lib/ruby_llm/active_record/chat_methods.rb', line 17

def model=(value)
  @model_string = value if value.is_a?(String)
  return if value.is_a?(String)

  if self.class.model_association_name == :model
    super
  else
    self.model_association = value
  end
end

#model_idObject



32
33
34
# File 'lib/ruby_llm/active_record/chat_methods.rb', line 32

def model_id
  model_association&.model_id
end

#model_id=(value) ⇒ Object



28
29
30
# File 'lib/ruby_llm/active_record/chat_methods.rb', line 28

def model_id=(value)
  @model_string = value
end

#on_end_messageObject



164
165
166
167
# File 'lib/ruby_llm/active_record/chat_methods.rb', line 164

def on_end_message(&)
  to_llm.on_end_message(&)
  self
end

#on_new_messageObject



159
160
161
162
# File 'lib/ruby_llm/active_record/chat_methods.rb', line 159

def on_new_message(&)
  to_llm.on_new_message(&)
  self
end

#on_tool_callObject



189
190
191
192
# File 'lib/ruby_llm/active_record/chat_methods.rb', line 189

def on_tool_call(...)
  to_llm.on_tool_call(...)
  self
end

#on_tool_resultObject



194
195
196
197
# File 'lib/ruby_llm/active_record/chat_methods.rb', line 194

def on_tool_result(...)
  to_llm.on_tool_result(...)
  self
end

#providerObject



40
41
42
# File 'lib/ruby_llm/active_record/chat_methods.rb', line 40

def provider
  model_association&.provider
end

#provider=(value) ⇒ Object



36
37
38
# File 'lib/ruby_llm/active_record/chat_methods.rb', line 36

def provider=(value)
  @provider_string = value
end

#to_llmObject



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/ruby_llm/active_record/chat_methods.rb', line 80

def to_llm
  model_record = model_association
  @chat ||= (context || RubyLLM).chat(
    model: model_record.model_id,
    provider: model_record.provider.to_sym,
    assume_model_exists: assume_model_exists || false
  )
  @chat.reset_messages!

  ordered_messages = order_messages_for_llm(messages_association.to_a)
  ordered_messages.each do |msg|
    @chat.add_message(msg.to_llm)
  end
  reapply_runtime_instructions(@chat)

  setup_persistence_callbacks
end

#with_headersObject



149
150
151
152
# File 'lib/ruby_llm/active_record/chat_methods.rb', line 149

def with_headers(...)
  to_llm.with_headers(...)
  self
end

#with_instructions(instructions, append: false, replace: nil) ⇒ Object



98
99
100
101
102
103
104
# File 'lib/ruby_llm/active_record/chat_methods.rb', line 98

def with_instructions(instructions, append: false, replace: nil)
  append = append_instructions?(append:, replace:)
  persist_system_instruction(instructions, append:)

  to_llm.with_instructions(instructions, append:, replace:)
  self
end

#with_model(model_name, provider: nil, assume_exists: false) ⇒ Object



124
125
126
127
128
129
130
131
132
# File 'lib/ruby_llm/active_record/chat_methods.rb', line 124

def with_model(model_name, provider: nil, assume_exists: false)
  self.model = model_name
  self.provider = provider if provider
  self.assume_model_exists = assume_exists
  resolve_model_from_strings
  save!
  to_llm.with_model(model_association.model_id, provider: model_association.provider.to_sym, assume_exists:)
  self
end

#with_paramsObject



144
145
146
147
# File 'lib/ruby_llm/active_record/chat_methods.rb', line 144

def with_params(...)
  to_llm.with_params(...)
  self
end

#with_runtime_instructions(instructions, append: false, replace: nil) ⇒ Object



106
107
108
109
110
111
112
# File 'lib/ruby_llm/active_record/chat_methods.rb', line 106

def with_runtime_instructions(instructions, append: false, replace: nil)
  append = append_instructions?(append:, replace:)
  store_runtime_instruction(instructions, append:)

  to_llm.with_instructions(instructions, append:, replace:)
  self
end

#with_schemaObject



154
155
156
157
# File 'lib/ruby_llm/active_record/chat_methods.rb', line 154

def with_schema(...)
  to_llm.with_schema(...)
  self
end

#with_temperatureObject



134
135
136
137
# File 'lib/ruby_llm/active_record/chat_methods.rb', line 134

def with_temperature(...)
  to_llm.with_temperature(...)
  self
end

#with_thinkingObject



139
140
141
142
# File 'lib/ruby_llm/active_record/chat_methods.rb', line 139

def with_thinking(...)
  to_llm.with_thinking(...)
  self
end

#with_toolObject



114
115
116
117
# File 'lib/ruby_llm/active_record/chat_methods.rb', line 114

def with_tool(...)
  to_llm.with_tool(...)
  self
end

#with_toolsObject



119
120
121
122
# File 'lib/ruby_llm/active_record/chat_methods.rb', line 119

def with_tools(...)
  to_llm.with_tools(...)
  self
end