Module: OllamaAgent::Providers::ModelRegistry

Defined in:
lib/ollama_agent/providers/model_registry.rb

Constant Summary collapse

KNOWN_MODELS =
[
  # OpenAI
  ModelDescriptor.new(name: "gpt-4o", provider: "openai", context_size: 128_000,
                      capabilities: %i[chat tools vision], status: "available"),
  ModelDescriptor.new(name: "gpt-4o-mini", provider: "openai", context_size: 128_000,
                      capabilities: %i[chat tools vision], status: "available"),
  ModelDescriptor.new(name: "o1-mini", provider: "openai", context_size: 128_000,
                      capabilities: %i[chat tools reasoning], status: "available"),

  # Anthropic
  ModelDescriptor.new(name: "claude-3-5-sonnet-latest", provider: "anthropic", context_size: 200_000,
                      capabilities: %i[chat tools vision], status: "available"),
  ModelDescriptor.new(name: "claude-3-5-haiku-latest", provider: "anthropic", context_size: 200_000,
                      capabilities: %i[chat tools], status: "available"),

  # Groq
  ModelDescriptor.new(name: "llama-3.3-70b-versatile", provider: "groq", context_size: 128_000,
                      capabilities: %i[chat tools], status: "available"),
  ModelDescriptor.new(name: "mixtral-8x7b-32768", provider: "groq", context_size: 32_768,
                      capabilities: %i[chat tools], status: "available"),

  # OpenRouter
  ModelDescriptor.new(name: "deepseek-r1", provider: "openrouter", context_size: 163_840,
                      capabilities: %i[chat reasoning], status: "available")
].freeze
TOOL_CAPABLE_PATTERNS =
%w[
  qwen llama mistral mixtral kimi deepseek command-r firefunction hermes
  glm minimax nemotron gpt-oss devstral gemma4 gemini
].freeze
VISION_CAPABLE_PATTERNS =
%w[
  llava vision moondream gemma4 qwen3.5 qwen3-vl kimi-k2.5 kimi-k2.6 gemini-3
].freeze
THINKING_CAPABLE_PATTERNS =
%w[
  thinking glm minimax nemotron gemma4 gemini deepseek-v qwen3 kimi gpt-oss devstral
].freeze

Class Method Summary collapse

Class Method Details

.all(agent: nil) ⇒ Array<ModelDescriptor>

List all known and dynamic models.

Parameters:

  • agent (Agent, nil) (defaults to: nil)

Returns:



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/ollama_agent/providers/model_registry.rb', line 39

def all(agent: nil)
  list = KNOWN_MODELS.dup

  if agent
    # Resolve local host from agent or environment
    host = ENV.fetch("OLLAMA_HOST", "http://localhost:11434")
    local_models = fetch_local_models(host)
    if local_models.empty?
      begin
        agent.list_local_model_names.each do |name|
          list << ModelDescriptor.new(
            name: name,
            provider: "local",
            context_size: name.include?("qwen2.5-coder") ? 128_000 : 32_768,
            capabilities: infer_capabilities(name),
            status: "loaded"
          )
        end
      rescue StandardError
      end
    else
      list.concat(local_models)
    end

    # Fetch cloud models
    begin
      cloud_names = agent.list_cloud_model_names
      cloud_names.each do |name|
        # Avoid duplicating if already present
        next if list.any? { |m| m.name == name }

        list << ModelDescriptor.new(
          name: name,
          provider: "ollama_cloud",
          context_size: 128_000,
          capabilities: infer_capabilities(name),
          status: "available",
          subscription_required: subscription_required?(name)
        )
      end
    rescue StandardError
      # Silently ignore cloud fetch errors
    end
  end

  list.uniq(&:name)
end

.available_providersObject

Returns the set of provider names for which an API key is configured in ENV. “local” is always included (Ollama runs locally by default).



180
181
182
183
184
185
186
187
188
189
# File 'lib/ollama_agent/providers/model_registry.rb', line 180

def available_providers
  present = ->(key) { ENV.fetch(key, nil).to_s.strip.then { |v| v unless v.empty? } }
  providers = Set.new(["local"])
  providers << "ollama_cloud" if present.call("OLLAMA_API_KEY")
  providers << "openai"       if present.call("OPENAI_API_KEY")
  providers << "anthropic"    if present.call("ANTHROPIC_API_KEY")
  providers << "groq"         if present.call("GROQ_API_KEY") || present.call("GROQ_KEY")
  providers << "openrouter"   if present.call("OPENROUTER_API_KEY")
  providers
end

.fetch_local_models(host) ⇒ Object

Fetch local models directly from Ollama tags & ps API.



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/ollama_agent/providers/model_registry.rb', line 96

def fetch_local_models(host)
  require "net/http"
  require "json"

  # Normalize host URL
  base_url = host.to_s.strip
  base_url = "http://#{base_url}" unless base_url.start_with?("http://", "https://")
  base_url = base_url.chomp("/")

  # 1. Fetch tags
  uri = URI("#{base_url}/api/tags")
  req = Net::HTTP::Get.new(uri)
  res = Net::HTTP.start(uri.host, uri.port, open_timeout: 2, read_timeout: 3) { |h| h.request(req) }
  return [] unless res.is_a?(Net::HTTPSuccess)

  parsed = JSON.parse(res.body)
  models = parsed["models"] || []

  # 2. Fetch loaded models (ps)
  ps_uri = URI("#{base_url}/api/ps")
  ps_req = Net::HTTP::Get.new(ps_uri)
  ps_res = Net::HTTP.start(ps_uri.host, ps_uri.port, open_timeout: 2, read_timeout: 3) { |h| h.request(ps_req) }
  loaded_names = []
  if ps_res.is_a?(Net::HTTPSuccess)
    ps_parsed = JSON.parse(ps_res.body)
    loaded_names = (ps_parsed["models"] || []).map { |m| m["name"] }
  end

  models.map do |m|
    m_name = m["name"]
    details = m["details"] || {}
    size_bytes = m["size"] || 0
    size_gb = (size_bytes.to_f / 1_073_741_824).round(2)

    status = loaded_names.include?(m_name) ? "loaded" : "unloaded"

    ModelDescriptor.new(
      name: m_name,
      provider: "local",
      context_size: m_name.include?("qwen2.5-coder") ? 128_000 : 32_768,
      capabilities: infer_capabilities(m_name, details),
      size_gb: size_gb,
      status: status
    )
  end
rescue StandardError
  []
end

.find(name, agent: nil) ⇒ ModelDescriptor?

Find a model descriptor by name.

Parameters:

  • name (String)
  • agent (Agent, nil) (defaults to: nil)

Returns:



91
92
93
# File 'lib/ollama_agent/providers/model_registry.rb', line 91

def find(name, agent: nil)
  all(agent: agent).find { |m| m.name.to_s.casecmp(name.to_s).zero? }
end