ruby_llm 1.5.1 → 1.6.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 (80) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/ruby_llm/active_record/acts_as.rb +46 -6
  4. data/lib/ruby_llm/aliases.json +27 -3
  5. data/lib/ruby_llm/chat.rb +27 -6
  6. data/lib/ruby_llm/configuration.rb +7 -18
  7. data/lib/ruby_llm/connection.rb +11 -6
  8. data/lib/ruby_llm/context.rb +2 -3
  9. data/lib/ruby_llm/embedding.rb +3 -4
  10. data/lib/ruby_llm/error.rb +2 -2
  11. data/lib/ruby_llm/image.rb +3 -4
  12. data/lib/ruby_llm/message.rb +4 -0
  13. data/lib/ruby_llm/models.json +7306 -6676
  14. data/lib/ruby_llm/models.rb +22 -31
  15. data/lib/ruby_llm/provider.rb +150 -89
  16. data/lib/ruby_llm/providers/anthropic/capabilities.rb +1 -2
  17. data/lib/ruby_llm/providers/anthropic/chat.rb +1 -1
  18. data/lib/ruby_llm/providers/anthropic/embeddings.rb +1 -1
  19. data/lib/ruby_llm/providers/anthropic/media.rb +1 -1
  20. data/lib/ruby_llm/providers/anthropic/models.rb +1 -1
  21. data/lib/ruby_llm/providers/anthropic/streaming.rb +1 -1
  22. data/lib/ruby_llm/providers/anthropic/tools.rb +1 -1
  23. data/lib/ruby_llm/providers/anthropic.rb +17 -22
  24. data/lib/ruby_llm/providers/bedrock/capabilities.rb +3 -63
  25. data/lib/ruby_llm/providers/bedrock/chat.rb +5 -4
  26. data/lib/ruby_llm/providers/bedrock/media.rb +1 -1
  27. data/lib/ruby_llm/providers/bedrock/models.rb +5 -6
  28. data/lib/ruby_llm/providers/bedrock/signing.rb +1 -1
  29. data/lib/ruby_llm/providers/bedrock/streaming/base.rb +5 -4
  30. data/lib/ruby_llm/providers/bedrock/streaming/content_extraction.rb +1 -1
  31. data/lib/ruby_llm/providers/bedrock/streaming/message_processing.rb +1 -1
  32. data/lib/ruby_llm/providers/bedrock/streaming/payload_processing.rb +1 -1
  33. data/lib/ruby_llm/providers/bedrock/streaming/prelude_handling.rb +1 -1
  34. data/lib/ruby_llm/providers/bedrock/streaming.rb +1 -1
  35. data/lib/ruby_llm/providers/bedrock.rb +26 -31
  36. data/lib/ruby_llm/providers/deepseek/capabilities.rb +16 -57
  37. data/lib/ruby_llm/providers/deepseek/chat.rb +1 -1
  38. data/lib/ruby_llm/providers/deepseek.rb +12 -17
  39. data/lib/ruby_llm/providers/gemini/capabilities.rb +1 -1
  40. data/lib/ruby_llm/providers/gemini/chat.rb +1 -1
  41. data/lib/ruby_llm/providers/gemini/embeddings.rb +1 -1
  42. data/lib/ruby_llm/providers/gemini/images.rb +1 -1
  43. data/lib/ruby_llm/providers/gemini/media.rb +1 -1
  44. data/lib/ruby_llm/providers/gemini/models.rb +1 -1
  45. data/lib/ruby_llm/providers/gemini/streaming.rb +1 -1
  46. data/lib/ruby_llm/providers/gemini/tools.rb +1 -7
  47. data/lib/ruby_llm/providers/gemini.rb +18 -23
  48. data/lib/ruby_llm/providers/gpustack/chat.rb +1 -1
  49. data/lib/ruby_llm/providers/gpustack/models.rb +1 -1
  50. data/lib/ruby_llm/providers/gpustack.rb +16 -19
  51. data/lib/ruby_llm/providers/mistral/capabilities.rb +1 -1
  52. data/lib/ruby_llm/providers/mistral/chat.rb +1 -1
  53. data/lib/ruby_llm/providers/mistral/embeddings.rb +1 -1
  54. data/lib/ruby_llm/providers/mistral/models.rb +1 -1
  55. data/lib/ruby_llm/providers/mistral.rb +14 -19
  56. data/lib/ruby_llm/providers/ollama/chat.rb +1 -1
  57. data/lib/ruby_llm/providers/ollama/media.rb +1 -1
  58. data/lib/ruby_llm/providers/ollama.rb +13 -18
  59. data/lib/ruby_llm/providers/openai/capabilities.rb +2 -2
  60. data/lib/ruby_llm/providers/openai/chat.rb +2 -2
  61. data/lib/ruby_llm/providers/openai/embeddings.rb +1 -1
  62. data/lib/ruby_llm/providers/openai/images.rb +1 -1
  63. data/lib/ruby_llm/providers/openai/media.rb +1 -1
  64. data/lib/ruby_llm/providers/openai/models.rb +1 -1
  65. data/lib/ruby_llm/providers/openai/streaming.rb +1 -1
  66. data/lib/ruby_llm/providers/openai/tools.rb +1 -1
  67. data/lib/ruby_llm/providers/openai.rb +24 -36
  68. data/lib/ruby_llm/providers/openrouter/models.rb +1 -1
  69. data/lib/ruby_llm/providers/openrouter.rb +9 -14
  70. data/lib/ruby_llm/providers/perplexity/capabilities.rb +1 -30
  71. data/lib/ruby_llm/providers/perplexity/chat.rb +1 -1
  72. data/lib/ruby_llm/providers/perplexity/models.rb +1 -1
  73. data/lib/ruby_llm/providers/perplexity.rb +13 -18
  74. data/lib/ruby_llm/stream_accumulator.rb +3 -3
  75. data/lib/ruby_llm/streaming.rb +16 -3
  76. data/lib/ruby_llm/tool.rb +19 -0
  77. data/lib/ruby_llm/version.rb +1 -1
  78. data/lib/tasks/models_docs.rake +18 -11
  79. data/lib/tasks/models_update.rake +5 -4
  80. metadata +1 -1
@@ -2,14 +2,11 @@
2
2
 
3
3
  module RubyLLM
4
4
  module Providers
5
- module Bedrock
5
+ class Bedrock
6
6
  # Determines capabilities and pricing for AWS Bedrock models
7
7
  module Capabilities
8
8
  module_function
9
9
 
10
- # Returns the context window size for the given model ID
11
- # @param model_id [String] the model identifier
12
- # @return [Integer] the context window size in tokens
13
10
  def context_window_for(model_id)
14
11
  case model_id
15
12
  when /anthropic\.claude-2/ then 100_000
@@ -17,95 +14,56 @@ module RubyLLM
17
14
  end
18
15
  end
19
16
 
20
- # Returns the maximum output tokens for the given model ID
21
- # @param model_id [String] the model identifier
22
- # @return [Integer] the maximum output tokens
23
17
  def max_tokens_for(_model_id)
24
18
  4_096
25
19
  end
26
20
 
27
- # Returns the input price per million tokens for the given model ID
28
- # @param model_id [String] the model identifier
29
- # @return [Float] the price per million tokens for input
30
21
  def input_price_for(model_id)
31
22
  PRICES.dig(model_family(model_id), :input) || default_input_price
32
23
  end
33
24
 
34
- # Returns the output price per million tokens for the given model ID
35
- # @param model_id [String] the model identifier
36
- # @return [Float] the price per million tokens for output
37
25
  def output_price_for(model_id)
38
26
  PRICES.dig(model_family(model_id), :output) || default_output_price
39
27
  end
40
28
 
41
- # Determines if the model supports chat capabilities
42
- # @param model_id [String] the model identifier
43
- # @return [Boolean] true if the model supports chat
44
29
  def supports_chat?(model_id)
45
30
  model_id.match?(/anthropic\.claude/)
46
31
  end
47
32
 
48
- # Determines if the model supports streaming capabilities
49
- # @param model_id [String] the model identifier
50
- # @return [Boolean] true if the model supports streaming
51
33
  def supports_streaming?(model_id)
52
34
  model_id.match?(/anthropic\.claude/)
53
35
  end
54
36
 
55
- # Determines if the model supports image input/output
56
- # @param model_id [String] the model identifier
57
- # @return [Boolean] true if the model supports images
58
37
  def supports_images?(model_id)
59
38
  model_id.match?(/anthropic\.claude/)
60
39
  end
61
40
 
62
- # Determines if the model supports vision capabilities
63
- # @param model_id [String] the model identifier
64
- # @return [Boolean] true if the model supports vision
65
41
  def supports_vision?(model_id)
66
42
  model_id.match?(/anthropic\.claude/)
67
43
  end
68
44
 
69
- # Determines if the model supports function calling
70
- # @param model_id [String] the model identifier
71
- # @return [Boolean] true if the model supports functions
72
45
  def supports_functions?(model_id)
73
46
  model_id.match?(/anthropic\.claude/)
74
47
  end
75
48
 
76
- # Determines if the model supports audio input/output
77
- # @param model_id [String] the model identifier
78
- # @return [Boolean] true if the model supports audio
79
49
  def supports_audio?(_model_id)
80
50
  false
81
51
  end
82
52
 
83
- # Determines if the model supports JSON mode
84
- # @param model_id [String] the model identifier
85
- # @return [Boolean] true if the model supports JSON mode
86
53
  def supports_json_mode?(model_id)
87
54
  model_id.match?(/anthropic\.claude/)
88
55
  end
89
56
 
90
- # Formats the model ID into a human-readable display name
91
- # @param model_id [String] the model identifier
92
- # @return [String] the formatted display name
93
57
  def format_display_name(model_id)
94
58
  model_id.then { |id| humanize(id) }
95
59
  end
96
60
 
97
- # Determines the type of model
98
- # @param model_id [String] the model identifier
99
- # @return [String] the model type (chat, embedding, image, audio)
100
61
  def model_type(_model_id)
101
62
  'chat'
102
63
  end
103
64
 
104
- # Determines if the model supports structured output
105
- # @param model_id [String] the model identifier
106
- # @return [Boolean] true if the model supports structured output
107
- def supports_structured_output?(model_id)
108
- model_id.match?(/anthropic\.claude/)
65
+ def supports_structured_output?(_model_id)
66
+ false
109
67
  end
110
68
 
111
69
  # Model family patterns for capability lookup
@@ -120,9 +78,6 @@ module RubyLLM
120
78
  /anthropic\.claude-instant/ => :claude_instant
121
79
  }.freeze
122
80
 
123
- # Determines the model family for pricing and capability lookup
124
- # @param model_id [String] the model identifier
125
- # @return [Symbol] the model family identifier
126
81
  def model_family(model_id)
127
82
  MODEL_FAMILIES.find { |pattern, _family| model_id.match?(pattern) }&.last || :other
128
83
  end
@@ -137,21 +92,14 @@ module RubyLLM
137
92
  claude_instant: { input: 0.8, output: 2.4 }
138
93
  }.freeze
139
94
 
140
- # Default input price when model-specific pricing is not available
141
- # @return [Float] the default price per million tokens
142
95
  def default_input_price
143
96
  0.1
144
97
  end
145
98
 
146
- # Default output price when model-specific pricing is not available
147
- # @return [Float] the default price per million tokens
148
99
  def default_output_price
149
100
  0.2
150
101
  end
151
102
 
152
- # Converts a model ID to a human-readable format
153
- # @param id [String] the model identifier
154
- # @return [String] the humanized model name
155
103
  def humanize(id)
156
104
  id.tr('-', ' ')
157
105
  .split('.')
@@ -167,7 +115,6 @@ module RubyLLM
167
115
  output: ['text']
168
116
  }
169
117
 
170
- # Vision support for Claude models
171
118
  if model_id.match?(/anthropic\.claude/) && supports_vision?(model_id)
172
119
  modalities[:input] << 'image'
173
120
  modalities[:input] << 'pdf'
@@ -179,18 +126,12 @@ module RubyLLM
179
126
  def capabilities_for(model_id)
180
127
  capabilities = []
181
128
 
182
- # Streaming
183
129
  capabilities << 'streaming' if model_id.match?(/anthropic\.claude/)
184
130
 
185
- # Function calling & structured output
186
131
  capabilities << 'function_calling' if supports_functions?(model_id)
187
132
 
188
- capabilities << 'structured_output' if supports_json_mode?(model_id)
189
-
190
- # Extended thinking for 3.7 models
191
133
  capabilities << 'reasoning' if model_id.match?(/claude-3-7/)
192
134
 
193
- # Batch capabilities for newer Claude models
194
135
  if model_id.match?(/claude-3\.5|claude-3-7/)
195
136
  capabilities << 'batch'
196
137
  capabilities << 'citations'
@@ -208,7 +149,6 @@ module RubyLLM
208
149
  output_per_million: prices[:output]
209
150
  }
210
151
 
211
- # Batch pricing - typically 50% of standard
212
152
  batch_pricing = {
213
153
  input_per_million: prices[:input] * 0.5,
214
154
  output_per_million: prices[:output] * 0.5
@@ -2,16 +2,17 @@
2
2
 
3
3
  module RubyLLM
4
4
  module Providers
5
- module Bedrock
5
+ class Bedrock
6
6
  # Chat methods for the AWS Bedrock API implementation
7
7
  module Chat
8
8
  module_function
9
9
 
10
- def sync_response(connection, payload)
11
- signature = sign_request("#{connection.connection.url_prefix}#{completion_url}", config: connection.config,
12
- payload:)
10
+ def sync_response(connection, payload, additional_headers = {})
11
+ signature = sign_request("#{connection.connection.url_prefix}#{completion_url}", payload:)
13
12
  response = connection.post completion_url, payload do |req|
14
13
  req.headers.merge! build_headers(signature.headers, streaming: block_given?)
14
+ # Merge additional headers, with existing headers taking precedence
15
+ req.headers = additional_headers.merge(req.headers) unless additional_headers.empty?
15
16
  end
16
17
  Anthropic::Chat.parse_completion_response response
17
18
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module RubyLLM
4
4
  module Providers
5
- module Bedrock
5
+ class Bedrock
6
6
  # Media handling methods for the Bedrock API integration
7
7
  # NOTE: Bedrock does not support url attachments
8
8
  module Media
@@ -2,15 +2,14 @@
2
2
 
3
3
  module RubyLLM
4
4
  module Providers
5
- module Bedrock
5
+ class Bedrock
6
6
  # Models methods for the AWS Bedrock API implementation
7
7
  module Models
8
- def list_models(connection:)
9
- config = connection.config
10
- mgmt_api_base = "https://bedrock.#{config.bedrock_region}.amazonaws.com"
8
+ def list_models
9
+ mgmt_api_base = "https://bedrock.#{@config.bedrock_region}.amazonaws.com"
11
10
  full_models_url = "#{mgmt_api_base}/#{models_url}"
12
- signature = sign_request(full_models_url, config: config, method: :get)
13
- response = connection.get(full_models_url) do |req|
11
+ signature = sign_request(full_models_url, method: :get)
12
+ response = @connection.get(full_models_url) do |req|
14
13
  req.headers.merge! signature.headers
15
14
  end
16
15
 
@@ -14,7 +14,7 @@ require 'pathname'
14
14
 
15
15
  module RubyLLM
16
16
  module Providers
17
- module Bedrock
17
+ class Bedrock
18
18
  module Signing
19
19
  # Utility class for creating AWS signature version 4 signature. This class
20
20
  # provides a method for generating signatures:
@@ -2,7 +2,7 @@
2
2
 
3
3
  module RubyLLM
4
4
  module Providers
5
- module Bedrock
5
+ class Bedrock
6
6
  module Streaming
7
7
  # Base module for AWS Bedrock streaming functionality.
8
8
  # Serves as the core module that includes all other streaming-related modules
@@ -29,13 +29,14 @@ module RubyLLM
29
29
  "model/#{@model_id}/invoke-with-response-stream"
30
30
  end
31
31
 
32
- def stream_response(connection, payload, &block)
33
- signature = sign_request("#{connection.connection.url_prefix}#{stream_url}", config: connection.config,
34
- payload:)
32
+ def stream_response(connection, payload, additional_headers = {}, &block)
33
+ signature = sign_request("#{connection.connection.url_prefix}#{stream_url}", payload:)
35
34
  accumulator = StreamAccumulator.new
36
35
 
37
36
  response = connection.post stream_url, payload do |req|
38
37
  req.headers.merge! build_headers(signature.headers, streaming: block_given?)
38
+ # Merge additional headers, with existing headers taking precedence
39
+ req.headers = additional_headers.merge(req.headers) unless additional_headers.empty?
39
40
  req.options.on_data = handle_stream do |chunk|
40
41
  accumulator.add chunk
41
42
  block.call chunk
@@ -2,7 +2,7 @@
2
2
 
3
3
  module RubyLLM
4
4
  module Providers
5
- module Bedrock
5
+ class Bedrock
6
6
  module Streaming
7
7
  # Module for handling content extraction from AWS Bedrock streaming responses.
8
8
  # Provides methods to extract and process various types of content from the response data.
@@ -2,7 +2,7 @@
2
2
 
3
3
  module RubyLLM
4
4
  module Providers
5
- module Bedrock
5
+ class Bedrock
6
6
  module Streaming
7
7
  # Module for processing streaming messages from AWS Bedrock.
8
8
  # Handles the core message processing logic, including validation and chunking.
@@ -4,7 +4,7 @@ require 'base64'
4
4
 
5
5
  module RubyLLM
6
6
  module Providers
7
- module Bedrock
7
+ class Bedrock
8
8
  module Streaming
9
9
  # Module for processing payloads from AWS Bedrock streaming responses.
10
10
  # Handles JSON payload extraction, decoding, and chunk creation.
@@ -2,7 +2,7 @@
2
2
 
3
3
  module RubyLLM
4
4
  module Providers
5
- module Bedrock
5
+ class Bedrock
6
6
  module Streaming
7
7
  # Module for handling message preludes in AWS Bedrock streaming responses.
8
8
  # Manages the parsing and validation of message headers and prelude data.
@@ -8,7 +8,7 @@ require_relative 'streaming/prelude_handling'
8
8
 
9
9
  module RubyLLM
10
10
  module Providers
11
- module Bedrock
11
+ class Bedrock
12
12
  # Streaming implementation for the AWS Bedrock API.
13
13
  # This module provides functionality for handling streaming responses from AWS Bedrock,
14
14
  # including message processing, content extraction, and error handling.
@@ -7,19 +7,16 @@ module RubyLLM
7
7
  module Providers
8
8
  # AWS Bedrock API integration. Handles chat completion and streaming
9
9
  # for Claude models.
10
- module Bedrock
11
- extend Provider
12
- extend Bedrock::Chat
13
- extend Bedrock::Streaming
14
- extend Bedrock::Models
15
- extend Bedrock::Signing
16
- extend Bedrock::Media
17
- extend Anthropic::Tools
10
+ class Bedrock < Provider
11
+ include Bedrock::Chat
12
+ include Bedrock::Streaming
13
+ include Bedrock::Models
14
+ include Bedrock::Signing
15
+ include Bedrock::Media
16
+ include Anthropic::Tools
18
17
 
19
- module_function
20
-
21
- def api_base(config)
22
- "https://bedrock-runtime.#{config.bedrock_region}.amazonaws.com"
18
+ def api_base
19
+ "https://bedrock-runtime.#{@config.bedrock_region}.amazonaws.com"
23
20
  end
24
21
 
25
22
  def parse_error(response)
@@ -38,25 +35,25 @@ module RubyLLM
38
35
  end
39
36
  end
40
37
 
41
- def sign_request(url, config:, method: :post, payload: nil)
42
- signer = create_signer(config)
43
- request = build_request(url, config:, method:, payload:)
38
+ def sign_request(url, method: :post, payload: nil)
39
+ signer = create_signer
40
+ request = build_request(url, method:, payload:)
44
41
  signer.sign_request(request)
45
42
  end
46
43
 
47
- def create_signer(config)
44
+ def create_signer
48
45
  Signing::Signer.new({
49
- access_key_id: config.bedrock_api_key,
50
- secret_access_key: config.bedrock_secret_key,
51
- session_token: config.bedrock_session_token,
52
- region: config.bedrock_region,
46
+ access_key_id: @config.bedrock_api_key,
47
+ secret_access_key: @config.bedrock_secret_key,
48
+ session_token: @config.bedrock_session_token,
49
+ region: @config.bedrock_region,
53
50
  service: 'bedrock'
54
51
  })
55
52
  end
56
53
 
57
- def build_request(url, config:, method: :post, payload: nil)
54
+ def build_request(url, method: :post, payload: nil)
58
55
  {
59
- connection: connection(config),
56
+ connection: @connection,
60
57
  http_method: method,
61
58
  url: url || completion_url,
62
59
  body: payload ? JSON.generate(payload, ascii_only: false) : nil
@@ -72,16 +69,14 @@ module RubyLLM
72
69
  )
73
70
  end
74
71
 
75
- def capabilities
76
- Bedrock::Capabilities
77
- end
78
-
79
- def slug
80
- 'bedrock'
81
- end
72
+ class << self
73
+ def capabilities
74
+ Bedrock::Capabilities
75
+ end
82
76
 
83
- def configuration_requirements
84
- %i[bedrock_api_key bedrock_secret_key bedrock_region]
77
+ def configuration_requirements
78
+ %i[bedrock_api_key bedrock_secret_key bedrock_region]
79
+ end
85
80
  end
86
81
  end
87
82
  end
@@ -2,14 +2,11 @@
2
2
 
3
3
  module RubyLLM
4
4
  module Providers
5
- module DeepSeek
5
+ class DeepSeek
6
6
  # Determines capabilities and pricing for DeepSeek models
7
7
  module Capabilities
8
8
  module_function
9
9
 
10
- # Returns the context window size for the given model
11
- # @param model_id [String] the model identifier
12
- # @return [Integer] the context window size in tokens
13
10
  def context_window_for(model_id)
14
11
  case model_id
15
12
  when /deepseek-(?:chat|reasoner)/ then 64_000
@@ -17,61 +14,37 @@ module RubyLLM
17
14
  end
18
15
  end
19
16
 
20
- # Returns the maximum number of tokens that can be generated
21
- # @param model_id [String] the model identifier
22
- # @return [Integer] the maximum number of tokens
23
17
  def max_tokens_for(model_id)
24
18
  case model_id
25
19
  when /deepseek-(?:chat|reasoner)/ then 8_192
26
- else 4_096 # Default if max_tokens not specified
20
+ else 4_096
27
21
  end
28
22
  end
29
23
 
30
- # Returns the price per million tokens for input (cache miss)
31
- # @param model_id [String] the model identifier
32
- # @return [Float] the price per million tokens in USD
33
24
  def input_price_for(model_id)
34
25
  PRICES.dig(model_family(model_id), :input_miss) || default_input_price
35
26
  end
36
27
 
37
- # Returns the price per million tokens for output
38
- # @param model_id [String] the model identifier
39
- # @return [Float] the price per million tokens in USD
40
28
  def output_price_for(model_id)
41
29
  PRICES.dig(model_family(model_id), :output) || default_output_price
42
30
  end
43
31
 
44
- # Returns the price per million tokens for input with cache hit
45
- # @param model_id [String] the model identifier
46
- # @return [Float] the price per million tokens in USD
47
32
  def cache_hit_price_for(model_id)
48
33
  PRICES.dig(model_family(model_id), :input_hit) || default_cache_hit_price
49
34
  end
50
35
 
51
- # Determines if the model supports vision capabilities
52
- # @param model_id [String] the model identifier
53
- # @return [Boolean] true if the model supports vision
54
36
  def supports_vision?(_model_id)
55
- false # DeepSeek models don't currently support vision
37
+ false
56
38
  end
57
39
 
58
- # Determines if the model supports function calling
59
- # @param model_id [String] the model identifier
60
- # @return [Boolean] true if the model supports function calling
61
40
  def supports_functions?(model_id)
62
- model_id.match?(/deepseek-chat/) # Only deepseek-chat supports function calling
41
+ model_id.match?(/deepseek-chat/)
63
42
  end
64
43
 
65
- # Determines if the model supports JSON mode
66
- # @param model_id [String] the model identifier
67
- # @return [Boolean] true if the model supports JSON mode
68
44
  def supports_json_mode?(_model_id)
69
- false # DeepSeek function calling is unstable
45
+ false
70
46
  end
71
47
 
72
- # Returns a formatted display name for the model
73
- # @param model_id [String] the model identifier
74
- # @return [String] the formatted display name
75
48
  def format_display_name(model_id)
76
49
  case model_id
77
50
  when 'deepseek-chat' then 'DeepSeek V3'
@@ -83,53 +56,41 @@ module RubyLLM
83
56
  end
84
57
  end
85
58
 
86
- # Returns the model type
87
- # @param model_id [String] the model identifier
88
- # @return [String] the model type (e.g., 'chat')
89
59
  def model_type(_model_id)
90
- 'chat' # All DeepSeek models are chat models
60
+ 'chat'
91
61
  end
92
62
 
93
- # Returns the model family
94
- # @param model_id [String] the model identifier
95
- # @return [Symbol] the model family
96
63
  def model_family(model_id)
97
64
  case model_id
98
65
  when /deepseek-reasoner/ then :reasoner
99
- else :chat # Default to chat family
66
+ else :chat
100
67
  end
101
68
  end
102
69
 
103
70
  # Pricing information for DeepSeek models (USD per 1M tokens)
104
71
  PRICES = {
105
72
  chat: {
106
- input_hit: 0.07, # $0.07 per million tokens on cache hit
107
- input_miss: 0.27, # $0.27 per million tokens on cache miss
108
- output: 1.10 # $1.10 per million tokens output
73
+ input_hit: 0.07,
74
+ input_miss: 0.27,
75
+ output: 1.10
109
76
  },
110
77
  reasoner: {
111
- input_hit: 0.14, # $0.14 per million tokens on cache hit
112
- input_miss: 0.55, # $0.55 per million tokens on cache miss
113
- output: 2.19 # $2.19 per million tokens output
78
+ input_hit: 0.14,
79
+ input_miss: 0.55,
80
+ output: 2.19
114
81
  }
115
82
  }.freeze
116
83
 
117
- # Default input price when model family can't be determined
118
- # @return [Float] the default input price
119
84
  def default_input_price
120
- 0.27 # Default to chat cache miss price
85
+ 0.27
121
86
  end
122
87
 
123
- # Default output price when model family can't be determined
124
- # @return [Float] the default output price
125
88
  def default_output_price
126
- 1.10 # Default to chat output price
89
+ 1.10
127
90
  end
128
91
 
129
- # Default cache hit price when model family can't be determined
130
- # @return [Float] the default cache hit price
131
92
  def default_cache_hit_price
132
- 0.07 # Default to chat cache hit price
93
+ 0.07
133
94
  end
134
95
 
135
96
  def modalities_for(_model_id)
@@ -142,7 +103,6 @@ module RubyLLM
142
103
  def capabilities_for(model_id)
143
104
  capabilities = ['streaming']
144
105
 
145
- # Function calling for chat models
146
106
  capabilities << 'function_calling' if model_id.match?(/deepseek-chat/)
147
107
 
148
108
  capabilities
@@ -157,7 +117,6 @@ module RubyLLM
157
117
  output_per_million: prices[:output]
158
118
  }
159
119
 
160
- # Add cached pricing if available
161
120
  standard_pricing[:cached_input_per_million] = prices[:input_hit] if prices[:input_hit]
162
121
 
163
122
  {
@@ -2,7 +2,7 @@
2
2
 
3
3
  module RubyLLM
4
4
  module Providers
5
- module DeepSeek
5
+ class DeepSeek
6
6
  # Chat methods of the DeepSeek API integration
7
7
  module Chat
8
8
  module_function
@@ -3,32 +3,27 @@
3
3
  module RubyLLM
4
4
  module Providers
5
5
  # DeepSeek API integration.
6
- module DeepSeek
7
- extend OpenAI
8
- extend DeepSeek::Chat
6
+ class DeepSeek < OpenAI
7
+ include DeepSeek::Chat
9
8
 
10
- module_function
11
-
12
- def api_base(_config)
9
+ def api_base
13
10
  'https://api.deepseek.com'
14
11
  end
15
12
 
16
- def headers(config)
13
+ def headers
17
14
  {
18
- 'Authorization' => "Bearer #{config.deepseek_api_key}"
15
+ 'Authorization' => "Bearer #{@config.deepseek_api_key}"
19
16
  }
20
17
  end
21
18
 
22
- def capabilities
23
- DeepSeek::Capabilities
24
- end
25
-
26
- def slug
27
- 'deepseek'
28
- end
19
+ class << self
20
+ def capabilities
21
+ DeepSeek::Capabilities
22
+ end
29
23
 
30
- def configuration_requirements
31
- %i[deepseek_api_key]
24
+ def configuration_requirements
25
+ %i[deepseek_api_key]
26
+ end
32
27
  end
33
28
  end
34
29
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module RubyLLM
4
4
  module Providers
5
- module Gemini
5
+ class Gemini
6
6
  # Determines capabilities and pricing for Google Gemini models
7
7
  module Capabilities
8
8
  module_function
@@ -2,7 +2,7 @@
2
2
 
3
3
  module RubyLLM
4
4
  module Providers
5
- module Gemini
5
+ class Gemini
6
6
  # Chat methods for the Gemini API implementation
7
7
  module Chat
8
8
  module_function
@@ -2,7 +2,7 @@
2
2
 
3
3
  module RubyLLM
4
4
  module Providers
5
- module Gemini
5
+ class Gemini
6
6
  # Embeddings methods for the Gemini API integration
7
7
  module Embeddings
8
8
  module_function
@@ -2,7 +2,7 @@
2
2
 
3
3
  module RubyLLM
4
4
  module Providers
5
- module Gemini
5
+ class Gemini
6
6
  # Image generation methods for the Gemini API implementation
7
7
  module Images
8
8
  def images_url