Class: AgentHarness::Providers::Registry

Inherits:
Object
  • Object
show all
Includes:
Singleton
Defined in:
lib/agent_harness/providers/registry.rb

Overview

Registry for provider classes

Manages registration and lookup of provider classes. Supports dynamic registration of custom providers and aliasing of provider names.

Examples:

Registering a custom provider

AgentHarness::Providers::Registry.instance.register(:my_provider, MyProviderClass)

Looking up a provider

klass = AgentHarness::Providers::Registry.instance.get(:claude)

Constant Summary collapse

BUILTIN_PROVIDER_DEFINITIONS =
[
  {name: :claude, require_path: "agent_harness/providers/anthropic", class_name: :Anthropic, aliases: [:anthropic]},
  {name: :cursor, require_path: "agent_harness/providers/cursor", class_name: :Cursor, aliases: []},
  {name: :gemini, require_path: "agent_harness/providers/gemini", class_name: :Gemini, aliases: []},
  {
    name: :github_copilot,
    require_path: "agent_harness/providers/github_copilot",
    class_name: :GithubCopilot,
    aliases: [:copilot]
  },
  {name: :pi, require_path: "agent_harness/providers/pi", class_name: :Pi, aliases: []},
  {name: :codex, require_path: "agent_harness/providers/codex", class_name: :Codex, aliases: []},
  {name: :opencode, require_path: "agent_harness/providers/opencode", class_name: :Opencode, aliases: []},
  {name: :kilocode, require_path: "agent_harness/providers/kilocode", class_name: :Kilocode, aliases: []},
  {name: :aider, require_path: "agent_harness/providers/aider", class_name: :Aider, aliases: []},
  {name: :mistral_vibe, require_path: "agent_harness/providers/mistral_vibe", class_name: :MistralVibe, aliases: []}
].freeze

Instance Method Summary collapse

Constructor Details

#initializeRegistry

Returns a new instance of Registry.



38
39
40
41
42
43
44
45
46
47
# File 'lib/agent_harness/providers/registry.rb', line 38

def initialize
  @providers = {}
  @aliases = {}
  @provider_aliases = Hash.new { |hash, key| hash[key] = [] }
  @metadata_runtime_available = {}
  @provider_metadata_cache = {}
  @provider_metadata_catalog_cache = nil
  @builtin_registered = false
  @builtin_registration_in_progress = false
end

Instance Method Details

#allArray<Symbol>

List all registered provider names

Returns:

  • (Array<Symbol>)

    provider names



122
123
124
125
# File 'lib/agent_harness/providers/registry.rb', line 122

def all
  ensure_builtin_providers_registered
  @providers.keys
end

#availableArray<Symbol>

List available providers (CLI installed)

Returns:

  • (Array<Symbol>)

    available provider names



130
131
132
133
# File 'lib/agent_harness/providers/registry.rb', line 130

def available
  ensure_builtin_providers_registered
  @providers.select { |_, klass| klass.available? }.keys
end

#canonical_name(name) ⇒ Symbol

Resolve a provider lookup key to its canonical registered name.

Parameters:

  • name (Symbol, String)

    the provider name or alias

Returns:

  • (Symbol)

    canonical provider name



114
115
116
117
# File 'lib/agent_harness/providers/registry.rb', line 114

def canonical_name(name)
  ensure_builtin_providers_registered
  resolve_alias(name.to_sym)
end

#get(name) ⇒ Class

Get provider class by name

Parameters:

  • name (Symbol, String)

    the provider name

Returns:

  • (Class)

    the provider class

Raises:



94
95
96
97
98
# File 'lib/agent_harness/providers/registry.rb', line 94

def get(name)
  ensure_builtin_providers_registered
  name = resolve_alias(name.to_sym)
  @providers[name] || raise(ConfigurationError, "Unknown provider: #{name}")
end

#install_contract(name) ⇒ Hash

Fetch install contract metadata for a provider.

Parameters:

  • name (Symbol, String)

    the provider name

Returns:

  • (Hash)

    the provider install contract

Raises:



141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/agent_harness/providers/registry.rb', line 141

def install_contract(name)
  provider_class = get(name)

  unless provider_class.respond_to?(:install_contract)
    raise ConfigurationError, "Provider #{provider_class} does not implement .install_contract"
  end

  contract = provider_class.install_contract
  unless contract
    raise ConfigurationError, "Provider #{provider_class} does not expose an install contract"
  end

  contract
end

#installation_contract(name, **options) ⇒ Hash?

Fetch installation metadata for a provider.

Parameters:

  • name (Symbol, String)

    the provider name

  • options (Hash)

    optional target selection (for example, ‘version:`)

Returns:

  • (Hash, nil)

    provider installation contract, or nil when the registered provider class does not define ‘.installation_contract`

Raises:



163
164
165
166
167
168
# File 'lib/agent_harness/providers/registry.rb', line 163

def installation_contract(name, **options)
  provider_class = get(name)
  return nil unless provider_class.respond_to?(:installation_contract)

  provider_class.installation_contract(**options)
end

#installation_contractsHash<Symbol, Hash>

Get installation metadata for all providers that expose it.

Returns:

  • (Hash<Symbol, Hash>)

    installation contracts keyed by provider



173
174
175
176
177
178
179
180
181
182
# File 'lib/agent_harness/providers/registry.rb', line 173

def installation_contracts
  ensure_builtin_providers_registered

  @providers.each_with_object({}) do |(name, klass), contracts|
    next unless klass.respond_to?(:installation_contract)

    contract = klass.installation_contract
    contracts[name] = contract if contract
  end
end

#provider_metadata(name, refresh: false) ⇒ Hash

Fetch consolidated provider metadata for a provider.

Parameters:

  • name (Symbol, String)

    the provider name or alias

Returns:

  • (Hash)

    provider metadata

Raises:



215
216
217
218
219
220
221
222
223
224
225
# File 'lib/agent_harness/providers/registry.rb', line 215

def (name, refresh: false)
  ensure_builtin_providers_registered

  requested_name = name.to_sym
  canonical_name = resolve_alias(requested_name)
  cache_key = [requested_name, canonical_name]

  return (@provider_metadata_cache[cache_key]) if !refresh && @provider_metadata_cache.key?(cache_key)

  (requested_name, canonical_name, refresh: refresh)
end

#provider_metadata_catalog(refresh: false) ⇒ Hash<Symbol, Hash>

Get consolidated metadata for all registered providers.

Parameters:

  • refresh (Boolean) (defaults to: false)

    when true, refresh live runtime metadata such as CLI availability instead of reusing cached values

Returns:

  • (Hash<Symbol, Hash>)

    provider metadata keyed by canonical provider



232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
# File 'lib/agent_harness/providers/registry.rb', line 232

def (refresh: false)
  ensure_builtin_providers_registered

  return (@provider_metadata_catalog_cache) if !refresh && @provider_metadata_catalog_cache

  if refresh
    
    
  end

  catalog = @providers.keys.each_with_object({}) do |name, result|
    result[name] = (
      name,
      name,
      refresh: refresh,
      invalidate_provider_cache: false,
      invalidate_catalog: false
    )
  end

  @provider_metadata_catalog_cache = (catalog)
  (catalog)
end

#register(name, klass, aliases: []) ⇒ void

This method returns an undefined value.

Register a provider class

Parameters:

  • name (Symbol, String)

    the provider name

  • klass (Class)

    the provider class

  • aliases (Array<Symbol, String>) (defaults to: [])

    alternative names



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
86
87
# File 'lib/agent_harness/providers/registry.rb', line 55

def register(name, klass, aliases: [])
  name = name.to_sym
  validate_provider_class!(klass)
  normalized_aliases = aliases
    .filter_map do |alias_name|
      normalized_alias = alias_name.to_s.strip
      next if normalized_alias.empty?

      normalized_alias.to_sym
    end
    .uniq - [name]

  validate_provider_name!(name)
  validate_aliases!(name, normalized_aliases)
  unregister_aliases_for(name)

  @providers[name] = klass
  @provider_aliases[name] = normalized_aliases
  @metadata_runtime_available.delete(name)
  
  (klass)

  normalized_aliases.each do |alias_name|
    previous_owner = @aliases[alias_name]
    if previous_owner && previous_owner != name
      @provider_aliases[previous_owner] = @provider_aliases[previous_owner] - [alias_name]
    end

    @aliases[alias_name] = name
  end

  AgentHarness.logger&.debug("[AgentHarness::Registry] Registered provider: #{name}")
end

#registered?(name) ⇒ Boolean

Check if provider is registered

Parameters:

  • name (Symbol, String)

    the provider name

Returns:

  • (Boolean)

    true if registered



104
105
106
107
108
# File 'lib/agent_harness/providers/registry.rb', line 104

def registered?(name)
  ensure_builtin_providers_registered
  name = resolve_alias(name.to_sym)
  @providers.key?(name)
end

#reset!Object



256
257
258
259
260
261
262
263
264
265
# File 'lib/agent_harness/providers/registry.rb', line 256

def reset!
  @providers.each_value { |klass| (klass) }
  @providers.clear
  @aliases.clear
  @provider_aliases.clear
  @metadata_runtime_available.clear
  
  @builtin_registered = false
  @builtin_registration_in_progress = false
end

#smoke_test_contract(name) ⇒ Hash?

Get smoke-test metadata for a provider.

Parameters:

  • name (Symbol, String)

    the provider name

Returns:

  • (Hash, nil)

    smoke-test contract

Raises:



189
190
191
192
193
194
# File 'lib/agent_harness/providers/registry.rb', line 189

def smoke_test_contract(name)
  klass = get(name)
  return nil unless klass.respond_to?(:smoke_test_contract)

  klass.smoke_test_contract
end

#smoke_test_contractsHash<Symbol, Hash>

Get smoke-test metadata for all providers that expose it.

Returns:

  • (Hash<Symbol, Hash>)

    smoke-test contracts keyed by provider



199
200
201
202
203
204
205
206
207
208
# File 'lib/agent_harness/providers/registry.rb', line 199

def smoke_test_contracts
  ensure_builtin_providers_registered

  @providers.each_with_object({}) do |(name, klass), contracts|
    next unless klass.respond_to?(:smoke_test_contract)

    contract = klass.smoke_test_contract
    contracts[name] = contract if contract
  end
end