ruby_llm 1.12.0 → 1.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/ruby_llm/active_record/acts_as.rb +0 -2
- data/lib/ruby_llm/active_record/acts_as_legacy.rb +56 -20
- data/lib/ruby_llm/active_record/chat_methods.rb +32 -12
- data/lib/ruby_llm/agent.rb +6 -3
- data/lib/ruby_llm/content.rb +6 -0
- data/lib/ruby_llm/version.rb +1 -1
- metadata +5 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6f2aa1f16058fca83243f2b098b0a3f454fb9383e410a00b04955cd5b48cbf54
|
|
4
|
+
data.tar.gz: fb4591fe16b50449dc1baf90f77a2b92baa986a51b9573f5c0b79dc231d9a9b9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 687200d2c127d604e0bbff56c888ef5bb5ab2938b585ec2f8959f77b74ad35ae0d0dbad588068ccccd3219ab0aa4208dbc47b8436606c7b12ec1de10cf2928c2
|
|
7
|
+
data.tar.gz: 9aab7e7a79aa98b2772e4a01f4269c17a1969755276fde9b0fb4b3311a81dd4ff3a4a1e4e4c4a1f0fa863a162caaa4f3d3cd05cc044cfc5116ceaaa878963737
|
|
@@ -18,8 +18,6 @@ module RubyLLM
|
|
|
18
18
|
class_name: @message_class,
|
|
19
19
|
inverse_of: :chat,
|
|
20
20
|
dependent: :destroy
|
|
21
|
-
|
|
22
|
-
delegate :add_message, to: :to_llm
|
|
23
21
|
end
|
|
24
22
|
|
|
25
23
|
def acts_as_message(chat_class: 'Chat',
|
|
@@ -185,14 +183,34 @@ module RubyLLM
|
|
|
185
183
|
self
|
|
186
184
|
end
|
|
187
185
|
|
|
188
|
-
def
|
|
189
|
-
|
|
190
|
-
|
|
186
|
+
def add_message(message_or_attributes)
|
|
187
|
+
llm_message = message_or_attributes.is_a?(RubyLLM::Message) ? message_or_attributes : RubyLLM::Message.new(message_or_attributes)
|
|
188
|
+
content, attachments_to_persist = prepare_content_for_storage(llm_message.content)
|
|
189
|
+
|
|
190
|
+
attrs = { role: llm_message.role, content: }
|
|
191
|
+
tool_call_foreign_key = messages.klass.tool_call_foreign_key
|
|
192
|
+
if llm_message.tool_call_id && tool_call_foreign_key
|
|
193
|
+
tool_call_id = find_tool_call_id(llm_message.tool_call_id)
|
|
194
|
+
attrs[tool_call_foreign_key] = tool_call_id if tool_call_id
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
message_record = messages.create!(attrs)
|
|
198
|
+
persist_content(message_record, attachments_to_persist) if attachments_to_persist.present?
|
|
199
|
+
persist_tool_calls(llm_message.tool_calls, message_record:) if llm_message.tool_calls.present?
|
|
200
|
+
|
|
191
201
|
message_record
|
|
192
202
|
end
|
|
193
203
|
|
|
194
|
-
def
|
|
195
|
-
|
|
204
|
+
def create_user_message(content, with: nil)
|
|
205
|
+
RubyLLM.logger.warn(
|
|
206
|
+
'`create_user_message` is deprecated and will be removed in RubyLLM 2.0. ' \
|
|
207
|
+
'Use `add_message(role: :user, content: ...)` instead.'
|
|
208
|
+
)
|
|
209
|
+
add_message(role: :user, content: build_content(content, with))
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def ask(message = nil, with: nil, &)
|
|
213
|
+
add_message(role: :user, content: build_content(message, with))
|
|
196
214
|
complete(&)
|
|
197
215
|
end
|
|
198
216
|
|
|
@@ -281,21 +299,13 @@ module RubyLLM
|
|
|
281
299
|
@message = messages.create!(role: :assistant, content: '')
|
|
282
300
|
end
|
|
283
301
|
|
|
284
|
-
def persist_message_completion(message)
|
|
302
|
+
def persist_message_completion(message)
|
|
285
303
|
return unless message
|
|
286
304
|
|
|
287
305
|
tool_call_id = find_tool_call_id(message.tool_call_id) if message.tool_call_id
|
|
288
306
|
|
|
289
307
|
transaction do
|
|
290
|
-
content = message.content
|
|
291
|
-
attachments_to_persist = nil
|
|
292
|
-
|
|
293
|
-
if content.is_a?(RubyLLM::Content)
|
|
294
|
-
attachments_to_persist = content.attachments if content.attachments.any?
|
|
295
|
-
content = content.text
|
|
296
|
-
elsif content.is_a?(Hash) || content.is_a?(Array)
|
|
297
|
-
content = content.to_json
|
|
298
|
-
end
|
|
308
|
+
content, attachments_to_persist = prepare_content_for_storage(message.content)
|
|
299
309
|
|
|
300
310
|
@message.update!(
|
|
301
311
|
role: message.role,
|
|
@@ -312,14 +322,17 @@ module RubyLLM
|
|
|
312
322
|
end
|
|
313
323
|
end
|
|
314
324
|
|
|
315
|
-
def persist_tool_calls(tool_calls)
|
|
316
|
-
|
|
325
|
+
def persist_tool_calls(tool_calls, message_record: @message)
|
|
326
|
+
tool_call_assoc = message_record.respond_to?(:tool_calls) ? message_record.tool_calls : nil
|
|
327
|
+
return unless tool_call_assoc
|
|
328
|
+
|
|
329
|
+
supports_thought_signature = tool_call_assoc.klass.column_names.include?('thought_signature')
|
|
317
330
|
|
|
318
331
|
tool_calls.each_value do |tool_call|
|
|
319
332
|
attributes = tool_call.to_h
|
|
320
333
|
attributes.delete(:thought_signature) unless supports_thought_signature
|
|
321
334
|
attributes[:tool_call_id] = attributes.delete(:id)
|
|
322
|
-
|
|
335
|
+
tool_call_assoc.create!(**attributes)
|
|
323
336
|
end
|
|
324
337
|
end
|
|
325
338
|
|
|
@@ -363,6 +376,29 @@ module RubyLLM
|
|
|
363
376
|
RubyLLM.logger.warn "Failed to process attachment #{source}: #{e.message}"
|
|
364
377
|
nil
|
|
365
378
|
end
|
|
379
|
+
|
|
380
|
+
def build_content(message, attachments)
|
|
381
|
+
return message if content_like?(message)
|
|
382
|
+
|
|
383
|
+
RubyLLM::Content.new(message, attachments)
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
def content_like?(object)
|
|
387
|
+
object.is_a?(RubyLLM::Content) || object.is_a?(RubyLLM::Content::Raw)
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
def prepare_content_for_storage(content)
|
|
391
|
+
attachments = nil
|
|
392
|
+
|
|
393
|
+
if content.is_a?(RubyLLM::Content)
|
|
394
|
+
attachments = content.attachments if content.attachments.any?
|
|
395
|
+
[content.text, attachments]
|
|
396
|
+
elsif content.is_a?(Hash) || content.is_a?(Array)
|
|
397
|
+
[content.to_json, attachments]
|
|
398
|
+
else
|
|
399
|
+
[content, attachments]
|
|
400
|
+
end
|
|
401
|
+
end
|
|
366
402
|
end
|
|
367
403
|
|
|
368
404
|
# Methods mixed into message models.
|
|
@@ -178,22 +178,32 @@ module RubyLLM
|
|
|
178
178
|
self
|
|
179
179
|
end
|
|
180
180
|
|
|
181
|
-
def
|
|
182
|
-
|
|
181
|
+
def add_message(message_or_attributes)
|
|
182
|
+
llm_message = message_or_attributes.is_a?(RubyLLM::Message) ? message_or_attributes : RubyLLM::Message.new(message_or_attributes)
|
|
183
|
+
content_text, attachments, content_raw = prepare_content_for_storage(llm_message.content)
|
|
184
|
+
|
|
185
|
+
attrs = { role: llm_message.role, content: content_text }
|
|
186
|
+
parent_tool_call_assoc = messages_association.klass.reflect_on_association(:parent_tool_call)
|
|
187
|
+
if parent_tool_call_assoc && llm_message.tool_call_id
|
|
188
|
+
tool_call_id = find_tool_call_id(llm_message.tool_call_id)
|
|
189
|
+
attrs[parent_tool_call_assoc.foreign_key] = tool_call_id if tool_call_id
|
|
190
|
+
end
|
|
183
191
|
|
|
184
|
-
message_record = messages_association.
|
|
185
|
-
message_record.
|
|
186
|
-
message_record.content_raw = content_raw if message_record.respond_to?(:content_raw=)
|
|
187
|
-
message_record.save!
|
|
192
|
+
message_record = messages_association.create!(attrs)
|
|
193
|
+
message_record.update!(content_raw:) if message_record.respond_to?(:content_raw=)
|
|
188
194
|
|
|
189
|
-
persist_content(message_record, with) if with.present?
|
|
190
195
|
persist_content(message_record, attachments) if attachments.present?
|
|
196
|
+
persist_tool_calls(llm_message.tool_calls, message_record:) if llm_message.tool_calls.present?
|
|
191
197
|
|
|
192
198
|
message_record
|
|
193
199
|
end
|
|
194
200
|
|
|
195
|
-
def
|
|
196
|
-
|
|
201
|
+
def create_user_message(content, with: nil)
|
|
202
|
+
add_message(role: :user, content: build_content(content, with))
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def ask(message = nil, with: nil, &)
|
|
206
|
+
add_message(role: :user, content: build_content(message, with))
|
|
197
207
|
complete(&)
|
|
198
208
|
end
|
|
199
209
|
|
|
@@ -323,15 +333,15 @@ module RubyLLM
|
|
|
323
333
|
end
|
|
324
334
|
# rubocop:enable Metrics/PerceivedComplexity
|
|
325
335
|
|
|
326
|
-
def persist_tool_calls(tool_calls)
|
|
327
|
-
tool_call_klass =
|
|
336
|
+
def persist_tool_calls(tool_calls, message_record: @message)
|
|
337
|
+
tool_call_klass = message_record.tool_calls_association.klass
|
|
328
338
|
supports_thought_signature = tool_call_klass.column_names.include?('thought_signature')
|
|
329
339
|
|
|
330
340
|
tool_calls.each_value do |tool_call|
|
|
331
341
|
attributes = tool_call.to_h
|
|
332
342
|
attributes.delete(:thought_signature) unless supports_thought_signature
|
|
333
343
|
attributes[:tool_call_id] = attributes.delete(:id)
|
|
334
|
-
|
|
344
|
+
message_record.tool_calls_association.create!(**attributes)
|
|
335
345
|
end
|
|
336
346
|
end
|
|
337
347
|
|
|
@@ -386,6 +396,16 @@ module RubyLLM
|
|
|
386
396
|
nil
|
|
387
397
|
end
|
|
388
398
|
|
|
399
|
+
def build_content(message, attachments)
|
|
400
|
+
return message if content_like?(message)
|
|
401
|
+
|
|
402
|
+
RubyLLM::Content.new(message, attachments)
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
def content_like?(object)
|
|
406
|
+
object.is_a?(RubyLLM::Content) || object.is_a?(RubyLLM::Content::Raw)
|
|
407
|
+
end
|
|
408
|
+
|
|
389
409
|
def prepare_content_for_storage(content)
|
|
390
410
|
attachments = nil
|
|
391
411
|
content_raw = nil
|
data/lib/ruby_llm/agent.rb
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'erb'
|
|
4
|
+
require 'forwardable'
|
|
4
5
|
require 'pathname'
|
|
5
6
|
|
|
6
7
|
module RubyLLM
|
|
7
8
|
# Base class for simple, class-configured agents.
|
|
8
9
|
class Agent
|
|
10
|
+
extend Forwardable
|
|
9
11
|
include Enumerable
|
|
10
12
|
|
|
11
13
|
class << self
|
|
@@ -316,8 +318,9 @@ module RubyLLM
|
|
|
316
318
|
|
|
317
319
|
attr_reader :chat
|
|
318
320
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
321
|
+
def_delegators :chat, :model, :messages, :tools, :params, :headers, :schema, :ask, :say, :with_tool, :with_tools,
|
|
322
|
+
:with_model, :with_temperature, :with_thinking, :with_context, :with_params, :with_headers,
|
|
323
|
+
:with_schema, :on_new_message, :on_end_message, :on_tool_call, :on_tool_result, :each, :complete,
|
|
324
|
+
:add_message, :reset_messages!
|
|
322
325
|
end
|
|
323
326
|
end
|
data/lib/ruby_llm/content.rb
CHANGED
|
@@ -35,10 +35,16 @@ module RubyLLM
|
|
|
35
35
|
|
|
36
36
|
def process_attachments_array_or_string(attachments)
|
|
37
37
|
Utils.to_safe_array(attachments).each do |file|
|
|
38
|
+
next if blank_attachment_entry?(file)
|
|
39
|
+
|
|
38
40
|
add_attachment(file)
|
|
39
41
|
end
|
|
40
42
|
end
|
|
41
43
|
|
|
44
|
+
def blank_attachment_entry?(file)
|
|
45
|
+
file.nil? || (file.is_a?(String) && file.strip.empty?)
|
|
46
|
+
end
|
|
47
|
+
|
|
42
48
|
def process_attachments(attachments)
|
|
43
49
|
if attachments.is_a?(Hash)
|
|
44
50
|
attachments.each_value { |attachment| process_attachments_array_or_string(attachment) }
|
data/lib/ruby_llm/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ruby_llm
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.12.
|
|
4
|
+
version: 1.12.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Carmine Paolino
|
|
@@ -99,28 +99,28 @@ dependencies:
|
|
|
99
99
|
requirements:
|
|
100
100
|
- - "~>"
|
|
101
101
|
- !ruby/object:Gem::Version
|
|
102
|
-
version: '1
|
|
102
|
+
version: '1'
|
|
103
103
|
type: :runtime
|
|
104
104
|
prerelease: false
|
|
105
105
|
version_requirements: !ruby/object:Gem::Requirement
|
|
106
106
|
requirements:
|
|
107
107
|
- - "~>"
|
|
108
108
|
- !ruby/object:Gem::Version
|
|
109
|
-
version: '1
|
|
109
|
+
version: '1'
|
|
110
110
|
- !ruby/object:Gem::Dependency
|
|
111
111
|
name: ruby_llm-schema
|
|
112
112
|
requirement: !ruby/object:Gem::Requirement
|
|
113
113
|
requirements:
|
|
114
114
|
- - "~>"
|
|
115
115
|
- !ruby/object:Gem::Version
|
|
116
|
-
version: 0
|
|
116
|
+
version: '0'
|
|
117
117
|
type: :runtime
|
|
118
118
|
prerelease: false
|
|
119
119
|
version_requirements: !ruby/object:Gem::Requirement
|
|
120
120
|
requirements:
|
|
121
121
|
- - "~>"
|
|
122
122
|
- !ruby/object:Gem::Version
|
|
123
|
-
version: 0
|
|
123
|
+
version: '0'
|
|
124
124
|
- !ruby/object:Gem::Dependency
|
|
125
125
|
name: zeitwerk
|
|
126
126
|
requirement: !ruby/object:Gem::Requirement
|