Skip to content

Commit 94f4e4e

Browse files
committed
Allow local models to fetch model list
This prevents assume local model warning from happening while keeping local model registry. Both GPUStack and Ollama can now fetch model lists, so in theory running RubyLLM.models.refresh! is all that's needed to verify's model availability.
1 parent 0deebcc commit 94f4e4e

File tree

3 files changed

+62
-15
lines changed

3 files changed

+62
-15
lines changed

lib/ruby_llm/models.rb

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def refresh!
3737
end
3838

3939
def fetch_from_providers
40-
configured = Provider.configured_providers(RubyLLM.config).filter(&:remote?)
40+
configured = Provider.configured_providers(RubyLLM.config)
4141

4242
RubyLLM.logger.info "Fetching models from providers: #{configured.map(&:slug).join(', ')}"
4343

@@ -47,23 +47,24 @@ def fetch_from_providers
4747
end
4848

4949
def resolve(model_id, provider: nil, assume_exists: false) # rubocop:disable Metrics/PerceivedComplexity
50-
assume_exists = true if provider && Provider.providers[provider.to_sym].local?
51-
52-
if assume_exists
50+
if assume_exists || local_provider?(provider)
51+
model = find_local_model(model_id, provider) if local_provider?(provider)
5352
raise ArgumentError, 'Provider must be specified if assume_exists is true' unless provider
5453

5554
provider = Provider.providers[provider.to_sym] || raise(Error, "Unknown provider: #{provider.to_sym}")
56-
model = Model::Info.new(
57-
id: model_id,
58-
name: model_id.gsub('-', ' ').capitalize,
59-
provider: provider.slug,
60-
capabilities: %w[function_calling streaming],
61-
modalities: { input: %w[text image], output: %w[text] },
62-
metadata: { warning: 'Assuming model exists, capabilities may not be accurate' }
63-
)
64-
if RubyLLM.config.log_assume_model_exists
65-
RubyLLM.logger.warn "Assuming model '#{model_id}' exists for provider '#{provider}'. " \
66-
'Capabilities may not be accurately reflected.'
55+
unless model
56+
model = Model::Info.new(
57+
id: model_id,
58+
name: model_id.gsub('-', ' ').capitalize,
59+
provider: provider.slug,
60+
capabilities: %w[function_calling streaming],
61+
modalities: { input: %w[text image], output: %w[text] },
62+
metadata: { warning: 'Assuming model exists, capabilities may not be accurate' }
63+
)
64+
if RubyLLM.config.log_assume_model_exists
65+
RubyLLM.logger.warn "Assuming model '#{model_id}' exists for provider '#{provider}'. " \
66+
'Capabilities may not be accurately reflected.'
67+
end
6768
end
6869
else
6970
model = Models.find model_id, provider
@@ -223,5 +224,15 @@ def find_without_provider(model_id)
223224
all.find { |m| m.id == Aliases.resolve(model_id) } ||
224225
raise(ModelNotFoundError, "Unknown model: #{model_id}")
225226
end
227+
228+
def self.local_provider?(provider)
229+
provider && Provider.providers[provider.to_sym]&.local?
230+
end
231+
232+
def self.find_local_model(model_id, provider)
233+
Models.find(model_id, provider)
234+
rescue ModelNotFoundError
235+
nil
236+
end
226237
end
227238
end

lib/ruby_llm/providers/ollama.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ module Ollama
77
extend OpenAI
88
extend Ollama::Chat
99
extend Ollama::Media
10+
extend Ollama::Models
1011

1112
module_function
1213

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# frozen_string_literal: true
2+
3+
module RubyLLM
4+
module Providers
5+
module Ollama
6+
# Models methods of the Ollama API integration
7+
module Models
8+
module_function
9+
10+
def models_url
11+
'models'
12+
end
13+
14+
def parse_list_models_response(response, slug, _capabilities)
15+
Array(response.body['data']).map do |model_data|
16+
Model::Info.new(
17+
id: model_data['id'],
18+
name: model_data['id'],
19+
provider: slug,
20+
family: 'ollama',
21+
created_at: model_data['created'] ? Time.at(model_data['created']) : nil,
22+
modalities: {
23+
input: %w[text image], # Ollama models don't advertise input modalities, so we assume text and image
24+
output: ['text'] # Ollama models don't expose output modalities, so we assume text
25+
},
26+
capabilities: %w[streaming function_calling structured_output],
27+
pricing: {}, # Ollama does not provide pricing details
28+
metadata: {}
29+
)
30+
end
31+
end
32+
end
33+
end
34+
end
35+
end

0 commit comments

Comments
 (0)