ruby_llm 1.8.2 → 1.9.0
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/README.md +8 -3
- data/lib/generators/ruby_llm/install/templates/create_messages_migration.rb.tt +3 -0
- data/lib/generators/ruby_llm/upgrade_to_v1_7/upgrade_to_v1_7_generator.rb +1 -1
- data/lib/generators/ruby_llm/upgrade_to_v1_9/templates/add_v1_9_message_columns.rb.tt +15 -0
- data/lib/generators/ruby_llm/upgrade_to_v1_9/upgrade_to_v1_9_generator.rb +49 -0
- data/lib/ruby_llm/active_record/acts_as.rb +6 -6
- data/lib/ruby_llm/active_record/chat_methods.rb +41 -13
- data/lib/ruby_llm/active_record/message_methods.rb +11 -2
- data/lib/ruby_llm/active_record/model_methods.rb +1 -1
- data/lib/ruby_llm/aliases.json +62 -20
- data/lib/ruby_llm/attachment.rb +8 -0
- data/lib/ruby_llm/chat.rb +13 -2
- data/lib/ruby_llm/configuration.rb +6 -1
- data/lib/ruby_llm/connection.rb +3 -3
- data/lib/ruby_llm/content.rb +23 -0
- data/lib/ruby_llm/message.rb +9 -4
- data/lib/ruby_llm/model/info.rb +4 -0
- data/lib/ruby_llm/models.json +9410 -7793
- data/lib/ruby_llm/models.rb +14 -22
- data/lib/ruby_llm/provider.rb +23 -1
- data/lib/ruby_llm/providers/anthropic/chat.rb +22 -3
- data/lib/ruby_llm/providers/anthropic/content.rb +44 -0
- data/lib/ruby_llm/providers/anthropic/media.rb +2 -1
- data/lib/ruby_llm/providers/anthropic/models.rb +15 -0
- data/lib/ruby_llm/providers/anthropic/streaming.rb +2 -0
- data/lib/ruby_llm/providers/anthropic/tools.rb +20 -18
- data/lib/ruby_llm/providers/bedrock/media.rb +2 -1
- data/lib/ruby_llm/providers/bedrock/streaming/content_extraction.rb +15 -0
- data/lib/ruby_llm/providers/bedrock/streaming/payload_processing.rb +2 -0
- data/lib/ruby_llm/providers/gemini/chat.rb +352 -69
- data/lib/ruby_llm/providers/gemini/media.rb +59 -1
- data/lib/ruby_llm/providers/gemini/tools.rb +146 -25
- data/lib/ruby_llm/providers/gemini/transcription.rb +116 -0
- data/lib/ruby_llm/providers/gemini.rb +2 -1
- data/lib/ruby_llm/providers/gpustack/media.rb +1 -0
- data/lib/ruby_llm/providers/ollama/media.rb +1 -0
- data/lib/ruby_llm/providers/openai/chat.rb +7 -2
- data/lib/ruby_llm/providers/openai/media.rb +2 -1
- data/lib/ruby_llm/providers/openai/streaming.rb +7 -2
- data/lib/ruby_llm/providers/openai/tools.rb +26 -6
- data/lib/ruby_llm/providers/openai/transcription.rb +70 -0
- data/lib/ruby_llm/providers/openai.rb +1 -0
- data/lib/ruby_llm/providers/vertexai/transcription.rb +16 -0
- data/lib/ruby_llm/providers/vertexai.rb +3 -0
- data/lib/ruby_llm/stream_accumulator.rb +10 -4
- data/lib/ruby_llm/tool.rb +126 -0
- data/lib/ruby_llm/transcription.rb +35 -0
- data/lib/ruby_llm/utils.rb +46 -0
- data/lib/ruby_llm/version.rb +1 -1
- data/lib/ruby_llm.rb +6 -0
- metadata +24 -3
data/lib/ruby_llm/tool.rb
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'ruby_llm/schema'
|
|
4
|
+
|
|
3
5
|
module RubyLLM
|
|
4
6
|
# Parameter definition for Tool methods.
|
|
5
7
|
class Parameter
|
|
@@ -29,6 +31,8 @@ module RubyLLM
|
|
|
29
31
|
end
|
|
30
32
|
|
|
31
33
|
class << self
|
|
34
|
+
attr_reader :params_schema_definition
|
|
35
|
+
|
|
32
36
|
def description(text = nil)
|
|
33
37
|
return @description unless text
|
|
34
38
|
|
|
@@ -42,6 +46,20 @@ module RubyLLM
|
|
|
42
46
|
def parameters
|
|
43
47
|
@parameters ||= {}
|
|
44
48
|
end
|
|
49
|
+
|
|
50
|
+
def params(schema = nil, &block)
|
|
51
|
+
@params_schema_definition = SchemaDefinition.new(schema:, block:)
|
|
52
|
+
self
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def with_params(**params)
|
|
56
|
+
@provider_params = params
|
|
57
|
+
self
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def provider_params
|
|
61
|
+
@provider_params ||= {}
|
|
62
|
+
end
|
|
45
63
|
end
|
|
46
64
|
|
|
47
65
|
def name
|
|
@@ -63,6 +81,23 @@ module RubyLLM
|
|
|
63
81
|
self.class.parameters
|
|
64
82
|
end
|
|
65
83
|
|
|
84
|
+
def provider_params
|
|
85
|
+
self.class.provider_params
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def params_schema
|
|
89
|
+
return @params_schema if defined?(@params_schema)
|
|
90
|
+
|
|
91
|
+
@params_schema = begin
|
|
92
|
+
definition = self.class.params_schema_definition
|
|
93
|
+
if definition&.present?
|
|
94
|
+
definition.json_schema
|
|
95
|
+
elsif parameters.any?
|
|
96
|
+
SchemaDefinition.from_parameters(parameters)&.json_schema
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
66
101
|
def call(args)
|
|
67
102
|
RubyLLM.logger.debug "Tool #{name} called with: #{args.inspect}"
|
|
68
103
|
result = execute(**args.transform_keys(&:to_sym))
|
|
@@ -79,5 +114,96 @@ module RubyLLM
|
|
|
79
114
|
def halt(message)
|
|
80
115
|
Halt.new(message)
|
|
81
116
|
end
|
|
117
|
+
|
|
118
|
+
# Wraps schema handling for tool parameters, supporting JSON Schema hashes,
|
|
119
|
+
# RubyLLM::Schema instances/classes, and DSL blocks.
|
|
120
|
+
class SchemaDefinition
|
|
121
|
+
def self.from_parameters(parameters)
|
|
122
|
+
return nil if parameters.nil? || parameters.empty?
|
|
123
|
+
|
|
124
|
+
properties = parameters.to_h do |name, param|
|
|
125
|
+
schema = {
|
|
126
|
+
type: map_type(param.type),
|
|
127
|
+
description: param.description
|
|
128
|
+
}.compact
|
|
129
|
+
|
|
130
|
+
schema[:items] = default_items_schema if schema[:type] == 'array'
|
|
131
|
+
|
|
132
|
+
[name.to_s, schema]
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
required = parameters.select { |_, param| param.required }.keys.map(&:to_s)
|
|
136
|
+
|
|
137
|
+
json_schema = {
|
|
138
|
+
type: 'object',
|
|
139
|
+
properties: properties,
|
|
140
|
+
required: required,
|
|
141
|
+
additionalProperties: false,
|
|
142
|
+
strict: true
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
new(schema: json_schema)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def self.map_type(type)
|
|
149
|
+
case type.to_s
|
|
150
|
+
when 'integer', 'int' then 'integer'
|
|
151
|
+
when 'number', 'float', 'double' then 'number'
|
|
152
|
+
when 'boolean' then 'boolean'
|
|
153
|
+
when 'array' then 'array'
|
|
154
|
+
when 'object' then 'object'
|
|
155
|
+
else
|
|
156
|
+
'string'
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def self.default_items_schema
|
|
161
|
+
{ type: 'string' }
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def initialize(schema: nil, block: nil)
|
|
165
|
+
@schema = schema
|
|
166
|
+
@block = block
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def present?
|
|
170
|
+
@schema || @block
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def json_schema
|
|
174
|
+
@json_schema ||= RubyLLM::Utils.deep_stringify_keys(resolve_schema)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
private
|
|
178
|
+
|
|
179
|
+
def resolve_schema
|
|
180
|
+
return resolve_direct_schema(@schema) if @schema
|
|
181
|
+
return build_from_block(&@block) if @block
|
|
182
|
+
|
|
183
|
+
nil
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def resolve_direct_schema(schema)
|
|
187
|
+
return extract_schema(schema.to_json_schema) if schema.respond_to?(:to_json_schema)
|
|
188
|
+
return RubyLLM::Utils.deep_dup(schema) if schema.is_a?(Hash)
|
|
189
|
+
if schema.is_a?(Class) && schema.instance_methods.include?(:to_json_schema)
|
|
190
|
+
return extract_schema(schema.new.to_json_schema)
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
nil
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def build_from_block(&)
|
|
197
|
+
schema_class = RubyLLM::Schema.create(&)
|
|
198
|
+
extract_schema(schema_class.new.to_json_schema)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def extract_schema(schema_hash)
|
|
202
|
+
return nil unless schema_hash.is_a?(Hash)
|
|
203
|
+
|
|
204
|
+
schema = schema_hash[:schema] || schema_hash['schema'] || schema_hash
|
|
205
|
+
RubyLLM::Utils.deep_dup(schema)
|
|
206
|
+
end
|
|
207
|
+
end
|
|
82
208
|
end
|
|
83
209
|
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyLLM
|
|
4
|
+
# Represents a transcription of audio content.
|
|
5
|
+
class Transcription
|
|
6
|
+
attr_reader :text, :model, :language, :duration, :segments, :input_tokens, :output_tokens
|
|
7
|
+
|
|
8
|
+
def initialize(text:, model:, **attributes)
|
|
9
|
+
@text = text
|
|
10
|
+
@model = model
|
|
11
|
+
@language = attributes[:language]
|
|
12
|
+
@duration = attributes[:duration]
|
|
13
|
+
@segments = attributes[:segments]
|
|
14
|
+
@input_tokens = attributes[:input_tokens]
|
|
15
|
+
@output_tokens = attributes[:output_tokens]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.transcribe(audio_file, **kwargs)
|
|
19
|
+
model = kwargs.delete(:model)
|
|
20
|
+
language = kwargs.delete(:language)
|
|
21
|
+
provider = kwargs.delete(:provider)
|
|
22
|
+
assume_model_exists = kwargs.delete(:assume_model_exists) { false }
|
|
23
|
+
context = kwargs.delete(:context)
|
|
24
|
+
options = kwargs
|
|
25
|
+
|
|
26
|
+
config = context&.config || RubyLLM.config
|
|
27
|
+
model ||= config.default_transcription_model
|
|
28
|
+
model, provider_instance = Models.resolve(model, provider: provider, assume_exists: assume_model_exists,
|
|
29
|
+
config: config)
|
|
30
|
+
model_id = model.id
|
|
31
|
+
|
|
32
|
+
provider_instance.transcribe(audio_file, model: model_id, language:, **options)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
data/lib/ruby_llm/utils.rb
CHANGED
|
@@ -41,5 +41,51 @@ module RubyLLM
|
|
|
41
41
|
end
|
|
42
42
|
end
|
|
43
43
|
end
|
|
44
|
+
|
|
45
|
+
def deep_dup(value)
|
|
46
|
+
case value
|
|
47
|
+
when Hash
|
|
48
|
+
value.each_with_object({}) do |(key, val), duped|
|
|
49
|
+
duped[deep_dup(key)] = deep_dup(val)
|
|
50
|
+
end
|
|
51
|
+
when Array
|
|
52
|
+
value.map { |item| deep_dup(item) }
|
|
53
|
+
else
|
|
54
|
+
begin
|
|
55
|
+
value.dup
|
|
56
|
+
rescue TypeError
|
|
57
|
+
value
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def deep_stringify_keys(value)
|
|
63
|
+
case value
|
|
64
|
+
when Hash
|
|
65
|
+
value.each_with_object({}) do |(key, val), result|
|
|
66
|
+
result[key.to_s] = deep_stringify_keys(val)
|
|
67
|
+
end
|
|
68
|
+
when Array
|
|
69
|
+
value.map { |item| deep_stringify_keys(item) }
|
|
70
|
+
when Symbol
|
|
71
|
+
value.to_s
|
|
72
|
+
else
|
|
73
|
+
value
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def deep_symbolize_keys(value)
|
|
78
|
+
case value
|
|
79
|
+
when Hash
|
|
80
|
+
value.each_with_object({}) do |(key, val), result|
|
|
81
|
+
symbolized_key = key.respond_to?(:to_sym) ? key.to_sym : key
|
|
82
|
+
result[symbolized_key] = deep_symbolize_keys(val)
|
|
83
|
+
end
|
|
84
|
+
when Array
|
|
85
|
+
value.map { |item| deep_symbolize_keys(item) }
|
|
86
|
+
else
|
|
87
|
+
value
|
|
88
|
+
end
|
|
89
|
+
end
|
|
44
90
|
end
|
|
45
91
|
end
|
data/lib/ruby_llm/version.rb
CHANGED
data/lib/ruby_llm.rb
CHANGED
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
require 'base64'
|
|
4
4
|
require 'event_stream_parser'
|
|
5
5
|
require 'faraday'
|
|
6
|
+
require 'faraday/multipart'
|
|
6
7
|
require 'faraday/retry'
|
|
7
8
|
require 'json'
|
|
8
9
|
require 'logger'
|
|
10
|
+
require 'marcel'
|
|
9
11
|
require 'securerandom'
|
|
10
12
|
require 'zeitwerk'
|
|
11
13
|
|
|
@@ -56,6 +58,10 @@ module RubyLLM
|
|
|
56
58
|
Image.paint(...)
|
|
57
59
|
end
|
|
58
60
|
|
|
61
|
+
def transcribe(...)
|
|
62
|
+
Transcription.transcribe(...)
|
|
63
|
+
end
|
|
64
|
+
|
|
59
65
|
def models
|
|
60
66
|
Models.instance
|
|
61
67
|
end
|
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.
|
|
4
|
+
version: 1.9.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Carmine Paolino
|
|
@@ -107,6 +107,20 @@ dependencies:
|
|
|
107
107
|
- - "~>"
|
|
108
108
|
- !ruby/object:Gem::Version
|
|
109
109
|
version: '1.0'
|
|
110
|
+
- !ruby/object:Gem::Dependency
|
|
111
|
+
name: ruby_llm-schema
|
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
|
113
|
+
requirements:
|
|
114
|
+
- - "~>"
|
|
115
|
+
- !ruby/object:Gem::Version
|
|
116
|
+
version: 0.2.1
|
|
117
|
+
type: :runtime
|
|
118
|
+
prerelease: false
|
|
119
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
120
|
+
requirements:
|
|
121
|
+
- - "~>"
|
|
122
|
+
- !ruby/object:Gem::Version
|
|
123
|
+
version: 0.2.1
|
|
110
124
|
- !ruby/object:Gem::Dependency
|
|
111
125
|
name: zeitwerk
|
|
112
126
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -168,6 +182,8 @@ files:
|
|
|
168
182
|
- lib/generators/ruby_llm/install/templates/tool_call_model.rb.tt
|
|
169
183
|
- lib/generators/ruby_llm/upgrade_to_v1_7/templates/migration.rb.tt
|
|
170
184
|
- lib/generators/ruby_llm/upgrade_to_v1_7/upgrade_to_v1_7_generator.rb
|
|
185
|
+
- lib/generators/ruby_llm/upgrade_to_v1_9/templates/add_v1_9_message_columns.rb.tt
|
|
186
|
+
- lib/generators/ruby_llm/upgrade_to_v1_9/upgrade_to_v1_9_generator.rb
|
|
171
187
|
- lib/ruby_llm.rb
|
|
172
188
|
- lib/ruby_llm/active_record/acts_as.rb
|
|
173
189
|
- lib/ruby_llm/active_record/acts_as_legacy.rb
|
|
@@ -202,6 +218,7 @@ files:
|
|
|
202
218
|
- lib/ruby_llm/providers/anthropic.rb
|
|
203
219
|
- lib/ruby_llm/providers/anthropic/capabilities.rb
|
|
204
220
|
- lib/ruby_llm/providers/anthropic/chat.rb
|
|
221
|
+
- lib/ruby_llm/providers/anthropic/content.rb
|
|
205
222
|
- lib/ruby_llm/providers/anthropic/embeddings.rb
|
|
206
223
|
- lib/ruby_llm/providers/anthropic/media.rb
|
|
207
224
|
- lib/ruby_llm/providers/anthropic/models.rb
|
|
@@ -231,6 +248,7 @@ files:
|
|
|
231
248
|
- lib/ruby_llm/providers/gemini/models.rb
|
|
232
249
|
- lib/ruby_llm/providers/gemini/streaming.rb
|
|
233
250
|
- lib/ruby_llm/providers/gemini/tools.rb
|
|
251
|
+
- lib/ruby_llm/providers/gemini/transcription.rb
|
|
234
252
|
- lib/ruby_llm/providers/gpustack.rb
|
|
235
253
|
- lib/ruby_llm/providers/gpustack/chat.rb
|
|
236
254
|
- lib/ruby_llm/providers/gpustack/media.rb
|
|
@@ -254,6 +272,7 @@ files:
|
|
|
254
272
|
- lib/ruby_llm/providers/openai/moderation.rb
|
|
255
273
|
- lib/ruby_llm/providers/openai/streaming.rb
|
|
256
274
|
- lib/ruby_llm/providers/openai/tools.rb
|
|
275
|
+
- lib/ruby_llm/providers/openai/transcription.rb
|
|
257
276
|
- lib/ruby_llm/providers/openrouter.rb
|
|
258
277
|
- lib/ruby_llm/providers/openrouter/models.rb
|
|
259
278
|
- lib/ruby_llm/providers/perplexity.rb
|
|
@@ -265,11 +284,13 @@ files:
|
|
|
265
284
|
- lib/ruby_llm/providers/vertexai/embeddings.rb
|
|
266
285
|
- lib/ruby_llm/providers/vertexai/models.rb
|
|
267
286
|
- lib/ruby_llm/providers/vertexai/streaming.rb
|
|
287
|
+
- lib/ruby_llm/providers/vertexai/transcription.rb
|
|
268
288
|
- lib/ruby_llm/railtie.rb
|
|
269
289
|
- lib/ruby_llm/stream_accumulator.rb
|
|
270
290
|
- lib/ruby_llm/streaming.rb
|
|
271
291
|
- lib/ruby_llm/tool.rb
|
|
272
292
|
- lib/ruby_llm/tool_call.rb
|
|
293
|
+
- lib/ruby_llm/transcription.rb
|
|
273
294
|
- lib/ruby_llm/utils.rb
|
|
274
295
|
- lib/ruby_llm/version.rb
|
|
275
296
|
- lib/tasks/models.rake
|
|
@@ -288,8 +309,8 @@ metadata:
|
|
|
288
309
|
funding_uri: https://github.com/sponsors/crmne
|
|
289
310
|
rubygems_mfa_required: 'true'
|
|
290
311
|
post_install_message: |
|
|
291
|
-
Upgrading from RubyLLM <= 1.
|
|
292
|
-
--> https://rubyllm.com/upgrading
|
|
312
|
+
Upgrading from RubyLLM <= 1.8.x? Check the upgrade guide for new features and migration instructions
|
|
313
|
+
--> https://rubyllm.com/upgrading/
|
|
293
314
|
rdoc_options: []
|
|
294
315
|
require_paths:
|
|
295
316
|
- lib
|