Class: AgentHarness::Orchestration::ProviderManager

Inherits:
Object
  • Object
show all
Defined in:
lib/agent_harness/orchestration/provider_manager.rb

Overview

Manages provider instances and selection

Handles provider lifecycle, health tracking, circuit breakers, and rate limiters. Provides intelligent provider selection based on availability and health.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config) ⇒ ProviderManager

Create a new provider manager

Parameters:



16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/agent_harness/orchestration/provider_manager.rb', line 16

def initialize(config)
  @config = config
  @registry = Providers::Registry.instance
  @provider_instances = {}
  @current_provider = config.default_provider

  @circuit_breakers = {}
  @rate_limiters = {}
  @health_monitor = HealthMonitor.new(config.orchestration_config.health_check_config)
  @fallback_chains = {}

  initialize_providers
end

Instance Attribute Details

#current_providerObject (readonly)

Returns the value of attribute current_provider.



11
12
13
# File 'lib/agent_harness/orchestration/provider_manager.rb', line 11

def current_provider
  @current_provider
end

#provider_instancesObject (readonly)

Returns the value of attribute provider_instances.



11
12
13
# File 'lib/agent_harness/orchestration/provider_manager.rb', line 11

def provider_instances
  @provider_instances
end

Instance Method Details

#available_providersArray<Symbol>

Get available providers

Returns:

  • (Array<Symbol>)

    available provider names



133
134
135
136
137
# File 'lib/agent_harness/orchestration/provider_manager.rb', line 133

def available_providers
  @provider_instances.keys.select do |name|
    !circuit_open?(name) && !rate_limited?(name) && healthy?(name)
  end
end

#circuit_open?(provider_name) ⇒ Boolean

Check if circuit is open for provider

Parameters:

  • provider_name (Symbol, String)

    the provider name

Returns:

  • (Boolean)

    true if open



168
169
170
# File 'lib/agent_harness/orchestration/provider_manager.rb', line 168

def circuit_open?(provider_name)
  @circuit_breakers[provider_name.to_sym]&.open? || false
end

#get_provider(name, executor: nil) ⇒ Providers::Base

Get or create provider instance

Parameters:

  • name (Symbol, String)

    the provider name

  • executor (CommandExecutor, nil) (defaults to: nil)

    per-request executor override

Returns:



62
63
64
65
66
67
# File 'lib/agent_harness/orchestration/provider_manager.rb', line 62

def get_provider(name, executor: nil)
  name = name.to_sym
  return create_provider(name, executor: executor) if executor

  @provider_instances[name] ||= create_provider(name)
end

#health_statusArray<Hash>

Get health status for all providers

Returns:

  • (Array<Hash>)

    health status for each provider



142
143
144
145
146
147
148
149
150
151
152
# File 'lib/agent_harness/orchestration/provider_manager.rb', line 142

def health_status
  @provider_instances.keys.map do |name|
    {
      provider: name,
      healthy: healthy?(name),
      circuit_open: circuit_open?(name),
      rate_limited: rate_limited?(name),
      metrics: @health_monitor.metrics_for(name)
    }
  end
end

#healthy?(provider_name) ⇒ Boolean

Check if provider is healthy

Parameters:

  • provider_name (Symbol, String)

    the provider name

Returns:

  • (Boolean)

    true if healthy



184
185
186
# File 'lib/agent_harness/orchestration/provider_manager.rb', line 184

def healthy?(provider_name)
  @health_monitor.healthy?(provider_name.to_sym)
end

#mark_rate_limited(provider_name, reset_at: nil) ⇒ void

This method returns an undefined value.

Mark provider as rate limited

Parameters:

  • provider_name (Symbol, String)

    the provider name

  • reset_at (Time, nil) (defaults to: nil)

    when the limit resets



125
126
127
128
# File 'lib/agent_harness/orchestration/provider_manager.rb', line 125

def mark_rate_limited(provider_name, reset_at: nil)
  provider_name = provider_name.to_sym
  @rate_limiters[provider_name]&.mark_limited(reset_at: reset_at)
end

#rate_limited?(provider_name) ⇒ Boolean

Check if provider is rate limited

Parameters:

  • provider_name (Symbol, String)

    the provider name

Returns:

  • (Boolean)

    true if limited



176
177
178
# File 'lib/agent_harness/orchestration/provider_manager.rb', line 176

def rate_limited?(provider_name)
  @rate_limiters[provider_name.to_sym]&.limited? || false
end

#record_failure(provider_name) ⇒ void

This method returns an undefined value.

Record failure for provider

Parameters:

  • provider_name (Symbol, String)

    the provider name



114
115
116
117
118
# File 'lib/agent_harness/orchestration/provider_manager.rb', line 114

def record_failure(provider_name)
  provider_name = provider_name.to_sym
  @health_monitor.record_failure(provider_name)
  @circuit_breakers[provider_name]&.record_failure
end

#record_success(provider_name) ⇒ void

This method returns an undefined value.

Record success for provider

Parameters:

  • provider_name (Symbol, String)

    the provider name



104
105
106
107
108
# File 'lib/agent_harness/orchestration/provider_manager.rb', line 104

def record_success(provider_name)
  provider_name = provider_name.to_sym
  @health_monitor.record_success(provider_name)
  @circuit_breakers[provider_name]&.record_success
end

#reset!void

This method returns an undefined value.

Reset all state



157
158
159
160
161
162
# File 'lib/agent_harness/orchestration/provider_manager.rb', line 157

def reset!
  @circuit_breakers.each_value(&:reset!)
  @rate_limiters.each_value(&:reset!)
  @health_monitor.reset!
  @current_provider = @config.default_provider
end

#select_provider(preferred = nil, executor: nil) ⇒ Providers::Base

Select best available provider

Parameters:

  • preferred (Symbol, nil) (defaults to: nil)

    preferred provider name

  • executor (CommandExecutor, nil) (defaults to: nil)

    per-request executor override

Returns:

Raises:



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/agent_harness/orchestration/provider_manager.rb', line 36

def select_provider(preferred = nil, executor: nil)
  preferred ||= @current_provider

  # Check circuit breaker
  if circuit_open?(preferred)
    return select_fallback(preferred, reason: :circuit_open, executor: executor)
  end

  # Check rate limit
  if rate_limited?(preferred)
    return select_fallback(preferred, reason: :rate_limited, executor: executor)
  end

  # Check health
  unless healthy?(preferred)
    return select_fallback(preferred, reason: :unhealthy, executor: executor)
  end

  get_provider(preferred, executor: executor)
end

#switch_provider(reason:, context: {}, executor: nil, from: @current_provider) ⇒ Providers::Base?

Switch to next available provider

Parameters:

  • from (Symbol, String) (defaults to: @current_provider)

    provider that failed and should be switched from

  • reason (Symbol, String)

    reason for switch

  • context (Hash) (defaults to: {})

    additional context

  • executor (CommandExecutor, nil) (defaults to: nil)

    per-request executor override

Returns:



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/agent_harness/orchestration/provider_manager.rb', line 76

def switch_provider(reason:, context: {}, executor: nil, from: @current_provider)
  old_provider = from.to_sym

  fallback = select_fallback(old_provider, reason: reason, executor: executor)
  return nil unless fallback

  return fallback if executor

  @current_provider = fallback.class.provider_name

  AgentHarness.logger&.info(
    "[AgentHarness] Provider switch: #{old_provider} -> #{@current_provider} (#{reason})"
  )

  @config.callbacks.emit(:provider_switch, {
    from: old_provider,
    to: @current_provider,
    reason: reason,
    context: context
  })

  fallback
end