ruby_llm 1.9.0 → 1.9.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: af7f86a7a466d3632083cb3a0b08f463ff140ccb81125ca2a0cdbe9e07c987aa
4
- data.tar.gz: 38e08d2bed60f094117c1649c405026101a7205ee47d55833957231874e3b751
3
+ metadata.gz: 608fe5c960367e570a076fc956c9deed5232f289ede88971ad9f98c312a63c81
4
+ data.tar.gz: e402cce6a24c53ac98d0ae956e3f508664b08ceb35c02a3f228659e41735b7ed
5
5
  SHA512:
6
- metadata.gz: 1391c4a44df215cee71c7458923e7bcc4e883a1e883cdcba42355bab3b7f76f6f8e82e33b9cc9b7b1c06e4d15c65fcff9822cee75477f2ac7cb53076abed9f4c
7
- data.tar.gz: 04cbf69517185e7b6da978ae9625421553258baef325a93cbc73d243cd14cc178a556f8531946a073f77e150bd519e79eeccf1c1dbb5e53826587f28e56051eb
6
+ metadata.gz: a63d7a0f9d78ce884ee4da47ee758dadda1436ce831a5e3386652f297355b656ffe5f49ab20dc89e2773d87482d6d7b83e8b06fa1912aca5c5e7c56724558791
7
+ data.tar.gz: 4437db6a16721f689f1a0adc8a880a9a83fcf177a16856a50df012bffe088fb1de304218daeaa396ad1b88b8c68883eede8d1bee71c4b7da4f70a44d0b0428ee
@@ -52,8 +52,10 @@ module RubyLLM
52
52
  def acts_as_chat_declaration
53
53
  params = []
54
54
 
55
- add_association_params(params, :messages, message_table_name, message_model_name, plural: true)
56
- add_association_params(params, :model, model_table_name, model_model_name)
55
+ add_association_params(params, :messages, message_table_name, message_model_name,
56
+ owner_table: chat_table_name, plural: true)
57
+ add_association_params(params, :model, model_table_name, model_model_name,
58
+ owner_table: chat_table_name)
57
59
 
58
60
  "acts_as_chat#{" #{params.join(', ')}" if params.any?}"
59
61
  end
@@ -61,9 +63,12 @@ module RubyLLM
61
63
  def acts_as_message_declaration
62
64
  params = []
63
65
 
64
- add_association_params(params, :chat, chat_table_name, chat_model_name)
65
- add_association_params(params, :tool_calls, tool_call_table_name, tool_call_model_name, plural: true)
66
- add_association_params(params, :model, model_table_name, model_model_name)
66
+ add_association_params(params, :chat, chat_table_name, chat_model_name,
67
+ owner_table: message_table_name)
68
+ add_association_params(params, :tool_calls, tool_call_table_name, tool_call_model_name,
69
+ owner_table: message_table_name, plural: true)
70
+ add_association_params(params, :model, model_table_name, model_model_name,
71
+ owner_table: message_table_name)
67
72
 
68
73
  "acts_as_message#{" #{params.join(', ')}" if params.any?}"
69
74
  end
@@ -71,7 +76,8 @@ module RubyLLM
71
76
  def acts_as_model_declaration
72
77
  params = []
73
78
 
74
- add_association_params(params, :chats, chat_table_name, chat_model_name, plural: true)
79
+ add_association_params(params, :chats, chat_table_name, chat_model_name,
80
+ owner_table: model_table_name, plural: true)
75
81
 
76
82
  "acts_as_model#{" #{params.join(', ')}" if params.any?}"
77
83
  end
@@ -79,7 +85,8 @@ module RubyLLM
79
85
  def acts_as_tool_call_declaration
80
86
  params = []
81
87
 
82
- add_association_params(params, :message, message_table_name, message_model_name)
88
+ add_association_params(params, :message, message_table_name, message_model_name,
89
+ owner_table: tool_call_table_name)
83
90
 
84
91
  "acts_as_tool_call#{" #{params.join(', ')}" if params.any?}"
85
92
  end
@@ -120,6 +127,12 @@ module RubyLLM
120
127
  false
121
128
  end
122
129
 
130
+ def mysql?
131
+ ::ActiveRecord::Base.connection.adapter_name.downcase.include?('mysql')
132
+ rescue StandardError
133
+ false
134
+ end
135
+
123
136
  def table_exists?(table_name)
124
137
  ::ActiveRecord::Base.connection.table_exists?(table_name)
125
138
  rescue StandardError
@@ -128,13 +141,21 @@ module RubyLLM
128
141
 
129
142
  private
130
143
 
131
- def add_association_params(params, default_assoc, table_name, model_name, plural: false)
144
+ def add_association_params(params, default_assoc, table_name, model_name, owner_table:, plural: false) # rubocop:disable Metrics/ParameterLists
132
145
  assoc = plural ? table_name.to_sym : table_name.singularize.to_sym
133
146
 
134
- return if assoc == default_assoc
147
+ default_foreign_key = "#{default_assoc}_id"
148
+ # has_many/has_one: foreign key is on the associated table pointing back to owner
149
+ # belongs_to: foreign key is on the owner table pointing to associated table
150
+ foreign_key = if plural || default_assoc.to_s.pluralize == default_assoc.to_s # has_many or has_one
151
+ "#{owner_table.singularize}_id"
152
+ else # belongs_to
153
+ "#{table_name.singularize}_id"
154
+ end
135
155
 
136
- params << "#{default_assoc}: :#{assoc}"
156
+ params << "#{default_assoc}: :#{assoc}" if assoc != default_assoc
137
157
  params << "#{default_assoc.to_s.singularize}_class: '#{model_name}'" if model_name != assoc.to_s.classify
158
+ params << "#{default_assoc}_foreign_key: :#{foreign_key}" if foreign_key != default_foreign_key
138
159
  end
139
160
 
140
161
  # Convert namespaced model names to proper table names
@@ -14,6 +14,11 @@ class Create<%= model_model_name.gsub('::', '').pluralize %> < ActiveRecord::Mig
14
14
  t.jsonb :capabilities, default: []
15
15
  t.jsonb :pricing, default: {}
16
16
  t.jsonb :metadata, default: {}
17
+ <% elsif mysql? %>
18
+ t.json :modalities
19
+ t.json :capabilities
20
+ t.json :pricing
21
+ t.json :metadata
17
22
  <% else %>
18
23
  t.json :modalities, default: {}
19
24
  t.json :capabilities, default: []
@@ -4,7 +4,13 @@ class Create<%= tool_call_model_name.gsub('::', '').pluralize %> < ActiveRecord:
4
4
  create_table :<%= tool_call_table_name %> do |t|
5
5
  t.string :tool_call_id, null: false
6
6
  t.string :name, null: false
7
- t.<%= postgresql? ? 'jsonb' : 'json' %> :arguments, default: {}
7
+ <% if postgresql? %>
8
+ t.jsonb :arguments, default: {}
9
+ <% elsif mysql? %>
10
+ t.json :arguments
11
+ <% else %>
12
+ t.json :arguments, default: {}
13
+ <% end %>
8
14
  t.timestamps
9
15
  end
10
16
 
@@ -31,8 +31,8 @@ module RubyLLM
31
31
  end
32
32
 
33
33
  class_methods do # rubocop:disable Metrics/BlockLength
34
- def acts_as_chat(messages: :messages, message_class: nil,
35
- model: :model, model_class: nil)
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
36
  include RubyLLM::ActiveRecord::ChatMethods
37
37
 
38
38
  class_attribute :messages_association_name, :model_association_name, :message_class, :model_class
@@ -45,12 +45,12 @@ module RubyLLM
45
45
  has_many messages,
46
46
  -> { order(created_at: :asc) },
47
47
  class_name: self.message_class,
48
- foreign_key: ActiveSupport::Inflector.foreign_key(table_name.singularize),
48
+ foreign_key: messages_foreign_key,
49
49
  dependent: :destroy
50
50
 
51
51
  belongs_to model,
52
52
  class_name: self.model_class,
53
- foreign_key: ActiveSupport::Inflector.foreign_key(model.to_s.singularize),
53
+ foreign_key: model_foreign_key,
54
54
  optional: true
55
55
 
56
56
  delegate :add_message, to: :to_llm
@@ -68,7 +68,7 @@ module RubyLLM
68
68
  end
69
69
  end
70
70
 
71
- def acts_as_model(chats: :chats, chat_class: nil)
71
+ def acts_as_model(chats: :chats, chat_class: nil, chats_foreign_key: nil)
72
72
  include RubyLLM::ActiveRecord::ModelMethods
73
73
 
74
74
  class_attribute :chats_association_name, :chat_class
@@ -80,18 +80,16 @@ module RubyLLM
80
80
  validates :provider, presence: true
81
81
  validates :name, presence: true
82
82
 
83
- has_many chats,
84
- class_name: self.chat_class,
85
- foreign_key: ActiveSupport::Inflector.foreign_key(table_name.singularize)
83
+ has_many chats, class_name: self.chat_class, foreign_key: chats_foreign_key
86
84
 
87
85
  define_method :chats_association do
88
86
  send(chats_association_name)
89
87
  end
90
88
  end
91
89
 
92
- def acts_as_message(chat: :chat, chat_class: nil, touch_chat: false, # rubocop:disable Metrics/ParameterLists
93
- tool_calls: :tool_calls, tool_call_class: nil,
94
- model: :model, model_class: nil)
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)
95
93
  include RubyLLM::ActiveRecord::MessageMethods
96
94
 
97
95
  class_attribute :chat_association_name, :tool_calls_association_name, :model_association_name,
@@ -106,12 +104,12 @@ module RubyLLM
106
104
 
107
105
  belongs_to chat,
108
106
  class_name: self.chat_class,
109
- foreign_key: ActiveSupport::Inflector.foreign_key(chat.to_s.singularize),
107
+ foreign_key: chat_foreign_key,
110
108
  touch: touch_chat
111
109
 
112
110
  has_many tool_calls,
113
111
  class_name: self.tool_call_class,
114
- foreign_key: ActiveSupport::Inflector.foreign_key(table_name.singularize),
112
+ foreign_key: tool_calls_foreign_key,
115
113
  dependent: :destroy
116
114
 
117
115
  belongs_to :parent_tool_call,
@@ -126,7 +124,7 @@ module RubyLLM
126
124
 
127
125
  belongs_to model,
128
126
  class_name: self.model_class,
129
- foreign_key: ActiveSupport::Inflector.foreign_key(model.to_s.singularize),
127
+ foreign_key: model_foreign_key,
130
128
  optional: true
131
129
 
132
130
  delegate :tool_call?, :tool_result?, to: :to_llm
@@ -144,8 +142,8 @@ module RubyLLM
144
142
  end
145
143
  end
146
144
 
147
- def acts_as_tool_call(message: :message, message_class: nil,
148
- result: :result, result_class: nil)
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)
149
147
  class_attribute :message_association_name, :result_association_name, :message_class, :result_class
150
148
 
151
149
  self.message_association_name = message
@@ -155,11 +153,11 @@ module RubyLLM
155
153
 
156
154
  belongs_to message,
157
155
  class_name: self.message_class,
158
- foreign_key: ActiveSupport::Inflector.foreign_key(message.to_s.singularize)
156
+ foreign_key: message_foreign_key
159
157
 
160
158
  has_one result,
161
159
  class_name: self.result_class,
162
- foreign_key: ActiveSupport::Inflector.foreign_key(table_name.singularize),
160
+ foreign_key: result_foreign_key,
163
161
  dependent: :nullify
164
162
 
165
163
  define_method :message_association do
@@ -11,11 +11,6 @@
11
11
  "claude-3-5-haiku-latest": {
12
12
  "anthropic": "claude-3-5-haiku-latest"
13
13
  },
14
- "claude-3-5-sonnet": {
15
- "anthropic": "claude-3-5-sonnet-20241022",
16
- "openrouter": "anthropic/claude-3.5-sonnet",
17
- "bedrock": "anthropic.claude-3-5-sonnet-20240620-v1:0:200k"
18
- },
19
14
  "claude-3-7-sonnet": {
20
15
  "anthropic": "claude-3-7-sonnet-20250219",
21
16
  "openrouter": "anthropic/claude-3.7-sonnet",
@@ -265,14 +260,6 @@
265
260
  "openai": "o1",
266
261
  "openrouter": "openai/o1"
267
262
  },
268
- "o1-mini": {
269
- "openai": "o1-mini",
270
- "openrouter": "openai/o1-mini"
271
- },
272
- "o1-mini-2024-09-12": {
273
- "openai": "o1-mini-2024-09-12",
274
- "openrouter": "openai/o1-mini-2024-09-12"
275
- },
276
263
  "o1-pro": {
277
264
  "openai": "o1-pro",
278
265
  "openrouter": "openai/o1-pro"
@@ -7,17 +7,8 @@ module RubyLLM
7
7
 
8
8
  def initialize(source, filename: nil)
9
9
  @source = source
10
- if url?
11
- @source = URI source
12
- @filename = filename || File.basename(@source.path).to_s
13
- elsif path?
14
- @source = Pathname.new source
15
- @filename = filename || @source.basename.to_s
16
- elsif active_storage?
17
- @filename = filename || extract_filename_from_active_storage
18
- else
19
- @filename = filename
20
- end
10
+ @source = source_type_cast
11
+ @filename = filename || source_filename
21
12
 
22
13
  determine_mime_type
23
14
  end
@@ -166,6 +157,38 @@ module RubyLLM
166
157
  end
167
158
  end
168
159
 
160
+ def source_type_cast
161
+ if url?
162
+ URI(@source)
163
+ elsif path?
164
+ Pathname.new(@source)
165
+ else
166
+ @source
167
+ end
168
+ end
169
+
170
+ def source_filename
171
+ if url?
172
+ File.basename(@source.path).to_s
173
+ elsif path?
174
+ @source.basename.to_s
175
+ elsif io_like?
176
+ extract_filename_from_io
177
+ elsif active_storage?
178
+ extract_filename_from_active_storage
179
+ end
180
+ end
181
+
182
+ def extract_filename_from_io
183
+ if defined?(ActionDispatch::Http::UploadedFile) && @source.is_a?(ActionDispatch::Http::UploadedFile)
184
+ @source.original_filename.to_s
185
+ elsif @source.respond_to?(:path)
186
+ File.basename(@source.path).to_s
187
+ else
188
+ 'attachment'
189
+ end
190
+ end
191
+
169
192
  def extract_filename_from_active_storage # rubocop:disable Metrics/PerceivedComplexity
170
193
  return 'attachment' unless defined?(ActiveStorage)
171
194