Class: AgentHarness::Providers::Base

Inherits:
Object
  • Object
show all
Includes:
Adapter
Defined in:
lib/agent_harness/providers/base.rb

Overview

Base class for all providers

Provides common functionality for provider implementations including command execution, error handling, and response parsing.

Examples:

Implementing a provider

class MyProvider < AgentHarness::Providers::Base
  class << self
    def provider_name
      :my_provider
    end

    def binary_name
      "my-cli"
    end

    def available?
      system("which my-cli > /dev/null 2>&1")
    end
  end

  protected

  def build_command(prompt, options)
    [self.class.binary_name, "--prompt", prompt]
  end
end

Constant Summary collapse

COMMON_ERROR_PATTERNS =

Common error patterns shared across providers that use standard HTTP-style error responses. Providers with unique patterns (e.g. Anthropic, GitHub Copilot) override error_patterns entirely.

{
  rate_limited: [
    /rate.?limit/i,
    /too.?many.?requests/i,
    /429/
  ],
  auth_expired: [
    /invalid.*api.*key/i,
    /unauthorized/i,
    /authentication/i
  ],
  quota_exceeded: [
    /quota.*exceeded/i,
    /insufficient.*quota/i,
    /billing/i
  ],
  transient: [
    /timeout/i,
    /connection.*error/i,
    /service.*unavailable/i,
    /503/,
    /502/
  ]
}.tap { |patterns| patterns.each_value(&:freeze) }.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Adapter

#auth_type, #build_mcp_flags, #capabilities, #dangerous_mode_flags, #error_patterns, #execution_semantics, #fetch_mcp_servers, #health_status, included, #parse_rate_limit_reset, #session_flags, #supported_mcp_transports, #supports_dangerous_mode?, #supports_mcp?, #supports_sessions?, #validate_config, #validate_mcp_servers!

Constructor Details

#initialize(config: nil, executor: nil, logger: nil) ⇒ Base

Initialize the provider

Parameters:

  • config (ProviderConfig, nil) (defaults to: nil)

    provider configuration

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

    command executor

  • logger (Logger, nil) (defaults to: nil)

    logger instance



71
72
73
74
75
# File 'lib/agent_harness/providers/base.rb', line 71

def initialize(config: nil, executor: nil, logger: nil)
  @config = config || ProviderConfig.new(self.class.provider_name)
  @executor = executor || AgentHarness.configuration.command_executor
  @logger = logger || AgentHarness.logger
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



63
64
65
# File 'lib/agent_harness/providers/base.rb', line 63

def config
  @config
end

#executorObject

Returns the value of attribute executor.



64
65
66
# File 'lib/agent_harness/providers/base.rb', line 64

def executor
  @executor
end

#loggerObject (readonly)

Returns the value of attribute logger.



63
64
65
# File 'lib/agent_harness/providers/base.rb', line 63

def logger
  @logger
end

Instance Method Details

#configure(options = {}) ⇒ self

Configure the provider instance

Parameters:

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

    configuration options

Returns:

  • (self)


81
82
83
84
# File 'lib/agent_harness/providers/base.rb', line 81

def configure(options = {})
  @config.merge!(options)
  self
end

#display_nameString

Human-friendly display name

Returns:

  • (String)

    display name



134
135
136
# File 'lib/agent_harness/providers/base.rb', line 134

def display_name
  name.capitalize
end

#nameString

Provider name for display

Returns:

  • (String)

    display name



127
128
129
# File 'lib/agent_harness/providers/base.rb', line 127

def name
  self.class.provider_name.to_s
end

#sandboxed_environment?Boolean

Whether the provider is running inside a sandboxed (Docker) environment

Providers can use this to adjust execution flags, e.g. skipping nested sandboxing when already inside a container.

Returns:

  • (Boolean)

    true when the executor is a DockerCommandExecutor



144
145
146
# File 'lib/agent_harness/providers/base.rb', line 144

def sandboxed_environment?
  @executor.is_a?(DockerCommandExecutor)
end

#send_message(prompt:, **options) ⇒ Response

Main send_message implementation

Parameters:

  • prompt (String)

    the prompt to send

  • options (Hash)

    additional options

Returns:



91
92
93
94
95
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
# File 'lib/agent_harness/providers/base.rb', line 91

def send_message(prompt:, **options)
  log_debug("send_message_start", prompt_length: prompt.length, options: options.keys)

  # Normalize and validate MCP servers
  options = normalize_mcp_servers(options)
  validate_mcp_servers!(options[:mcp_servers]) if options[:mcp_servers]&.any?

  # Build command
  command = build_command(prompt, options)

  # Calculate timeout
  timeout = options[:timeout] || @config.timeout || default_timeout

  # Execute command
  start_time = Time.now
  result = execute_with_timeout(command, timeout: timeout, env: build_env(options))
  duration = Time.now - start_time

  # Parse response
  response = parse_response(result, duration: duration)

  # Track tokens
  track_tokens(response) if response.tokens

  log_debug("send_message_complete", duration: duration, tokens: response.tokens)

  response
rescue McpConfigurationError, McpUnsupportedError, McpTransportUnsupportedError
  raise
rescue => e
  handle_error(e, prompt: prompt, options: options)
end