Skip to content

Commit 18978b5

Browse files
committed
Implement largest tag as alias
1 parent 50ee106 commit 18978b5

File tree

3 files changed

+38
-12
lines changed

3 files changed

+38
-12
lines changed

lib/ruby_llm/aliases.rb

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,11 @@ class << self
1919
# @param provider_slug [String, Symbol, nil] optional provider to resolve for
2020
# @return [String] the resolved model ID or the original if no alias exists
2121
def resolve(model_id, provider = nil)
22-
return model_id unless aliases[model_id]
23-
2422
if provider
25-
aliases[model_id][provider.to_s] || model_id
23+
@runtime_aliases.dig(provider.to_s, model_id) || aliases.dig(model_id, provider.to_s) || model_id
2624
else
2725
# Get native provider's version
28-
aliases[model_id].values.first || model_id
26+
aliases[model_id]&.values&.first || model_id
2927
end
3028
end
3129

@@ -35,6 +33,14 @@ def aliases
3533
@aliases ||= load_aliases
3634
end
3735

36+
# Adds extra runtime-only aliases for a specific provider
37+
# @return [Hash] the updated aliases mapping
38+
def register_runtime_aliases(provider, extra_aliases)
39+
# NOTE: not persisted; will be gone after app restart
40+
@runtime_aliases ||= {}
41+
@runtime_aliases[provider.to_s] = extra_aliases
42+
end
43+
3844
# Loads aliases from the JSON file
3945
# @return [Hash] the loaded aliases
4046
def load_aliases

lib/ruby_llm/providers/ollama/models.rb

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,6 @@ def models_url
1010
'api/tags'
1111
end
1212

13-
# FIXME: include aliases for tags with the format \d+m or \d+b
14-
# ie. given these models in the server,
15-
# - gemma3:27b
16-
# - gemma3:9b
17-
#
18-
# create an alias gemma3 for gemma3:27b
19-
2013
# NOTE: Unlike other providers for well known APIs with stable model
2114
# offerings, the Ollama provider deals with local servers which
2215
# might have arbitrarily named models or even zero models installed.
@@ -38,7 +31,28 @@ def list_models
3831
private
3932

4033
def parse_list_models_response(response, slug, capabilities) # rubocop:disable Metrics/MethodLength
41-
(response.body['models'] || []).map do |model|
34+
provider_aliases = {}
35+
list = response.body['models'] || []
36+
37+
# initial pass: discover Ollama "tags"
38+
list.each do |model|
39+
base, tag = model['name'].split(':', 2)
40+
model['model_name_base'] = base if tag
41+
end
42+
43+
# second pass: set aliases for models with multiple sizes
44+
list.group_by { |m| m['model_name_base'] }.each do |base, models|
45+
# given these models in the server,
46+
# - gemma3:27b
47+
# - gemma3:9b
48+
# then gemma3:27b will get the 'gemma3' alias since the 27b is larger in bytesize
49+
largest = models.max_by { |m| m['size'].to_i }
50+
provider_aliases[base] = largest['name']
51+
end
52+
RubyLLM::Aliases.register_runtime_aliases(slug, provider_aliases)
53+
54+
# final pass: assemble
55+
list.map do |model|
4256
model_id = model['name']
4357

4458
ModelInfo.new(
@@ -57,6 +71,7 @@ def parse_list_models_response(response, slug, capabilities) # rubocop:disable M
5771
input_price_per_million: capabilities.input_price_for(model_id),
5872
output_price_per_million: capabilities.output_price_for(model_id),
5973
metadata: {
74+
model_name_base: model['model_name_base'],
6075
byte_size: model['size']&.to_i,
6176
parameter_size: model.dig('details', 'parameter_size'),
6277
quantization_level: model.dig('details', 'quantization_level'),

spec/ruby_llm/providers/ollama/ollama_spec.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@
3131
an_object_having_attributes(provider: 'ollama', id: 'snowflake-arctic-embed:22m')
3232
)
3333
end
34+
35+
it 'aliases models to the largest available tag' do
36+
chat = RubyLLM.chat(model: 'smollm', provider: 'ollama')
37+
expect(chat.model.id).to eq('smollm:135m')
38+
end
3439
end
3540

3641
describe '.chat' do

0 commit comments

Comments
 (0)