Class: Ace::LLM::Molecules::ClientRegistry

Inherits:
Object
  • Object
show all
Defined in:
lib/ace/llm/molecules/client_registry.rb

Overview

ClientRegistry manages provider configurations and instantiation Loads provider definitions from YAML files and creates client instances dynamically

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeClientRegistry

Initialize the client registry



18
19
20
21
22
23
24
25
# File 'lib/ace/llm/molecules/client_registry.rb', line 18

def initialize
  @providers = {}
  @loaded_gems = {}
  @global_aliases = {}
  @model_aliases = {}
  load_all_configurations
  build_alias_maps
end

Instance Attribute Details

#global_aliasesObject (readonly)

Returns the value of attribute global_aliases.



15
16
17
# File 'lib/ace/llm/molecules/client_registry.rb', line 15

def global_aliases
  @global_aliases
end

#model_aliasesObject (readonly)

Returns the value of attribute model_aliases.



15
16
17
# File 'lib/ace/llm/molecules/client_registry.rb', line 15

def model_aliases
  @model_aliases
end

#providersObject (readonly)

Returns the value of attribute providers.



15
16
17
# File 'lib/ace/llm/molecules/client_registry.rb', line 15

def providers
  @providers
end

Instance Method Details

#available_aliasesHash

Get all available aliases

Returns:

  • (Hash)

    Hash with global and model aliases by provider



210
211
212
213
214
215
# File 'lib/ace/llm/molecules/client_registry.rb', line 210

def available_aliases
  {
    global: @global_aliases.dup,
    model: @model_aliases.dup
  }
end

#available_providersArray<String>

Get list of available provider names

Returns:

  • (Array<String>)

    Provider names



75
76
77
# File 'lib/ace/llm/molecules/client_registry.rb', line 75

def available_providers
  @providers.keys.sort
end

#get_client(provider_name, model: nil, **options) ⇒ BaseClient

Get a client instance for a provider and model

Parameters:

  • provider_name (String)

    Provider name

  • model (String, nil) (defaults to: nil)

    Model to use (uses default if nil)

  • options (Hash)

    Additional options for client initialization

Returns:

  • (BaseClient)

    Client instance

Raises:



33
34
35
36
37
38
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
# File 'lib/ace/llm/molecules/client_registry.rb', line 33

def get_client(provider_name, model: nil, **options)
  provider_config = get_provider(provider_name)

  unless provider_config
    raise ProviderError, "Unknown provider: #{provider_name}. Available providers: #{available_providers.join(", ")}"
  end

  # Load the provider's gem if needed
  load_provider_gem(provider_config)

  # Get the class and instantiate
  client_class = resolve_class(provider_config["class"])

  # Merge options with defaults from config
  merged_options = (provider_config["default_options"] || {}).merge(options)

  # Use specified model or default from config
  model ||= provider_config["models"]&.first || "default"

  # Add API key configuration if specified
  if provider_config["api_key"]
    merged_options[:api_key] = resolve_api_key(provider_config["api_key"])
  end

  # Pass backend configurations (base_url, env_key, model_tiers) to client
  if provider_config["backends"]
    merged_options[:backends] = provider_config["backends"]
  end

  client_class.new(model: model, **merged_options)
end

#get_provider(provider_name) ⇒ Hash?

Get provider configuration

Parameters:

  • provider_name (String)

    Provider name

Returns:

  • (Hash, nil)

    Provider configuration or nil if not found



68
69
70
71
# File 'lib/ace/llm/molecules/client_registry.rb', line 68

def get_provider(provider_name)
  normalized_name = normalize_provider_name(provider_name)
  @providers[normalized_name]
end

#list_providers_with_statusHash

List all providers with their status

Returns:

  • (Hash)

    Provider status information



113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/ace/llm/molecules/client_registry.rb', line 113

def list_providers_with_status
  @providers.map do |name, config|
    credential = credential_status(config, name)
    {
      name: name,
      models: config["models"] || [],
      gem: config["gem"],
      available: provider_available?(name),
      api_key_required: credential[:required],
      api_key_present: credential[:present],
      credential_env_keys: credential[:env_keys]
    }
  end
end

#models_for_provider(provider_name) ⇒ Array<String>?

Get list of models for a provider

Parameters:

  • provider_name (String)

    Provider name

Returns:

  • (Array<String>, nil)

    List of models or nil if provider not found



82
83
84
85
# File 'lib/ace/llm/molecules/client_registry.rb', line 82

def models_for_provider(provider_name)
  provider = get_provider(provider_name)
  provider&.fetch("models", [])
end

#provider_api_key_present?(provider_name) ⇒ Boolean

Whether provider has a present API key according to its api_key config.

Parameters:

  • provider_name (String)

Returns:

  • (Boolean)


141
142
143
144
145
146
147
# File 'lib/ace/llm/molecules/client_registry.rb', line 141

def provider_api_key_present?(provider_name)
  provider = get_provider(provider_name)
  return false unless provider

  normalized_name = normalize_provider_name(provider["name"] || provider_name)
  credential_status(provider, normalized_name)[:present]
end

#provider_api_key_required?(provider_name) ⇒ Boolean

Whether provider config marks API key as required.

Parameters:

  • provider_name (String)

Returns:

  • (Boolean)


131
132
133
134
135
136
# File 'lib/ace/llm/molecules/client_registry.rb', line 131

def provider_api_key_required?(provider_name)
  provider = get_provider(provider_name)
  return false unless provider

  provider.dig("api_key", "required") || false
end

#provider_available?(provider_name) ⇒ Boolean

Check if a provider’s gem is available

Parameters:

  • provider_name (String)

    Provider name

Returns:

  • (Boolean)

    True if provider gem can be loaded



98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/ace/llm/molecules/client_registry.rb', line 98

def provider_available?(provider_name)
  provider_config = get_provider(provider_name)
  return false unless provider_config

  # Try to load the gem
  begin
    load_provider_gem(provider_config)
    true
  rescue LoadError, NameError
    false
  end
end

#provider_exists?(provider_name) ⇒ Boolean

Check if a provider is available

Parameters:

  • provider_name (String)

    Provider name

Returns:

  • (Boolean)

    True if provider is registered



90
91
92
93
# File 'lib/ace/llm/molecules/client_registry.rb', line 90

def provider_exists?(provider_name)
  normalized_name = normalize_provider_name(provider_name)
  @providers.key?(normalized_name)
end

#reload!Object

Reload all configurations



150
151
152
153
154
155
156
157
# File 'lib/ace/llm/molecules/client_registry.rb', line 150

def reload!
  @providers.clear
  @loaded_gems.clear
  @global_aliases.clear
  @model_aliases.clear
  load_all_configurations
  build_alias_maps
end

#resolve_alias(input) ⇒ String

Resolve an alias to provider:model format

Parameters:

  • input (String)

    The alias or model to resolve

Returns:

  • (String)

    The resolved provider:model or original input



162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/ace/llm/molecules/client_registry.rb', line 162

def resolve_alias(input)
  input = input.to_s.strip

  # Check if it's already in provider:model format
  if input.include?(":")
    provider_name, model_alias = input.split(":", 2)
    normalized_provider = normalize_provider_name(provider_name)

    # Try to resolve model alias for this provider
    if @model_aliases[normalized_provider] && @model_aliases[normalized_provider][model_alias]
      return "#{provider_name}:#{@model_aliases[normalized_provider][model_alias]}"
    end

    # Auto-resolve: provider:provider → provider:default_model
    normalized_alias = normalize_provider_name(model_alias)
    if normalized_alias == normalized_provider
      default_model = @providers[normalized_provider]&.dig("models")&.first
      return "#{provider_name}:#{default_model}" if default_model
    end

    # Return as-is if no model alias found
    return input
  end

  # Check global aliases
  if @global_aliases[input]
    resolved = @global_aliases[input]

    # If global alias points to provider:model_alias, resolve the model alias too
    if resolved.include?(":")
      provider_name, model_part = resolved.split(":", 2)
      normalized_provider = normalize_provider_name(provider_name)

      # Check if model_part is itself an alias
      if @model_aliases[normalized_provider] && @model_aliases[normalized_provider][model_part]
        return "#{provider_name}:#{@model_aliases[normalized_provider][model_part]}"
      end
    end

    return resolved
  end

  # Return original if no alias found
  input
end