ruby_llm 2.0.0.rc3 → 2.0.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/.rdoc_options +2 -2
- data/README.md +34 -23
- data/lib/generators/ruby_llm/generator_helpers.rb +4 -1
- data/lib/generators/ruby_llm/install/templates/create_chats_migration.rb.tt +1 -1
- data/lib/generators/ruby_llm/install/templates/create_messages_migration.rb.tt +1 -1
- data/lib/generators/ruby_llm/install/templates/create_ruby_llm_records_migration.rb.tt +5 -5
- data/lib/generators/ruby_llm/upgrade/online_copy_migration/data.rb +9 -0
- data/lib/generators/ruby_llm/upgrade/online_copy_migration.rb +5 -1
- data/lib/generators/ruby_llm/upgrade/templates/backfill_v2_data.rb.tt +6 -2
- data/lib/generators/ruby_llm/upgrade/templates/finish_v2_upgrade.rb.tt +8 -2
- data/lib/generators/ruby_llm/upgrade/templates/prepare_v2_upgrade.rb.tt +2 -2
- data/lib/generators/ruby_llm/upgrade/templates/ruby_llm_upgrade.rb.tt +1 -1
- data/lib/generators/ruby_llm/upgrade/templates/upgrade_initializer.rb.tt +1 -1
- data/lib/generators/ruby_llm/upgrade/upgrade_generator.rb +11 -0
- data/lib/generators/ruby_llm/upgrade/upgrade_migration.rb +2 -1
- data/lib/ruby_llm/active_record/attachment_helpers.rb +81 -3
- data/lib/ruby_llm/active_record/chat_methods.rb +11 -8
- data/lib/ruby_llm/agent.rb +17 -17
- data/lib/ruby_llm/batch.rb +2 -2
- data/lib/ruby_llm/chat.rb +17 -17
- data/lib/ruby_llm/embedding.rb +1 -1
- data/lib/ruby_llm/error.rb +1 -1
- data/lib/ruby_llm/image.rb +1 -1
- data/lib/ruby_llm/message.rb +15 -1
- data/lib/ruby_llm/models.json +1654 -1791
- data/lib/ruby_llm/moderation.rb +1 -1
- data/lib/ruby_llm/ocr.rb +1 -1
- data/lib/ruby_llm/protocol.rb +36 -13
- data/lib/ruby_llm/protocols/anthropic/chat.rb +1 -6
- data/lib/ruby_llm/protocols/chat_completions/chat.rb +2 -11
- data/lib/ruby_llm/protocols/converse/chat.rb +0 -1
- data/lib/ruby_llm/protocols/responses/chat.rb +0 -10
- data/lib/ruby_llm/protocols/vertexai/research.rb +8 -8
- data/lib/ruby_llm/provider.rb +4 -4
- data/lib/ruby_llm/providers/openrouter/chat.rb +5 -5
- data/lib/ruby_llm/rerank.rb +1 -1
- data/lib/ruby_llm/research_job.rb +4 -4
- data/lib/ruby_llm/server_tool_call.rb +2 -2
- data/lib/ruby_llm/speech.rb +1 -1
- data/lib/ruby_llm/tools/{server_tools.rb → provider_tools.rb} +7 -7
- data/lib/ruby_llm/transcription.rb +1 -1
- data/lib/ruby_llm/version.rb +1 -1
- data/lib/ruby_llm/video_job.rb +1 -1
- data/lib/ruby_llm.rb +2 -2
- metadata +7 -7
data/lib/ruby_llm/moderation.rb
CHANGED
|
@@ -104,7 +104,7 @@ module RubyLLM
|
|
|
104
104
|
empty_tokens = Tokens.new
|
|
105
105
|
payload = {
|
|
106
106
|
provider: provider_instance.slug,
|
|
107
|
-
provider_class: provider_instance.
|
|
107
|
+
provider_class: provider_instance.name,
|
|
108
108
|
model: model&.id,
|
|
109
109
|
model_info: model,
|
|
110
110
|
input: input,
|
data/lib/ruby_llm/ocr.rb
CHANGED
data/lib/ruby_llm/protocol.rb
CHANGED
|
@@ -96,13 +96,13 @@ module RubyLLM
|
|
|
96
96
|
|
|
97
97
|
def complete(messages, tools:, temperature:, provider_options: {}, headers: {}, schema: nil, thinking: nil,
|
|
98
98
|
max_output_tokens: nil, citations: false, caching: nil, tool_prefs: nil, before_request: [],
|
|
99
|
-
usage_recorder: nil,
|
|
100
|
-
resolution =
|
|
99
|
+
usage_recorder: nil, provider_tools: [], compaction: nil, end_user: nil, &)
|
|
100
|
+
resolution = resolve_provider_tools_for_request(provider_tools)
|
|
101
101
|
headers = resolution.headers.merge(headers) if resolution
|
|
102
102
|
headers = apply_compaction_headers(headers, compaction) if compaction
|
|
103
103
|
payload = render(
|
|
104
104
|
messages, tools:, tool_prefs:, temperature:, max_output_tokens:, provider_options:, schema:, thinking:,
|
|
105
|
-
citations:, caching:, compaction:, end_user:, before_request:,
|
|
105
|
+
citations:, caching:, compaction:, end_user:, before_request:, provider_tools:,
|
|
106
106
|
stream: block_given?
|
|
107
107
|
)
|
|
108
108
|
|
|
@@ -122,7 +122,7 @@ module RubyLLM
|
|
|
122
122
|
|
|
123
123
|
def render(messages, tools:, temperature:, provider_options: {}, schema: nil, thinking: nil,
|
|
124
124
|
max_output_tokens: nil, citations: false, caching: nil, tool_prefs: nil, before_request: [],
|
|
125
|
-
stream: false,
|
|
125
|
+
stream: false, provider_tools: [], compaction: nil, end_user: nil)
|
|
126
126
|
payload = render_payload(
|
|
127
127
|
messages,
|
|
128
128
|
tools: tools,
|
|
@@ -139,7 +139,7 @@ module RubyLLM
|
|
|
139
139
|
payload = apply_end_user(payload, end_user) if end_user
|
|
140
140
|
payload = apply_compaction(payload, compaction) if compaction
|
|
141
141
|
payload = Support::Utils.deep_merge(payload, provider_options)
|
|
142
|
-
payload =
|
|
142
|
+
payload = apply_provider_tools(payload, provider_tools)
|
|
143
143
|
apply_before_request_hooks(payload, before_request)
|
|
144
144
|
rescue NotImplementedError
|
|
145
145
|
raise Error, "#{@provider.name} doesn't support chat"
|
|
@@ -188,8 +188,8 @@ module RubyLLM
|
|
|
188
188
|
end
|
|
189
189
|
|
|
190
190
|
# The alias table mapping portable server tool names to this protocol's
|
|
191
|
-
# wire format. Protocols with
|
|
192
|
-
# +nil+ means the protocol has no
|
|
191
|
+
# wire format. Protocols with provider-tool support override this;
|
|
192
|
+
# +nil+ means the protocol has no provider-tool support at all.
|
|
193
193
|
def server_tool_aliases
|
|
194
194
|
nil
|
|
195
195
|
end
|
|
@@ -471,6 +471,7 @@ module RubyLLM
|
|
|
471
471
|
end
|
|
472
472
|
|
|
473
473
|
def preprocess_message(message)
|
|
474
|
+
return message.without_thinking if foreign_thinking?(message)
|
|
474
475
|
return message unless auto_upload_large_files?
|
|
475
476
|
return message unless message.role == :user
|
|
476
477
|
return message if message.attachments.empty?
|
|
@@ -483,21 +484,43 @@ module RubyLLM
|
|
|
483
484
|
|
|
484
485
|
private
|
|
485
486
|
|
|
486
|
-
|
|
487
|
+
# A thinking signature is opaque to every provider but the one that
|
|
488
|
+
# issued it, so a message another provider produced replays without
|
|
489
|
+
# its thinking. A message with no known producer replays as it is.
|
|
490
|
+
def foreign_thinking?(message)
|
|
491
|
+
return false unless message.role == :assistant && carries_thinking?(message)
|
|
492
|
+
|
|
493
|
+
producer = producer_slug(message)
|
|
494
|
+
!producer.nil? && producer != @provider.slug
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
def carries_thinking?(message)
|
|
498
|
+
return true if message.thinking || message.raw_reasoning
|
|
499
|
+
|
|
500
|
+
message.tool_call? && message.tool_calls.each_value.any?(&:thought_signature)
|
|
501
|
+
end
|
|
502
|
+
|
|
503
|
+
# Only a usage entry names the producer: a model id alone can belong
|
|
504
|
+
# to several providers.
|
|
505
|
+
def producer_slug(message)
|
|
506
|
+
message.ruby_llm_usage_entries.reverse.find(&:succeeded?)&.provider
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
def resolve_provider_tools_for_request(entries)
|
|
487
510
|
return nil if entries.nil? || entries.empty?
|
|
488
511
|
|
|
489
512
|
aliases = server_tool_aliases
|
|
490
513
|
unless aliases
|
|
491
514
|
raise UnsupportedServerToolError,
|
|
492
|
-
"#{@provider.name} has no
|
|
515
|
+
"#{@provider.name} has no provider-tool support through RubyLLM yet. " \
|
|
493
516
|
'Request options in the provider vocabulary can be set with with_provider_options.'
|
|
494
517
|
end
|
|
495
518
|
|
|
496
|
-
RubyLLM::Tools::
|
|
519
|
+
RubyLLM::Tools::ProviderTools.resolve(entries, aliases: aliases, owner: @provider.name)
|
|
497
520
|
end
|
|
498
521
|
|
|
499
|
-
def
|
|
500
|
-
resolution =
|
|
522
|
+
def apply_provider_tools(payload, entries)
|
|
523
|
+
resolution = resolve_provider_tools_for_request(entries)
|
|
501
524
|
return payload unless resolution
|
|
502
525
|
|
|
503
526
|
payload = Support::Utils.deep_merge(payload, resolution.payload) unless resolution.payload.empty?
|
|
@@ -505,7 +528,7 @@ module RubyLLM
|
|
|
505
528
|
payload
|
|
506
529
|
end
|
|
507
530
|
|
|
508
|
-
#
|
|
531
|
+
# Provider tools join function tools in the payload's tools array. The
|
|
509
532
|
# entry shape comes from the alias table or the caller's raw Hash.
|
|
510
533
|
def merge_server_tool_entries(payload, entries)
|
|
511
534
|
payload[:tools] = Array(payload[:tools]) + entries
|
|
@@ -39,13 +39,12 @@ module RubyLLM
|
|
|
39
39
|
warn_unsupported_citations(model) if citations && !model.supports?(:citations)
|
|
40
40
|
tool_prefs ||= {}
|
|
41
41
|
system_messages, chat_messages = separate_messages(messages)
|
|
42
|
-
explicit_boundaries = cache_boundaries?(messages, caching:)
|
|
43
42
|
system_content = build_system_content(system_messages, caching:)
|
|
44
43
|
|
|
45
44
|
build_base_payload(chat_messages, model, stream, thinking, citations: citations, caching:,
|
|
46
45
|
max_output_tokens:).tap do |payload|
|
|
47
46
|
add_optional_fields(payload, system_content:, tools:, tool_prefs:, temperature:, schema:)
|
|
48
|
-
payload[:cache_control] = prompt_cache_control(caching) if caching
|
|
47
|
+
payload[:cache_control] = prompt_cache_control(caching) if caching
|
|
49
48
|
end
|
|
50
49
|
end
|
|
51
50
|
|
|
@@ -429,10 +428,6 @@ module RubyLLM
|
|
|
429
428
|
content_blocks.concat(Media.format_content(msg.content, msg.attachments, citations: citations))
|
|
430
429
|
end
|
|
431
430
|
|
|
432
|
-
def cache_boundaries?(messages, caching: nil)
|
|
433
|
-
caching != false && messages.any?(&:cache_until_here?)
|
|
434
|
-
end
|
|
435
|
-
|
|
436
431
|
def cache_boundary?(message, caching: nil)
|
|
437
432
|
caching != false && message.cache_until_here?
|
|
438
433
|
end
|
|
@@ -87,7 +87,7 @@ module RubyLLM
|
|
|
87
87
|
payload[:reasoning_effort] = effort if effort
|
|
88
88
|
|
|
89
89
|
payload[:stream_options] = { include_usage: true } if stream
|
|
90
|
-
apply_prompt_cache_params(payload,
|
|
90
|
+
apply_prompt_cache_params(payload, caching)
|
|
91
91
|
payload
|
|
92
92
|
end
|
|
93
93
|
|
|
@@ -250,11 +250,10 @@ module RubyLLM
|
|
|
250
250
|
end
|
|
251
251
|
end
|
|
252
252
|
|
|
253
|
-
def apply_prompt_cache_params(payload,
|
|
253
|
+
def apply_prompt_cache_params(payload, caching)
|
|
254
254
|
return unless openai_prompt_caching?
|
|
255
255
|
|
|
256
256
|
payload.merge!(prompt_cache_params(caching)) if caching
|
|
257
|
-
force_explicit_cache_mode(payload) if caching != false && cache_boundaries?(messages)
|
|
258
257
|
end
|
|
259
258
|
|
|
260
259
|
def openai_prompt_caching?
|
|
@@ -290,14 +289,6 @@ module RubyLLM
|
|
|
290
289
|
retention
|
|
291
290
|
end
|
|
292
291
|
|
|
293
|
-
def force_explicit_cache_mode(payload)
|
|
294
|
-
payload[:prompt_cache_options] = { mode: 'explicit' }.merge(payload[:prompt_cache_options] || {})
|
|
295
|
-
end
|
|
296
|
-
|
|
297
|
-
def cache_boundaries?(messages)
|
|
298
|
-
messages.any?(&:cache_until_here?)
|
|
299
|
-
end
|
|
300
|
-
|
|
301
292
|
def prompt_cache_options(caching)
|
|
302
293
|
options = caching.to_h.transform_keys(&:to_sym)
|
|
303
294
|
unsupported = options.keys - PROMPT_CACHE_OPTIONS
|
|
@@ -266,7 +266,6 @@ module RubyLLM
|
|
|
266
266
|
|
|
267
267
|
def automatic_cache_target(system_messages, chat_messages, caching)
|
|
268
268
|
return unless caching
|
|
269
|
-
return if (system_messages + chat_messages).any?(&:cache_until_here?)
|
|
270
269
|
|
|
271
270
|
(chat_messages.reverse + system_messages.reverse).find { |msg| cacheable_message?(msg) }
|
|
272
271
|
end
|
|
@@ -12,7 +12,6 @@ module RubyLLM
|
|
|
12
12
|
OPENAI_INLINE_FILE_LIMIT = 50 * 1024 * 1024
|
|
13
13
|
OPENAI_FILE_UPLOAD_LIMIT = 512 * 1024 * 1024
|
|
14
14
|
PROMPT_CACHE_OPTIONS = %i[key ttl mode retention].freeze
|
|
15
|
-
CACHE_BREAKPOINT_ROLES = %i[user system].freeze
|
|
16
15
|
|
|
17
16
|
module_function
|
|
18
17
|
|
|
@@ -47,7 +46,6 @@ module RubyLLM
|
|
|
47
46
|
payload[:reasoning] = { effort: effort } if effort
|
|
48
47
|
payload[:reasoning] = (payload[:reasoning] || {}).merge(summary: 'auto') if thinking&.display == :summarized
|
|
49
48
|
payload.merge!(prompt_cache_params(caching)) if caching
|
|
50
|
-
force_explicit_cache_mode(payload) if caching != false && cache_boundaries?(messages)
|
|
51
49
|
|
|
52
50
|
payload
|
|
53
51
|
end
|
|
@@ -225,14 +223,6 @@ module RubyLLM
|
|
|
225
223
|
retention
|
|
226
224
|
end
|
|
227
225
|
|
|
228
|
-
def force_explicit_cache_mode(payload)
|
|
229
|
-
payload[:prompt_cache_options] = { mode: 'explicit' }.merge(payload[:prompt_cache_options] || {})
|
|
230
|
-
end
|
|
231
|
-
|
|
232
|
-
def cache_boundaries?(messages)
|
|
233
|
-
messages.any? { |msg| msg.cache_until_here? && CACHE_BREAKPOINT_ROLES.include?(msg.role) }
|
|
234
|
-
end
|
|
235
|
-
|
|
236
226
|
def prompt_cache_options(caching)
|
|
237
227
|
options = caching.to_h.transform_keys(&:to_sym)
|
|
238
228
|
unsupported = options.keys - PROMPT_CACHE_OPTIONS
|
|
@@ -21,9 +21,9 @@ module RubyLLM
|
|
|
21
21
|
|
|
22
22
|
def server_tool_aliases = SERVER_TOOL_ALIASES
|
|
23
23
|
|
|
24
|
-
def create_research_job(prompt, agent:, with: nil,
|
|
24
|
+
def create_research_job(prompt, agent:, with: nil, provider_tools: nil, provider_options: {})
|
|
25
25
|
validate_research_agent(agent)
|
|
26
|
-
payload = render_research_payload(prompt, agent:, with:,
|
|
26
|
+
payload = render_research_payload(prompt, agent:, with:, provider_tools:, provider_options:)
|
|
27
27
|
response = @connection.post(research_url, payload, idempotent: false)
|
|
28
28
|
parse_research_job(response, agent:)
|
|
29
29
|
end
|
|
@@ -71,20 +71,20 @@ module RubyLLM
|
|
|
71
71
|
raise ArgumentError, 'Vertex AI research requires the supported Deep Research agent ID'
|
|
72
72
|
end
|
|
73
73
|
|
|
74
|
-
def render_research_payload(prompt, agent:, with:,
|
|
74
|
+
def render_research_payload(prompt, agent:, with:, provider_tools:, provider_options:)
|
|
75
75
|
raise ArgumentError, 'Research requires a nonempty prompt' unless prompt.is_a?(String) && !prompt.empty?
|
|
76
76
|
|
|
77
77
|
attachments = Attachment.wrap(with, config: @config)
|
|
78
78
|
validate_research_attachments(attachments)
|
|
79
79
|
payload = { agent:, input: render_interaction_content(prompt, attachments), background: true, stream: false }
|
|
80
|
-
payload[:tools] = [] unless
|
|
80
|
+
payload[:tools] = [] unless provider_tools.nil?
|
|
81
81
|
options = render_research_options(provider_options)
|
|
82
|
-
entries = if
|
|
83
|
-
RubyLLM::Tools::
|
|
82
|
+
entries = if provider_tools.is_a?(Hash)
|
|
83
|
+
RubyLLM::Tools::ProviderTools.normalize([], provider_tools)
|
|
84
84
|
else
|
|
85
|
-
RubyLLM::Tools::
|
|
85
|
+
RubyLLM::Tools::ProviderTools.normalize(Array(provider_tools), {})
|
|
86
86
|
end
|
|
87
|
-
|
|
87
|
+
apply_provider_tools(payload, entries).merge(options)
|
|
88
88
|
end
|
|
89
89
|
|
|
90
90
|
def validate_research_attachments(attachments)
|
data/lib/ruby_llm/provider.rb
CHANGED
|
@@ -130,13 +130,13 @@ module RubyLLM
|
|
|
130
130
|
|
|
131
131
|
def complete(messages, tools:, temperature:, model:, provider_options: {}, headers: {}, schema: nil, # :nodoc:
|
|
132
132
|
max_output_tokens: nil, thinking: nil, citations: false, caching: nil, tool_prefs: nil,
|
|
133
|
-
protocol: nil, before_request: [], usage_recorder: nil,
|
|
133
|
+
protocol: nil, before_request: [], usage_recorder: nil, provider_tools: [],
|
|
134
134
|
compaction: nil, end_user: nil, &)
|
|
135
135
|
protocol_class = resolve_protocol(protocol, model, tools:, schema:, thinking:, tool_prefs:, citations:)
|
|
136
136
|
protocol_class.new(self, model).complete(
|
|
137
137
|
messages,
|
|
138
138
|
tools: tools,
|
|
139
|
-
|
|
139
|
+
provider_tools: provider_tools,
|
|
140
140
|
tool_prefs: tool_prefs,
|
|
141
141
|
temperature: temperature,
|
|
142
142
|
max_output_tokens: max_output_tokens,
|
|
@@ -166,12 +166,12 @@ module RubyLLM
|
|
|
166
166
|
|
|
167
167
|
def render(messages, tools:, temperature:, model:, provider_options: {}, schema: nil, thinking: nil, # :nodoc:
|
|
168
168
|
max_output_tokens: nil, citations: false, caching: nil, tool_prefs: nil, protocol: nil,
|
|
169
|
-
before_request: [],
|
|
169
|
+
before_request: [], provider_tools: [], compaction: nil, end_user: nil)
|
|
170
170
|
protocol_class = resolve_protocol(protocol, model, tools:, schema:, thinking:, tool_prefs:, citations:)
|
|
171
171
|
protocol_class.new(self, model).render(
|
|
172
172
|
messages,
|
|
173
173
|
tools: tools,
|
|
174
|
-
|
|
174
|
+
provider_tools: provider_tools,
|
|
175
175
|
tool_prefs: tool_prefs,
|
|
176
176
|
temperature: temperature,
|
|
177
177
|
max_output_tokens: max_output_tokens,
|
|
@@ -44,10 +44,14 @@ module RubyLLM
|
|
|
44
44
|
payload = super
|
|
45
45
|
payload.delete(:reasoning_effort)
|
|
46
46
|
strip_schema_strict(payload)
|
|
47
|
+
if tool_prefs&.dig(:choice) == :none
|
|
48
|
+
payload.delete(:tools)
|
|
49
|
+
payload.delete(:parallel_tool_calls)
|
|
50
|
+
end
|
|
47
51
|
|
|
48
52
|
reasoning = build_reasoning(thinking)
|
|
49
53
|
payload[:reasoning] = reasoning if reasoning
|
|
50
|
-
payload[:cache_control] = prompt_cache_control(caching) if caching
|
|
54
|
+
payload[:cache_control] = prompt_cache_control(caching) if caching
|
|
51
55
|
payload
|
|
52
56
|
end
|
|
53
57
|
|
|
@@ -142,10 +146,6 @@ module RubyLLM
|
|
|
142
146
|
keys.map { |key| ":#{key}" }.join(', ')
|
|
143
147
|
end
|
|
144
148
|
|
|
145
|
-
def cache_boundaries?(messages)
|
|
146
|
-
messages.any?(&:cache_until_here?)
|
|
147
|
-
end
|
|
148
|
-
|
|
149
149
|
def openai_prompt_caching?
|
|
150
150
|
false
|
|
151
151
|
end
|
data/lib/ruby_llm/rerank.rb
CHANGED
|
@@ -67,15 +67,15 @@ module RubyLLM
|
|
|
67
67
|
|
|
68
68
|
# Submits one research task without waiting. +provider:+ and +agent:+
|
|
69
69
|
# are required; +with:+ attaches documents or images where supported.
|
|
70
|
-
# +
|
|
71
|
-
# and their options, as on Chat#
|
|
72
|
-
def self.research_later(prompt, provider:, agent:, with: nil,
|
|
70
|
+
# +provider_tools:+ accepts an array of aliases or a Hash of aliases
|
|
71
|
+
# and their options, as on Chat#with_provider_tools.
|
|
72
|
+
def self.research_later(prompt, provider:, agent:, with: nil, provider_tools: nil,
|
|
73
73
|
context: nil, provider_options: {}, metadata: nil)
|
|
74
74
|
config = context&.config || RubyLLM.config
|
|
75
75
|
instance = Provider.resolve!(provider).new(config)
|
|
76
76
|
payload = { provider: instance.slug, agent:, prompt:, metadata: }
|
|
77
77
|
RubyLLM.instrument('research_job.ruby_llm', payload, config:) do |event|
|
|
78
|
-
job = instance.research_later(prompt, agent:, with:,
|
|
78
|
+
job = instance.research_later(prompt, agent:, with:, provider_tools:, provider_options:)
|
|
79
79
|
event[:job_id] = job.id
|
|
80
80
|
event[:status] = job.status
|
|
81
81
|
job
|
|
@@ -5,9 +5,9 @@ module RubyLLM
|
|
|
5
5
|
# response: a web search the model ran, a code execution, or the results
|
|
6
6
|
# block a provider returned for one. They appear on
|
|
7
7
|
# Message#server_tool_calls when a chat enables tools with
|
|
8
|
-
# Chat#
|
|
8
|
+
# Chat#with_provider_tools.
|
|
9
9
|
#
|
|
10
|
-
# response = chat.
|
|
10
|
+
# response = chat.with_provider_tools(:web_search).ask "What changed in Ruby 3.5?"
|
|
11
11
|
# response.server_tool_calls.map(&:type) # => ["server_tool_use", "web_search_tool_result"]
|
|
12
12
|
#
|
|
13
13
|
# RubyLLM does not model each tool's result schema. #raw always holds the
|
data/lib/ruby_llm/speech.rb
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
module RubyLLM
|
|
4
4
|
module Tools # :nodoc:
|
|
5
|
-
# Normalizes and resolves the
|
|
6
|
-
# Chat#
|
|
5
|
+
# Normalizes and resolves the provider tools a chat enabled with
|
|
6
|
+
# Chat#with_provider_tools. Protocols declare an alias table mapping portable
|
|
7
7
|
# names such as +:web_search+ to their wire format; raw Hashes pass through
|
|
8
8
|
# verbatim so new provider tools work without a gem update. :nodoc:
|
|
9
|
-
module
|
|
10
|
-
# The result of resolving a chat's
|
|
9
|
+
module ProviderTools # :nodoc: all
|
|
10
|
+
# The result of resolving a chat's provider tools against a protocol's
|
|
11
11
|
# alias table: tool entries for the payload's tools slot, extra payload
|
|
12
12
|
# fields to merge, and request headers to add.
|
|
13
13
|
class Resolution
|
|
@@ -61,7 +61,7 @@ module RubyLLM
|
|
|
61
61
|
|
|
62
62
|
module_function
|
|
63
63
|
|
|
64
|
-
# Normalizes
|
|
64
|
+
# Normalizes with_provider_tools arguments into entry hashes:
|
|
65
65
|
# {name:, options:} for aliases and {raw:} for verbatim tool specs.
|
|
66
66
|
def normalize(tools, tools_with_options)
|
|
67
67
|
entries = tools.compact.map { |tool| normalize_positional(tool) }
|
|
@@ -74,13 +74,13 @@ module RubyLLM
|
|
|
74
74
|
when Hash then normalized_entry?(tool) ? tool : { raw: tool }
|
|
75
75
|
else
|
|
76
76
|
raise ArgumentError,
|
|
77
|
-
"
|
|
77
|
+
"Provider tools must be Symbols or Hashes, got #{tool.class}. " \
|
|
78
78
|
'Pass :web_search for a portable alias or the provider\'s tool definition as a Hash.'
|
|
79
79
|
end
|
|
80
80
|
end
|
|
81
81
|
|
|
82
82
|
# Entries that already went through normalize (an Agent's declared
|
|
83
|
-
#
|
|
83
|
+
# provider_tools, for example) pass through unchanged.
|
|
84
84
|
def normalized_entry?(hash)
|
|
85
85
|
hash.key?(:raw) ? hash.size == 1 : hash.size == 2 && hash.key?(:name) && hash.key?(:options)
|
|
86
86
|
end
|
|
@@ -132,7 +132,7 @@ module RubyLLM
|
|
|
132
132
|
empty_tokens = Tokens.new
|
|
133
133
|
payload = {
|
|
134
134
|
provider: provider_instance.slug,
|
|
135
|
-
provider_class: provider_instance.
|
|
135
|
+
provider_class: provider_instance.name,
|
|
136
136
|
model: model.id,
|
|
137
137
|
model_info: model,
|
|
138
138
|
language: language,
|
data/lib/ruby_llm/version.rb
CHANGED
data/lib/ruby_llm/video_job.rb
CHANGED
data/lib/ruby_llm.rb
CHANGED
|
@@ -44,7 +44,7 @@ loader.setup
|
|
|
44
44
|
|
|
45
45
|
# RubyLLM is an AI framework for Ruby and Rails. Build conversations and
|
|
46
46
|
# agents, generate media, process documents, and work with model providers
|
|
47
|
-
# through one Ruby API. The guides at https://rubyllm.com/
|
|
47
|
+
# through one Ruby API. The guides at https://rubyllm.com/ introduce
|
|
48
48
|
# each feature; this reference documents its classes, arguments, and results.
|
|
49
49
|
#
|
|
50
50
|
# RubyLLM.configure do |config|
|
|
@@ -75,7 +75,7 @@ loader.setup
|
|
|
75
75
|
#
|
|
76
76
|
# Subclass Tool and implement +execute+ to give the model an application
|
|
77
77
|
# action. Tool.requires_approval pauses execution for a human decision;
|
|
78
|
-
# Chat#approve and Chat#deny record it. Chat#
|
|
78
|
+
# Chat#approve and Chat#deny record it. Chat#with_provider_tools enables
|
|
79
79
|
# provider-executed tools such as web search, code execution, and remote MCP.
|
|
80
80
|
# Their calls appear as ServerToolCall values, with Citation values for sources.
|
|
81
81
|
#
|
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: 2.0.0
|
|
4
|
+
version: 2.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Carmine Paolino
|
|
@@ -589,7 +589,7 @@ files:
|
|
|
589
589
|
- lib/ruby_llm/tokens.rb
|
|
590
590
|
- lib/ruby_llm/tool.rb
|
|
591
591
|
- lib/ruby_llm/tool_call.rb
|
|
592
|
-
- lib/ruby_llm/tools/
|
|
592
|
+
- lib/ruby_llm/tools/provider_tools.rb
|
|
593
593
|
- lib/ruby_llm/transcription.rb
|
|
594
594
|
- lib/ruby_llm/transcription/wav_audio.rb
|
|
595
595
|
- lib/ruby_llm/transcription_chunk.rb
|
|
@@ -612,24 +612,24 @@ metadata:
|
|
|
612
612
|
homepage_uri: https://rubyllm.com
|
|
613
613
|
source_code_uri: https://github.com/crmne/ruby_llm
|
|
614
614
|
changelog_uri: https://github.com/crmne/ruby_llm/releases
|
|
615
|
-
documentation_uri: https://rubyllm.com/
|
|
615
|
+
documentation_uri: https://rubyllm.com/
|
|
616
616
|
bug_tracker_uri: https://github.com/crmne/ruby_llm/issues
|
|
617
617
|
funding_uri: https://github.com/sponsors/crmne
|
|
618
618
|
rubygems_mfa_required: 'true'
|
|
619
619
|
post_install_message: |
|
|
620
|
-
RubyLLM 2.0.0
|
|
620
|
+
RubyLLM 2.0.0
|
|
621
621
|
|
|
622
622
|
2.0 renames several APIs and changes what message content returns. Coming
|
|
623
623
|
from 1.x? Read the upgrade guide before you boot:
|
|
624
624
|
|
|
625
|
-
https://rubyllm.com/
|
|
625
|
+
https://rubyllm.com/upgrading/
|
|
626
626
|
|
|
627
627
|
The Rails upgrade uses forward-only preparation, backfill, and finish
|
|
628
628
|
phases, with cleanup later. Rename mode is the default; optional copy
|
|
629
629
|
mode supports a controlled return to 1.16. Read its requirements in the
|
|
630
630
|
upgrade guide and rehearse on a recent production snapshot.
|
|
631
631
|
|
|
632
|
-
Agent skill: https://rubyllm.com/
|
|
632
|
+
Agent skill: https://rubyllm.com/ai-coding-assistants/
|
|
633
633
|
rdoc_options: []
|
|
634
634
|
require_paths:
|
|
635
635
|
- lib
|
|
@@ -644,7 +644,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
644
644
|
- !ruby/object:Gem::Version
|
|
645
645
|
version: '0'
|
|
646
646
|
requirements: []
|
|
647
|
-
rubygems_version: 4.0.
|
|
647
|
+
rubygems_version: 4.0.20
|
|
648
648
|
specification_version: 4
|
|
649
649
|
summary: 'Build AI features the Ruby way: a delightful Ruby AI framework for every
|
|
650
650
|
major AI provider.'
|