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.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/ruby_llm/active_record/acts_as.rb +46 -6
- data/lib/ruby_llm/aliases.json +27 -3
- data/lib/ruby_llm/chat.rb +27 -6
- data/lib/ruby_llm/configuration.rb +7 -18
- data/lib/ruby_llm/connection.rb +11 -6
- data/lib/ruby_llm/context.rb +2 -3
- data/lib/ruby_llm/embedding.rb +3 -4
- data/lib/ruby_llm/error.rb +2 -2
- data/lib/ruby_llm/image.rb +3 -4
- data/lib/ruby_llm/message.rb +4 -0
- data/lib/ruby_llm/models.json +7306 -6676
- data/lib/ruby_llm/models.rb +22 -31
- data/lib/ruby_llm/provider.rb +150 -89
- data/lib/ruby_llm/providers/anthropic/capabilities.rb +1 -2
- data/lib/ruby_llm/providers/anthropic/chat.rb +1 -1
- data/lib/ruby_llm/providers/anthropic/embeddings.rb +1 -1
- data/lib/ruby_llm/providers/anthropic/media.rb +1 -1
- data/lib/ruby_llm/providers/anthropic/models.rb +1 -1
- data/lib/ruby_llm/providers/anthropic/streaming.rb +1 -1
- data/lib/ruby_llm/providers/anthropic/tools.rb +1 -1
- data/lib/ruby_llm/providers/anthropic.rb +17 -22
- data/lib/ruby_llm/providers/bedrock/capabilities.rb +3 -63
- data/lib/ruby_llm/providers/bedrock/chat.rb +5 -4
- data/lib/ruby_llm/providers/bedrock/media.rb +1 -1
- data/lib/ruby_llm/providers/bedrock/models.rb +5 -6
- data/lib/ruby_llm/providers/bedrock/signing.rb +1 -1
- data/lib/ruby_llm/providers/bedrock/streaming/base.rb +5 -4
- data/lib/ruby_llm/providers/bedrock/streaming/content_extraction.rb +1 -1
- data/lib/ruby_llm/providers/bedrock/streaming/message_processing.rb +1 -1
- data/lib/ruby_llm/providers/bedrock/streaming/payload_processing.rb +1 -1
- data/lib/ruby_llm/providers/bedrock/streaming/prelude_handling.rb +1 -1
- data/lib/ruby_llm/providers/bedrock/streaming.rb +1 -1
- data/lib/ruby_llm/providers/bedrock.rb +26 -31
- data/lib/ruby_llm/providers/deepseek/capabilities.rb +16 -57
- data/lib/ruby_llm/providers/deepseek/chat.rb +1 -1
- data/lib/ruby_llm/providers/deepseek.rb +12 -17
- data/lib/ruby_llm/providers/gemini/capabilities.rb +1 -1
- data/lib/ruby_llm/providers/gemini/chat.rb +1 -1
- data/lib/ruby_llm/providers/gemini/embeddings.rb +1 -1
- data/lib/ruby_llm/providers/gemini/images.rb +1 -1
- data/lib/ruby_llm/providers/gemini/media.rb +1 -1
- data/lib/ruby_llm/providers/gemini/models.rb +1 -1
- data/lib/ruby_llm/providers/gemini/streaming.rb +1 -1
- data/lib/ruby_llm/providers/gemini/tools.rb +1 -7
- data/lib/ruby_llm/providers/gemini.rb +18 -23
- data/lib/ruby_llm/providers/gpustack/chat.rb +1 -1
- data/lib/ruby_llm/providers/gpustack/models.rb +1 -1
- data/lib/ruby_llm/providers/gpustack.rb +16 -19
- data/lib/ruby_llm/providers/mistral/capabilities.rb +1 -1
- data/lib/ruby_llm/providers/mistral/chat.rb +1 -1
- data/lib/ruby_llm/providers/mistral/embeddings.rb +1 -1
- data/lib/ruby_llm/providers/mistral/models.rb +1 -1
- data/lib/ruby_llm/providers/mistral.rb +14 -19
- data/lib/ruby_llm/providers/ollama/chat.rb +1 -1
- data/lib/ruby_llm/providers/ollama/media.rb +1 -1
- data/lib/ruby_llm/providers/ollama.rb +13 -18
- data/lib/ruby_llm/providers/openai/capabilities.rb +2 -2
- data/lib/ruby_llm/providers/openai/chat.rb +2 -2
- data/lib/ruby_llm/providers/openai/embeddings.rb +1 -1
- data/lib/ruby_llm/providers/openai/images.rb +1 -1
- data/lib/ruby_llm/providers/openai/media.rb +1 -1
- data/lib/ruby_llm/providers/openai/models.rb +1 -1
- data/lib/ruby_llm/providers/openai/streaming.rb +1 -1
- data/lib/ruby_llm/providers/openai/tools.rb +1 -1
- data/lib/ruby_llm/providers/openai.rb +24 -36
- data/lib/ruby_llm/providers/openrouter/models.rb +1 -1
- data/lib/ruby_llm/providers/openrouter.rb +9 -14
- data/lib/ruby_llm/providers/perplexity/capabilities.rb +1 -30
- data/lib/ruby_llm/providers/perplexity/chat.rb +1 -1
- data/lib/ruby_llm/providers/perplexity/models.rb +1 -1
- data/lib/ruby_llm/providers/perplexity.rb +13 -18
- data/lib/ruby_llm/stream_accumulator.rb +3 -3
- data/lib/ruby_llm/streaming.rb +16 -3
- data/lib/ruby_llm/tool.rb +19 -0
- data/lib/ruby_llm/version.rb +1 -1
- data/lib/tasks/models_docs.rake +18 -11
- data/lib/tasks/models_update.rake +5 -4
- metadata +1 -1
data/lib/ruby_llm/models.rb
CHANGED
@@ -37,26 +37,35 @@ module RubyLLM
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def fetch_from_providers
|
40
|
-
|
40
|
+
config = RubyLLM.config
|
41
|
+
configured_classes = Provider.configured_remote_providers(config)
|
42
|
+
configured = configured_classes.map { |klass| klass.new(config) }
|
41
43
|
|
42
|
-
RubyLLM.logger.info "Fetching models from providers: #{configured.map(&:
|
44
|
+
RubyLLM.logger.info "Fetching models from providers: #{configured.map(&:name).join(', ')}"
|
43
45
|
|
44
|
-
configured.flat_map
|
45
|
-
provider.list_models(connection: provider.connection(RubyLLM.config))
|
46
|
-
end
|
46
|
+
configured.flat_map(&:list_models)
|
47
47
|
end
|
48
48
|
|
49
|
-
def resolve(model_id, provider: nil, assume_exists: false) # rubocop:disable Metrics/PerceivedComplexity
|
50
|
-
|
49
|
+
def resolve(model_id, provider: nil, assume_exists: false, config: nil) # rubocop:disable Metrics/PerceivedComplexity
|
50
|
+
config ||= RubyLLM.config
|
51
|
+
provider_class = provider ? Provider.providers[provider.to_sym] : nil
|
52
|
+
|
53
|
+
# Check if provider is local
|
54
|
+
if provider_class
|
55
|
+
temp_instance = provider_class.new(config)
|
56
|
+
assume_exists = true if temp_instance.local?
|
57
|
+
end
|
51
58
|
|
52
59
|
if assume_exists
|
53
60
|
raise ArgumentError, 'Provider must be specified if assume_exists is true' unless provider
|
54
61
|
|
55
|
-
|
62
|
+
provider_class ||= raise(Error, "Unknown provider: #{provider.to_sym}")
|
63
|
+
provider_instance = provider_class.new(config)
|
64
|
+
|
56
65
|
model = Model::Info.new(
|
57
66
|
id: model_id,
|
58
67
|
name: model_id.gsub('-', ' ').capitalize,
|
59
|
-
provider:
|
68
|
+
provider: provider_instance.slug,
|
60
69
|
capabilities: %w[function_calling streaming],
|
61
70
|
modalities: { input: %w[text image], output: %w[text] },
|
62
71
|
metadata: { warning: 'Assuming model exists, capabilities may not be accurate' }
|
@@ -67,9 +76,11 @@ module RubyLLM
|
|
67
76
|
end
|
68
77
|
else
|
69
78
|
model = Models.find model_id, provider
|
70
|
-
|
79
|
+
provider_class = Provider.providers[model.provider.to_sym] || raise(Error,
|
80
|
+
"Unknown provider: #{model.provider}")
|
81
|
+
provider_instance = provider_class.new(config)
|
71
82
|
end
|
72
|
-
[model,
|
83
|
+
[model, provider_instance]
|
73
84
|
end
|
74
85
|
|
75
86
|
def method_missing(method, ...)
|
@@ -97,26 +108,19 @@ module RubyLLM
|
|
97
108
|
end
|
98
109
|
|
99
110
|
def merge_models(provider_models, parsera_models)
|
100
|
-
# Create lookups for both sets of models
|
101
111
|
parsera_by_key = index_by_key(parsera_models)
|
102
112
|
provider_by_key = index_by_key(provider_models)
|
103
113
|
|
104
|
-
# All keys from both sources
|
105
114
|
all_keys = parsera_by_key.keys | provider_by_key.keys
|
106
115
|
|
107
|
-
# Merge data, with parsera taking precedence
|
108
116
|
models = all_keys.map do |key|
|
109
117
|
if (parsera_model = parsera_by_key[key])
|
110
|
-
# Parsera has this model - use it as the base
|
111
118
|
if (provider_model = provider_by_key[key])
|
112
|
-
# Both sources have this model, add provider metadata
|
113
119
|
add_provider_metadata(parsera_model, provider_model)
|
114
120
|
else
|
115
|
-
# Only parsera has this model
|
116
121
|
parsera_model
|
117
122
|
end
|
118
123
|
else
|
119
|
-
# Only provider has this model
|
120
124
|
provider_by_key[key]
|
121
125
|
end
|
122
126
|
end
|
@@ -131,19 +135,16 @@ module RubyLLM
|
|
131
135
|
end
|
132
136
|
|
133
137
|
def add_provider_metadata(parsera_model, provider_model)
|
134
|
-
# Create a new Model::Info with parsera data but include provider metadata
|
135
138
|
data = parsera_model.to_h
|
136
139
|
data[:metadata] = provider_model.metadata.merge(data[:metadata] || {})
|
137
140
|
Model::Info.new(data)
|
138
141
|
end
|
139
142
|
end
|
140
143
|
|
141
|
-
# Initialize with optional pre-filtered models
|
142
144
|
def initialize(models = nil)
|
143
145
|
@models = models || load_models
|
144
146
|
end
|
145
147
|
|
146
|
-
# Load models from the JSON file
|
147
148
|
def load_models
|
148
149
|
data = File.exist?(self.class.models_file) ? File.read(self.class.models_file) : '[]'
|
149
150
|
JSON.parse(data, symbolize_names: true).map { |model| Model::Info.new(model) }
|
@@ -155,17 +156,14 @@ module RubyLLM
|
|
155
156
|
File.write(self.class.models_file, JSON.pretty_generate(all.map(&:to_h)))
|
156
157
|
end
|
157
158
|
|
158
|
-
# Return all models in the collection
|
159
159
|
def all
|
160
160
|
@models
|
161
161
|
end
|
162
162
|
|
163
|
-
# Allow enumeration over all models
|
164
163
|
def each(&)
|
165
164
|
all.each(&)
|
166
165
|
end
|
167
166
|
|
168
|
-
# Find a specific model by ID
|
169
167
|
def find(model_id, provider = nil)
|
170
168
|
if provider
|
171
169
|
find_with_provider(model_id, provider)
|
@@ -174,37 +172,30 @@ module RubyLLM
|
|
174
172
|
end
|
175
173
|
end
|
176
174
|
|
177
|
-
# Filter to only chat models
|
178
175
|
def chat_models
|
179
176
|
self.class.new(all.select { |m| m.type == 'chat' })
|
180
177
|
end
|
181
178
|
|
182
|
-
# Filter to only embedding models
|
183
179
|
def embedding_models
|
184
180
|
self.class.new(all.select { |m| m.type == 'embedding' })
|
185
181
|
end
|
186
182
|
|
187
|
-
# Filter to only audio models
|
188
183
|
def audio_models
|
189
184
|
self.class.new(all.select { |m| m.type == 'audio' })
|
190
185
|
end
|
191
186
|
|
192
|
-
# Filter to only image models
|
193
187
|
def image_models
|
194
188
|
self.class.new(all.select { |m| m.type == 'image' })
|
195
189
|
end
|
196
190
|
|
197
|
-
# Filter models by family
|
198
191
|
def by_family(family)
|
199
192
|
self.class.new(all.select { |m| m.family == family.to_s })
|
200
193
|
end
|
201
194
|
|
202
|
-
# Filter models by provider
|
203
195
|
def by_provider(provider)
|
204
196
|
self.class.new(all.select { |m| m.provider == provider.to_s })
|
205
197
|
end
|
206
198
|
|
207
|
-
# Instance method to refresh models
|
208
199
|
def refresh!
|
209
200
|
self.class.refresh!
|
210
201
|
end
|
data/lib/ruby_llm/provider.rb
CHANGED
@@ -1,96 +1,94 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module RubyLLM
|
4
|
-
# Base
|
4
|
+
# Base class for LLM providers like OpenAI and Anthropic.
|
5
5
|
# Handles the complexities of API communication, streaming responses,
|
6
6
|
# and error handling so individual providers can focus on their unique features.
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
module Methods
|
11
|
-
extend Streaming
|
12
|
-
|
13
|
-
def complete(messages, tools:, temperature:, model:, connection:, params: {}, schema: nil, &) # rubocop:disable Metrics/ParameterLists
|
14
|
-
normalized_temperature = maybe_normalize_temperature(temperature, model)
|
15
|
-
|
16
|
-
payload = Utils.deep_merge(
|
17
|
-
params,
|
18
|
-
render_payload(
|
19
|
-
messages,
|
20
|
-
tools: tools,
|
21
|
-
temperature: normalized_temperature,
|
22
|
-
model: model,
|
23
|
-
stream: block_given?,
|
24
|
-
schema: schema
|
25
|
-
)
|
26
|
-
)
|
7
|
+
# Encapsulates configuration and connection to eliminate parameter threading.
|
8
|
+
class Provider
|
9
|
+
include Streaming
|
27
10
|
|
28
|
-
|
29
|
-
stream_response connection, payload, &
|
30
|
-
else
|
31
|
-
sync_response connection, payload
|
32
|
-
end
|
33
|
-
end
|
11
|
+
attr_reader :config, :connection
|
34
12
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
13
|
+
def initialize(config)
|
14
|
+
@config = config
|
15
|
+
ensure_configured!
|
16
|
+
@connection = Connection.new(self, @config)
|
17
|
+
end
|
39
18
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
parse_embedding_response(response, model:, text:)
|
44
|
-
end
|
19
|
+
def api_base
|
20
|
+
raise NotImplementedError
|
21
|
+
end
|
45
22
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
parse_image_response(response, model:)
|
50
|
-
end
|
23
|
+
def headers
|
24
|
+
{}
|
25
|
+
end
|
51
26
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
end
|
27
|
+
def slug
|
28
|
+
self.class.slug
|
29
|
+
end
|
56
30
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
value.nil? || value.empty?
|
61
|
-
end
|
62
|
-
end
|
31
|
+
def name
|
32
|
+
self.class.name
|
33
|
+
end
|
63
34
|
|
64
|
-
|
65
|
-
|
66
|
-
|
35
|
+
def capabilities
|
36
|
+
self.class.capabilities
|
37
|
+
end
|
67
38
|
|
68
|
-
|
69
|
-
|
70
|
-
|
39
|
+
def configuration_requirements
|
40
|
+
self.class.configuration_requirements
|
41
|
+
end
|
71
42
|
|
72
|
-
|
43
|
+
def complete(messages, tools:, temperature:, model:, params: {}, headers: {}, schema: nil, &) # rubocop:disable Metrics/ParameterLists
|
44
|
+
normalized_temperature = maybe_normalize_temperature(temperature, model)
|
45
|
+
|
46
|
+
payload = Utils.deep_merge(
|
47
|
+
params,
|
48
|
+
render_payload(
|
49
|
+
messages,
|
50
|
+
tools: tools,
|
51
|
+
temperature: normalized_temperature,
|
52
|
+
model: model,
|
53
|
+
stream: block_given?,
|
54
|
+
schema: schema
|
55
|
+
)
|
56
|
+
)
|
73
57
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
temperature
|
79
|
-
end
|
58
|
+
if block_given?
|
59
|
+
stream_response @connection, payload, headers, &
|
60
|
+
else
|
61
|
+
sync_response @connection, payload, headers
|
80
62
|
end
|
63
|
+
end
|
81
64
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
end
|
65
|
+
def list_models
|
66
|
+
response = @connection.get models_url
|
67
|
+
parse_list_models_response response, slug, capabilities
|
86
68
|
end
|
87
69
|
|
88
|
-
def
|
89
|
-
|
70
|
+
def embed(text, model:, dimensions:)
|
71
|
+
payload = render_embedding_payload(text, model:, dimensions:)
|
72
|
+
response = @connection.post(embedding_url(model:), payload)
|
73
|
+
parse_embedding_response(response, model:, text:)
|
74
|
+
end
|
90
75
|
|
91
|
-
|
92
|
-
|
93
|
-
|
76
|
+
def paint(prompt, model:, size:)
|
77
|
+
payload = render_image_payload(prompt, model:, size:)
|
78
|
+
response = @connection.post images_url, payload
|
79
|
+
parse_image_response(response, model:)
|
80
|
+
end
|
81
|
+
|
82
|
+
def configured?
|
83
|
+
configuration_requirements.all? { |req| @config.send(req) }
|
84
|
+
end
|
85
|
+
|
86
|
+
def local?
|
87
|
+
self.class.local?
|
88
|
+
end
|
89
|
+
|
90
|
+
def remote?
|
91
|
+
self.class.remote?
|
94
92
|
end
|
95
93
|
|
96
94
|
def parse_error(response)
|
@@ -109,28 +107,54 @@ module RubyLLM
|
|
109
107
|
end
|
110
108
|
end
|
111
109
|
|
112
|
-
def
|
113
|
-
|
114
|
-
|
115
|
-
|
110
|
+
def format_messages(messages)
|
111
|
+
messages.map do |msg|
|
112
|
+
{
|
113
|
+
role: msg.role.to_s,
|
114
|
+
content: msg.content
|
115
|
+
}
|
116
116
|
end
|
117
|
+
end
|
117
118
|
|
118
|
-
|
119
|
+
def format_tool_calls(_tool_calls)
|
119
120
|
nil
|
120
121
|
end
|
121
122
|
|
122
|
-
def
|
123
|
-
|
123
|
+
def parse_tool_calls(_tool_calls)
|
124
|
+
nil
|
124
125
|
end
|
125
126
|
|
126
127
|
class << self
|
127
|
-
def
|
128
|
-
|
129
|
-
|
128
|
+
def name
|
129
|
+
to_s.split('::').last
|
130
|
+
end
|
131
|
+
|
132
|
+
def slug
|
133
|
+
name.downcase
|
134
|
+
end
|
135
|
+
|
136
|
+
def capabilities
|
137
|
+
raise NotImplementedError
|
138
|
+
end
|
139
|
+
|
140
|
+
def configuration_requirements
|
141
|
+
[]
|
142
|
+
end
|
143
|
+
|
144
|
+
def local?
|
145
|
+
false
|
130
146
|
end
|
131
147
|
|
132
|
-
def
|
133
|
-
|
148
|
+
def remote?
|
149
|
+
!local?
|
150
|
+
end
|
151
|
+
|
152
|
+
def configured?(config)
|
153
|
+
configuration_requirements.all? { |req| config.send(req) }
|
154
|
+
end
|
155
|
+
|
156
|
+
def register(name, provider_class)
|
157
|
+
providers[name.to_sym] = provider_class
|
134
158
|
end
|
135
159
|
|
136
160
|
def for(model)
|
@@ -143,16 +167,53 @@ module RubyLLM
|
|
143
167
|
end
|
144
168
|
|
145
169
|
def local_providers
|
146
|
-
providers.select { |_slug,
|
170
|
+
providers.select { |_slug, provider_class| provider_class.local? }
|
147
171
|
end
|
148
172
|
|
149
173
|
def remote_providers
|
150
|
-
providers.select { |_slug,
|
174
|
+
providers.select { |_slug, provider_class| provider_class.remote? }
|
175
|
+
end
|
176
|
+
|
177
|
+
def configured_providers(config)
|
178
|
+
providers.select do |_slug, provider_class|
|
179
|
+
provider_class.configured?(config)
|
180
|
+
end.values
|
181
|
+
end
|
182
|
+
|
183
|
+
def configured_remote_providers(config)
|
184
|
+
providers.select do |_slug, provider_class|
|
185
|
+
provider_class.remote? && provider_class.configured?(config)
|
186
|
+
end.values
|
151
187
|
end
|
188
|
+
end
|
189
|
+
|
190
|
+
private
|
191
|
+
|
192
|
+
def try_parse_json(maybe_json)
|
193
|
+
return maybe_json unless maybe_json.is_a?(String)
|
194
|
+
|
195
|
+
JSON.parse(maybe_json)
|
196
|
+
rescue JSON::ParserError
|
197
|
+
maybe_json
|
198
|
+
end
|
199
|
+
|
200
|
+
def ensure_configured!
|
201
|
+
missing = configuration_requirements.reject { |req| @config.send(req) }
|
202
|
+
return if missing.empty?
|
203
|
+
|
204
|
+
raise ConfigurationError, "Missing configuration for #{name}: #{missing.join(', ')}"
|
205
|
+
end
|
206
|
+
|
207
|
+
def maybe_normalize_temperature(temperature, _model_id)
|
208
|
+
temperature
|
209
|
+
end
|
152
210
|
|
153
|
-
|
154
|
-
|
211
|
+
def sync_response(connection, payload, additional_headers = {})
|
212
|
+
response = connection.post completion_url, payload do |req|
|
213
|
+
# Merge additional headers, with existing headers taking precedence
|
214
|
+
req.headers = additional_headers.merge(req.headers) unless additional_headers.empty?
|
155
215
|
end
|
216
|
+
parse_completion_response response
|
156
217
|
end
|
157
218
|
end
|
158
219
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module RubyLLM
|
4
4
|
module Providers
|
5
|
-
|
5
|
+
class Anthropic
|
6
6
|
# Determines capabilities and pricing for Anthropic models
|
7
7
|
module Capabilities
|
8
8
|
module_function
|
@@ -133,7 +133,6 @@ module RubyLLM
|
|
133
133
|
# Function calling for Claude 3+
|
134
134
|
if model_id.match?(/claude-3/)
|
135
135
|
capabilities << 'function_calling'
|
136
|
-
capabilities << 'structured_output'
|
137
136
|
capabilities << 'batch'
|
138
137
|
end
|
139
138
|
|
@@ -4,38 +4,33 @@ module RubyLLM
|
|
4
4
|
module Providers
|
5
5
|
# Anthropic Claude API integration. Handles the complexities of
|
6
6
|
# Claude's unique message format and tool calling conventions.
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
extend Anthropic::Tools
|
7
|
+
class Anthropic < Provider
|
8
|
+
include Anthropic::Chat
|
9
|
+
include Anthropic::Embeddings
|
10
|
+
include Anthropic::Media
|
11
|
+
include Anthropic::Models
|
12
|
+
include Anthropic::Streaming
|
13
|
+
include Anthropic::Tools
|
15
14
|
|
16
|
-
|
17
|
-
|
18
|
-
def api_base(_config)
|
15
|
+
def api_base
|
19
16
|
'https://api.anthropic.com'
|
20
17
|
end
|
21
18
|
|
22
|
-
def headers
|
19
|
+
def headers
|
23
20
|
{
|
24
|
-
'x-api-key' => config.anthropic_api_key,
|
21
|
+
'x-api-key' => @config.anthropic_api_key,
|
25
22
|
'anthropic-version' => '2023-06-01'
|
26
23
|
}
|
27
24
|
end
|
28
25
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
def slug
|
34
|
-
'anthropic'
|
35
|
-
end
|
26
|
+
class << self
|
27
|
+
def capabilities
|
28
|
+
Anthropic::Capabilities
|
29
|
+
end
|
36
30
|
|
37
|
-
|
38
|
-
|
31
|
+
def configuration_requirements
|
32
|
+
%i[anthropic_api_key]
|
33
|
+
end
|
39
34
|
end
|
40
35
|
end
|
41
36
|
end
|