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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.rdoc_options +2 -2
  3. data/README.md +34 -23
  4. data/lib/generators/ruby_llm/generator_helpers.rb +4 -1
  5. data/lib/generators/ruby_llm/install/templates/create_chats_migration.rb.tt +1 -1
  6. data/lib/generators/ruby_llm/install/templates/create_messages_migration.rb.tt +1 -1
  7. data/lib/generators/ruby_llm/install/templates/create_ruby_llm_records_migration.rb.tt +5 -5
  8. data/lib/generators/ruby_llm/upgrade/online_copy_migration/data.rb +9 -0
  9. data/lib/generators/ruby_llm/upgrade/online_copy_migration.rb +5 -1
  10. data/lib/generators/ruby_llm/upgrade/templates/backfill_v2_data.rb.tt +6 -2
  11. data/lib/generators/ruby_llm/upgrade/templates/finish_v2_upgrade.rb.tt +8 -2
  12. data/lib/generators/ruby_llm/upgrade/templates/prepare_v2_upgrade.rb.tt +2 -2
  13. data/lib/generators/ruby_llm/upgrade/templates/ruby_llm_upgrade.rb.tt +1 -1
  14. data/lib/generators/ruby_llm/upgrade/templates/upgrade_initializer.rb.tt +1 -1
  15. data/lib/generators/ruby_llm/upgrade/upgrade_generator.rb +11 -0
  16. data/lib/generators/ruby_llm/upgrade/upgrade_migration.rb +2 -1
  17. data/lib/ruby_llm/active_record/attachment_helpers.rb +81 -3
  18. data/lib/ruby_llm/active_record/chat_methods.rb +11 -8
  19. data/lib/ruby_llm/agent.rb +17 -17
  20. data/lib/ruby_llm/batch.rb +2 -2
  21. data/lib/ruby_llm/chat.rb +17 -17
  22. data/lib/ruby_llm/embedding.rb +1 -1
  23. data/lib/ruby_llm/error.rb +1 -1
  24. data/lib/ruby_llm/image.rb +1 -1
  25. data/lib/ruby_llm/message.rb +15 -1
  26. data/lib/ruby_llm/models.json +1654 -1791
  27. data/lib/ruby_llm/moderation.rb +1 -1
  28. data/lib/ruby_llm/ocr.rb +1 -1
  29. data/lib/ruby_llm/protocol.rb +36 -13
  30. data/lib/ruby_llm/protocols/anthropic/chat.rb +1 -6
  31. data/lib/ruby_llm/protocols/chat_completions/chat.rb +2 -11
  32. data/lib/ruby_llm/protocols/converse/chat.rb +0 -1
  33. data/lib/ruby_llm/protocols/responses/chat.rb +0 -10
  34. data/lib/ruby_llm/protocols/vertexai/research.rb +8 -8
  35. data/lib/ruby_llm/provider.rb +4 -4
  36. data/lib/ruby_llm/providers/openrouter/chat.rb +5 -5
  37. data/lib/ruby_llm/rerank.rb +1 -1
  38. data/lib/ruby_llm/research_job.rb +4 -4
  39. data/lib/ruby_llm/server_tool_call.rb +2 -2
  40. data/lib/ruby_llm/speech.rb +1 -1
  41. data/lib/ruby_llm/tools/{server_tools.rb → provider_tools.rb} +7 -7
  42. data/lib/ruby_llm/transcription.rb +1 -1
  43. data/lib/ruby_llm/version.rb +1 -1
  44. data/lib/ruby_llm/video_job.rb +1 -1
  45. data/lib/ruby_llm.rb +2 -2
  46. metadata +7 -7
@@ -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.class.display_name,
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
@@ -62,7 +62,7 @@ module RubyLLM
62
62
  config: config)
63
63
  payload = {
64
64
  provider: provider_instance.slug,
65
- provider_class: provider_instance.class.display_name,
65
+ provider_class: provider_instance.name,
66
66
  model: model.id,
67
67
  model_info: model,
68
68
  pages: pages,
@@ -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, server_tools: [], compaction: nil, end_user: nil, &)
100
- resolution = resolve_server_tools_for_request(server_tools)
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:, server_tools:,
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, server_tools: [], compaction: nil, end_user: nil)
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 = apply_server_tools(payload, server_tools)
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 server-tool support override this;
192
- # +nil+ means the protocol has no server-tool support at all.
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
- def resolve_server_tools_for_request(entries)
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 server-tool support through RubyLLM yet. " \
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::ServerTools.resolve(entries, aliases: aliases, owner: @provider.name)
519
+ RubyLLM::Tools::ProviderTools.resolve(entries, aliases: aliases, owner: @provider.name)
497
520
  end
498
521
 
499
- def apply_server_tools(payload, entries)
500
- resolution = resolve_server_tools_for_request(entries)
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
- # Server tools join function tools in the payload's tools array. The
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 && !explicit_boundaries
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, messages, caching)
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, messages, caching)
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, server_tools: nil, provider_options: {})
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:, server_tools:, provider_options:)
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:, server_tools:, provider_options:)
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 server_tools.nil?
80
+ payload[:tools] = [] unless provider_tools.nil?
81
81
  options = render_research_options(provider_options)
82
- entries = if server_tools.is_a?(Hash)
83
- RubyLLM::Tools::ServerTools.normalize([], server_tools)
82
+ entries = if provider_tools.is_a?(Hash)
83
+ RubyLLM::Tools::ProviderTools.normalize([], provider_tools)
84
84
  else
85
- RubyLLM::Tools::ServerTools.normalize(Array(server_tools), {})
85
+ RubyLLM::Tools::ProviderTools.normalize(Array(provider_tools), {})
86
86
  end
87
- apply_server_tools(payload, entries).merge(options)
87
+ apply_provider_tools(payload, entries).merge(options)
88
88
  end
89
89
 
90
90
  def validate_research_attachments(attachments)
@@ -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, server_tools: [],
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
- server_tools: server_tools,
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: [], server_tools: [], compaction: nil, end_user: nil)
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
- server_tools: server_tools,
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 && !cache_boundaries?(messages)
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
@@ -81,7 +81,7 @@ module RubyLLM
81
81
  empty_tokens = Tokens.new
82
82
  payload = {
83
83
  provider: provider_instance.slug,
84
- provider_class: provider_instance.class.display_name,
84
+ provider_class: provider_instance.name,
85
85
  model: model.id,
86
86
  model_info: model,
87
87
  query: query,
@@ -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
- # +server_tools:+ accepts an array of aliases or a Hash of aliases
71
- # and their options, as on Chat#with_server_tools.
72
- def self.research_later(prompt, provider:, agent:, with: nil, server_tools: 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:, server_tools:, provider_options:)
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#with_server_tools.
8
+ # Chat#with_provider_tools.
9
9
  #
10
- # response = chat.with_server_tools(:web_search).ask "What changed in Ruby 3.5?"
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
@@ -91,7 +91,7 @@ module RubyLLM
91
91
 
92
92
  payload = {
93
93
  provider: provider_instance.slug,
94
- provider_class: provider_instance.class.display_name,
94
+ provider_class: provider_instance.name,
95
95
  model: model.id,
96
96
  model_info: model,
97
97
  input: input,
@@ -2,12 +2,12 @@
2
2
 
3
3
  module RubyLLM
4
4
  module Tools # :nodoc:
5
- # Normalizes and resolves the server tools a chat enabled with
6
- # Chat#with_server_tools. Protocols declare an alias table mapping portable
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 ServerTools # :nodoc: all
10
- # The result of resolving a chat's server tools against a protocol'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 with_server_tools arguments into entry hashes:
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
- "Server tools must be Symbols or Hashes, got #{tool.class}. " \
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
- # server_tools, for example) pass through unchanged.
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.class.display_name,
135
+ provider_class: provider_instance.name,
136
136
  model: model.id,
137
137
  model_info: model,
138
138
  language: language,
@@ -2,5 +2,5 @@
2
2
 
3
3
  module RubyLLM
4
4
  # The version of the ruby_llm gem, as a string.
5
- VERSION = '2.0.0.rc3'
5
+ VERSION = '2.0.0'
6
6
  end
@@ -50,7 +50,7 @@ module RubyLLM
50
50
  config: config)
51
51
  payload = {
52
52
  provider: provider_instance.slug,
53
- provider_class: provider_instance.class.display_name,
53
+ provider_class: provider_instance.name,
54
54
  model: model.id,
55
55
  model_info: model,
56
56
  prompt: prompt,
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/next/ introduce
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#with_server_tools enables
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.rc3
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/server_tools.rb
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/next/
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.rc3
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/next/upgrading/
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/next/ai-coding-assistants/
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.16
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.'