Module: AgentHarness
- Defined in:
- lib/agent_harness.rb,
lib/agent_harness/skill.rb,
lib/agent_harness/errors.rb,
lib/agent_harness/skills.rb,
lib/agent_harness/version.rb,
lib/agent_harness/response.rb,
lib/agent_harness/embeddings.rb,
lib/agent_harness/extensions.rb,
lib/agent_harness/mcp_server.rb,
lib/agent_harness/conversation.rb,
lib/agent_harness/providers/pi.rb,
lib/agent_harness/quota_status.rb,
lib/agent_harness/configuration.rb,
lib/agent_harness/providers/omp.rb,
lib/agent_harness/token_tracker.rb,
lib/agent_harness/authentication.rb,
lib/agent_harness/error_taxonomy.rb,
lib/agent_harness/providers/base.rb,
lib/agent_harness/text_transport.rb,
lib/agent_harness/providers/aider.rb,
lib/agent_harness/providers/codex.rb,
lib/agent_harness/command_executor.rb,
lib/agent_harness/embedding_result.rb,
lib/agent_harness/provider_runtime.rb,
lib/agent_harness/providers/cursor.rb,
lib/agent_harness/providers/gemini.rb,
lib/agent_harness/release_registry.rb,
lib/agent_harness/sub_agent_config.rb,
lib/agent_harness/embedding_adapter.rb,
lib/agent_harness/mcp_config_loader.rb,
lib/agent_harness/providers/adapter.rb,
lib/agent_harness/api/attempt_report.rb,
lib/agent_harness/api/chat_transport.rb,
lib/agent_harness/dependency_updater.rb,
lib/agent_harness/providers/kilocode.rb,
lib/agent_harness/providers/opencode.rb,
lib/agent_harness/providers/registry.rb,
lib/agent_harness/api/schema_response.rb,
lib/agent_harness/model_compatibility.rb,
lib/agent_harness/providers/anthropic.rb,
lib/agent_harness/token_usage_tracker.rb,
lib/agent_harness/sub_agent_translator.rb,
lib/agent_harness/execution_preparation.rb,
lib/agent_harness/mcp_config_translator.rb,
lib/agent_harness/orchestration/metrics.rb,
lib/agent_harness/provider_health_check.rb,
lib/agent_harness/sub_agent_file_loader.rb,
lib/agent_harness/providers/mistral_vibe.rb,
lib/agent_harness/docker_command_executor.rb,
lib/agent_harness/orchestration/conductor.rb,
lib/agent_harness/providers/github_copilot.rb,
lib/agent_harness/api/ruby_llm_chat_adapter.rb,
lib/agent_harness/orchestration/rate_limiter.rb,
lib/agent_harness/openai_compatible_transport.rb,
lib/agent_harness/orchestration/health_monitor.rb,
lib/agent_harness/orchestration/circuit_breaker.rb,
lib/agent_harness/providers/token_usage_parsing.rb,
lib/agent_harness/orchestration/provider_manager.rb,
lib/agent_harness/providers/codex_model_discovery.rb,
lib/agent_harness/providers/mcp_config_file_support.rb,
lib/agent_harness/providers/rate_limit_reset_parsing.rb,
lib/agent_harness/providers/quota_checkers/open_router.rb
Overview
AgentHarness provides a unified interface for CLI-based AI coding agents.
It offers:
- Unified interface for multiple AI coding agents (Claude Code, Cursor, Gemini CLI, etc.)
- Full orchestration layer with provider switching, circuit breakers, and health monitoring
- Flexible configuration via YAML, Ruby DSL, or environment variables
- Dynamic provider registration for custom provider support
- Token usage tracking for cost and limit calculations
Defined Under Namespace
Modules: Api, Authentication, EmbeddingAdapter, ErrorTaxonomy, Extensions, McpConfigTranslator, ModelCompatibility, Orchestration, Providers, Skills, SubAgentTranslator Classes: AuthMismatchError, AuthenticationError, AuthorizationError, CallbackRegistry, CancelledError, CircuitBreakerConfig, CircuitOpenError, CommandExecutionError, CommandExecutor, Configuration, ConfigurationError, Conversation, DependencyUpdater, DockerCommandExecutor, EmbeddingResult, Embeddings, Error, ExecutionPreparation, ExtensionCompatibilityError, HealthCheckConfig, IdleTimeoutError, InvalidDurationError, MalformedEmbeddingError, McpConfigLoader, McpConfigurationError, McpServer, McpTransportUnsupportedError, McpUnsupportedError, NoProvidersAvailableError, OpenAICompatibleTransport, OrchestrationConfig, ProviderConfig, ProviderError, ProviderHealthCheck, ProviderInstallationError, ProviderNotFoundError, ProviderRuntime, ProviderUnavailableError, QuotaStatus, RateLimitConfig, RateLimitError, ReleaseRegistry, Response, RetryConfig, Skill, SubAgentConfig, SubAgentFileLoader, TextTransport, TimeoutError, TokenTracker, TokenUsageTracker, ToolDefinition, ToolRegistry, UnsupportedAuthFlowError
Constant Summary collapse
- VERSION =
"0.44.0"
Class Method Summary collapse
-
.auth_capabilities(provider_name) ⇒ Hash
Get authentication flow capabilities for a provider.
-
.auth_status(provider_name) ⇒ Hash
Get detailed authentication status for a provider.
-
.auth_url(provider_name) ⇒ String
Generate an OAuth URL for a provider.
-
.auth_url_supported?(provider_name) ⇒ Boolean
Check whether OAuth URL generation is supported for a provider.
-
.auth_valid?(provider_name) ⇒ Boolean
Check if authentication is valid for a provider.
-
.build_config(name, **options) ⇒ ProviderConfig
Build a new ProviderConfig with defaults for the given provider.
-
.check_provider(provider_name, timeout: nil, executor: nil, provider_runtime: nil) ⇒ Hash
Check health of a single provider.
-
.check_providers(timeout: nil, executor: nil, provider_runtime: nil) ⇒ Array<Hash>
Check health of all configured providers.
-
.conductor ⇒ Orchestration::Conductor
Returns the global conductor for orchestrated requests.
-
.configuration ⇒ Configuration
Returns the global configuration instance.
-
.configure {|Configuration| ... } ⇒ void
Configure AgentHarness with a block.
-
.dependency_updater ⇒ DependencyUpdater
Returns the global dependency updater for managing agent tool versions.
-
.discover_extensions(directory) ⇒ Array<Extensions::Base>
Discover and register all extensions found in a directory.
-
.embed(inputs:, model:, credentials:, dimensions: nil, **options) ⇒ EmbeddingResult
Generate embeddings for a batch of strings through a request-local RubyLLM context.
-
.exchange_code(provider_name, code:, code_verifier:) ⇒ Hash
Exchange an OAuth authorization code for tokens using PKCE.
-
.exchange_code_supported?(provider_name) ⇒ Boolean
Check whether PKCE code exchange is supported for a provider.
-
.exchange_refresh_token(provider_name) ⇒ Hash
Exchange a stored refresh token for a fresh access token.
-
.exchange_refresh_token_supported?(provider_name) ⇒ Boolean
Check whether refresh-token exchange is supported for a provider.
-
.extension(reference) ⇒ Extensions::Base
Resolve a canonical extension definition by name or inline object.
-
.extension_compatibility(provider:, extensions:) ⇒ Array<Extensions::CompatibilityReport>
Build a compatibility report for extensions against a provider.
-
.install_contract(name) ⇒ Hash
Get install contract metadata for a provider.
-
.installation_contract(provider_name, **options) ⇒ Hash?
Get installation metadata for a provider CLI.
-
.installation_contracts ⇒ Hash<Symbol, Hash>
Get all provider installation contracts exposed by agent-harness.
-
.load_extensions(path, adapter: nil) ⇒ Array<Extensions::Base>
Load one or more extensions from disk through an adapter.
-
.logger ⇒ Logger?
Returns the global logger.
-
.model_compatibility(runner:, model_id:, auth_mode: nil, cli_version: nil) ⇒ AgentHarness::ModelCompatibility::Result
Query runner/model compatibility contract.
-
.provider(name) ⇒ Providers::Base
Get a provider instance.
-
.provider_class(name) ⇒ Class
Look up the provider class for a given name or alias.
-
.provider_install_contract(provider_name, version: nil) ⇒ Hash?
Returns install metadata for a provider CLI when the provider exposes it.
-
.provider_installation_contract(name, **options) ⇒ Hash?
Get the installation contract for a provider CLI.
-
.provider_metadata(provider_name, refresh: false) ⇒ Hash
Get consolidated metadata for a provider.
-
.provider_metadata_catalog(refresh: false) ⇒ Hash<Symbol, Hash>
Get consolidated metadata for all registered providers.
-
.provider_smoke_test_contract(provider_name) ⇒ Hash?
Get smoke-test metadata for a provider CLI when the provider exposes it.
-
.providers ⇒ Array<Symbol>
List all registered provider names.
-
.refresh_auth(provider_name, token: nil) ⇒ Hash
Refresh authentication credentials for a provider.
-
.refresh_auth_supported?(provider_name) ⇒ Boolean
Check whether credential refresh is supported for a provider.
-
.reset! ⇒ void
Reset configuration to defaults (useful for testing).
-
.resolve_latest_version(provider_name, bypass_cooldown: false) ⇒ Hash?
Resolve the latest eligible version for an installable provider tool, applying the configured cooldown period.
-
.send_message(prompt, provider: nil, executor: nil, **options) ⇒ Response
Send a message using the orchestration layer.
-
.smoke_test_contract(provider_name) ⇒ Hash?
Get smoke-test metadata for a provider CLI.
-
.smoke_test_contracts ⇒ Hash<Symbol, Hash>
Get all provider smoke-test contracts exposed by agent-harness.
-
.sub_agent(reference) ⇒ SubAgentConfig
Resolve a canonical sub-agent definition by name or inline payload.
-
.token_tracker ⇒ TokenTracker
Returns the global token tracker.
-
.token_usage_tracker ⇒ TokenUsageTracker
Returns the global token usage tracker used as a fallback when providers do not expose a proactive quota API.
-
.translate_sub_agent(reference, provider:) ⇒ Hash
Translate a canonical sub-agent definition into a provider-specific format.
Class Method Details
.auth_capabilities(provider_name) ⇒ Hash
Get authentication flow capabilities for a provider
319 320 321 |
# File 'lib/agent_harness.rb', line 319 def auth_capabilities(provider_name) Authentication.auth_capabilities(provider_name) end |
.auth_status(provider_name) ⇒ Hash
Get detailed authentication status for a provider
311 312 313 |
# File 'lib/agent_harness.rb', line 311 def auth_status(provider_name) Authentication.auth_status(provider_name) end |
.auth_url(provider_name) ⇒ String
Generate an OAuth URL for a provider
335 336 337 |
# File 'lib/agent_harness.rb', line 335 def auth_url(provider_name) Authentication.auth_url(provider_name) end |
.auth_url_supported?(provider_name) ⇒ Boolean
Check whether OAuth URL generation is supported for a provider
327 328 329 |
# File 'lib/agent_harness.rb', line 327 def auth_url_supported?(provider_name) Authentication.auth_url_supported?(provider_name) end |
.auth_valid?(provider_name) ⇒ Boolean
Check if authentication is valid for a provider
304 305 306 |
# File 'lib/agent_harness.rb', line 304 def auth_valid?(provider_name) Authentication.auth_valid?(provider_name) end |
.build_config(name, **options) ⇒ ProviderConfig
Build a new ProviderConfig with defaults for the given provider
182 183 184 185 186 |
# File 'lib/agent_harness.rb', line 182 def build_config(name, **) config = ProviderConfig.new(name) config.merge!() unless .empty? config end |
.check_provider(provider_name, timeout: nil, executor: nil, provider_runtime: nil) ⇒ Hash
Check health of a single provider
414 415 416 417 418 419 420 |
# File 'lib/agent_harness.rb', line 414 def check_provider(provider_name, timeout: nil, executor: nil, provider_runtime: nil) = {} [:timeout] = timeout unless timeout.nil? [:executor] = executor unless executor.nil? [:provider_runtime] = provider_runtime unless provider_runtime.nil? ProviderHealthCheck.check(provider_name, **) end |
.check_providers(timeout: nil, executor: nil, provider_runtime: nil) ⇒ Array<Hash>
Check health of all configured providers.
Validates each enabled provider through registration, CLI availability, authentication, provider health status, and config validation checks.
401 402 403 404 405 406 407 408 |
# File 'lib/agent_harness.rb', line 401 def check_providers(timeout: nil, executor: nil, provider_runtime: nil) raise ArgumentError, "provider_runtime is only supported for single-provider health checks" unless provider_runtime.nil? = {} [:timeout] = timeout unless timeout.nil? [:executor] = executor unless executor.nil? ProviderHealthCheck.check_all(**) end |
.conductor ⇒ Orchestration::Conductor
Returns the global conductor for orchestrated requests
76 77 78 |
# File 'lib/agent_harness.rb', line 76 def conductor @conductor ||= Orchestration::Conductor.new(config: configuration) end |
.configuration ⇒ Configuration
Returns the global configuration instance
33 34 35 |
# File 'lib/agent_harness.rb', line 33 def configuration @configuration ||= Configuration.new end |
.configure {|Configuration| ... } ⇒ void
This method returns an undefined value.
Configure AgentHarness with a block
40 41 42 |
# File 'lib/agent_harness.rb', line 40 def configure yield(configuration) if block_given? end |
.dependency_updater ⇒ DependencyUpdater
Returns the global dependency updater for managing agent tool versions.
The dependency updater applies a configurable cooldown period before adopting new upstream releases, reducing exposure to regressions.
428 429 430 |
# File 'lib/agent_harness.rb', line 428 def dependency_updater @dependency_updater ||= DependencyUpdater.new end |
.discover_extensions(directory) ⇒ Array<Extensions::Base>
Discover and register all extensions found in a directory.
117 118 119 |
# File 'lib/agent_harness.rb', line 117 def discover_extensions(directory) configuration.discover_extensions(directory) end |
.embed(inputs:, model:, credentials:, dimensions: nil, **options) ⇒ EmbeddingResult
Generate embeddings for a batch of strings through a request-local RubyLLM context.
92 93 94 |
# File 'lib/agent_harness.rb', line 92 def (inputs:, model:, credentials:, dimensions: nil, **) Embeddings.new(model: model, credentials: credentials, **).call(inputs: inputs, dimensions: dimensions) end |
.exchange_code(provider_name, code:, code_verifier:) ⇒ Hash
Exchange an OAuth authorization code for tokens using PKCE
353 354 355 |
# File 'lib/agent_harness.rb', line 353 def exchange_code(provider_name, code:, code_verifier:) Authentication.exchange_code(provider_name, code: code, code_verifier: code_verifier) end |
.exchange_code_supported?(provider_name) ⇒ Boolean
Check whether PKCE code exchange is supported for a provider
343 344 345 |
# File 'lib/agent_harness.rb', line 343 def exchange_code_supported?(provider_name) Authentication.exchange_code_supported?(provider_name) end |
.exchange_refresh_token(provider_name) ⇒ Hash
Exchange a stored refresh token for a fresh access token
387 388 389 |
# File 'lib/agent_harness.rb', line 387 def exchange_refresh_token(provider_name) Authentication.exchange_refresh_token(provider_name) end |
.exchange_refresh_token_supported?(provider_name) ⇒ Boolean
Check whether refresh-token exchange is supported for a provider
378 379 380 |
# File 'lib/agent_harness.rb', line 378 def exchange_refresh_token_supported?(provider_name) Authentication.exchange_refresh_token_supported?(provider_name) end |
.extension(reference) ⇒ Extensions::Base
Resolve a canonical extension definition by name or inline object.
100 101 102 |
# File 'lib/agent_harness.rb', line 100 def extension(reference) configuration.resolve_extension(reference) end |
.extension_compatibility(provider:, extensions:) ⇒ Array<Extensions::CompatibilityReport>
Build a compatibility report for extensions against a provider.
126 127 128 129 130 131 132 133 134 135 |
# File 'lib/agent_harness.rb', line 126 def extension_compatibility(provider:, extensions:) provider_instance = provider.is_a?(Providers::Base) ? provider : self.provider(provider) Array(extensions).map do |extension_ref| Extensions::Compatibility.report( provider: provider_instance, extension: extension(extension_ref) ) end end |
.install_contract(name) ⇒ Hash
Get install contract metadata for a provider
192 193 194 |
# File 'lib/agent_harness.rb', line 192 def install_contract(name) Providers::Registry.instance.install_contract(name) end |
.installation_contract(provider_name, **options) ⇒ Hash?
Get installation metadata for a provider CLI.
220 221 222 |
# File 'lib/agent_harness.rb', line 220 def installation_contract(provider_name, **) Providers::Registry.instance.installation_contract(provider_name, **) end |
.installation_contracts ⇒ Hash<Symbol, Hash>
Get all provider installation contracts exposed by agent-harness.
226 227 228 |
# File 'lib/agent_harness.rb', line 226 def installation_contracts Providers::Registry.instance.installation_contracts end |
.load_extensions(path, adapter: nil) ⇒ Array<Extensions::Base>
Load one or more extensions from disk through an adapter.
109 110 111 |
# File 'lib/agent_harness.rb', line 109 def load_extensions(path, adapter: nil) configuration.load_extensions(path, adapter: adapter) end |
.logger ⇒ Logger?
Returns the global logger
57 58 59 |
# File 'lib/agent_harness.rb', line 57 def logger configuration.logger end |
.model_compatibility(runner:, model_id:, auth_mode: nil, cli_version: nil) ⇒ AgentHarness::ModelCompatibility::Result
Query runner/model compatibility contract.
Returns a structured AgentHarness::ModelCompatibility::Result
describing whether the named runner can execute model_id under
the requested runtime constraints. Downstream orchestrators should
consume this contract before validating tier models, selecting a
runner, or scheduling work — rather than inferring compatibility
from scattered CLI version pins, smoke-test overrides, or runtime
error strings.
292 293 294 295 296 297 298 299 |
# File 'lib/agent_harness.rb', line 292 def model_compatibility(runner:, model_id:, auth_mode: nil, cli_version: nil) Providers::Registry.instance.model_compatibility( runner, model_id: model_id, auth_mode: auth_mode, cli_version: cli_version ) end |
.provider(name) ⇒ Providers::Base
Get a provider instance
157 158 159 |
# File 'lib/agent_harness.rb', line 157 def provider(name) conductor.provider_manager.get_provider(name) end |
.provider_class(name) ⇒ Class
Look up the provider class for a given name or alias
173 174 175 |
# File 'lib/agent_harness.rb', line 173 def provider_class(name) Providers::Registry.instance.get(name) end |
.provider_install_contract(provider_name, version: nil) ⇒ Hash?
Returns install metadata for a provider CLI when the provider exposes it.
201 202 203 |
# File 'lib/agent_harness.rb', line 201 def provider_install_contract(provider_name, version: nil) provider_installation_contract(provider_name, **(version ? {version: version} : {})) end |
.provider_installation_contract(name, **options) ⇒ Hash?
Get the installation contract for a provider CLI.
211 212 213 |
# File 'lib/agent_harness.rb', line 211 def provider_installation_contract(name, **) Providers::Registry.instance.installation_contract(name, **) end |
.provider_metadata(provider_name, refresh: false) ⇒ Hash
Get consolidated metadata for a provider.
237 238 239 |
# File 'lib/agent_harness.rb', line 237 def (provider_name, refresh: false) Providers::Registry.instance.(provider_name, refresh: refresh) end |
.provider_metadata_catalog(refresh: false) ⇒ Hash<Symbol, Hash>
Get consolidated metadata for all registered providers.
246 247 248 |
# File 'lib/agent_harness.rb', line 246 def (refresh: false) Providers::Registry.instance.(refresh: refresh) end |
.provider_smoke_test_contract(provider_name) ⇒ Hash?
Get smoke-test metadata for a provider CLI when the provider exposes it.
254 255 256 |
# File 'lib/agent_harness.rb', line 254 def provider_smoke_test_contract(provider_name) smoke_test_contract(provider_name) end |
.providers ⇒ Array<Symbol>
List all registered provider names
164 165 166 |
# File 'lib/agent_harness.rb', line 164 def providers Providers::Registry.instance.all end |
.refresh_auth(provider_name, token: nil) ⇒ Hash
Refresh authentication credentials for a provider
370 371 372 |
# File 'lib/agent_harness.rb', line 370 def refresh_auth(provider_name, token: nil) Authentication.refresh_auth(provider_name, token: token) end |
.refresh_auth_supported?(provider_name) ⇒ Boolean
Check whether credential refresh is supported for a provider
361 362 363 |
# File 'lib/agent_harness.rb', line 361 def refresh_auth_supported?(provider_name) Authentication.refresh_auth_supported?(provider_name) end |
.reset! ⇒ void
This method returns an undefined value.
Reset configuration to defaults (useful for testing)
46 47 48 49 50 51 52 53 |
# File 'lib/agent_harness.rb', line 46 def reset! @configuration = nil @conductor = nil @token_tracker = nil @token_usage_tracker = nil @dependency_updater = nil Skills.reset! if defined?(Skills) end |
.resolve_latest_version(provider_name, bypass_cooldown: false) ⇒ Hash?
Resolve the latest eligible version for an installable provider tool, applying the configured cooldown period.
439 440 441 442 443 444 |
# File 'lib/agent_harness.rb', line 439 def resolve_latest_version(provider_name, bypass_cooldown: false) dependency_updater.resolve_latest_installation_contract( provider_name, bypass_cooldown: bypass_cooldown ) end |
.send_message(prompt, provider: nil, executor: nil, **options) ⇒ Response
Send a message using the orchestration layer
86 87 88 |
# File 'lib/agent_harness.rb', line 86 def (prompt, provider: nil, executor: nil, **) conductor.(prompt, provider: provider, executor: executor, **) end |
.smoke_test_contract(provider_name) ⇒ Hash?
Get smoke-test metadata for a provider CLI.
262 263 264 265 266 |
# File 'lib/agent_harness.rb', line 262 def smoke_test_contract(provider_name) # Explicitly raise if provider is not registered to match documentation raise ConfigurationError, "Unknown provider: #{provider_name}" unless Providers::Registry.instance.registered?(provider_name) Providers::Registry.instance.smoke_test_contract(provider_name) end |
.smoke_test_contracts ⇒ Hash<Symbol, Hash>
Get all provider smoke-test contracts exposed by agent-harness.
270 271 272 |
# File 'lib/agent_harness.rb', line 270 def smoke_test_contracts Providers::Registry.instance.smoke_test_contracts end |
.sub_agent(reference) ⇒ SubAgentConfig
Resolve a canonical sub-agent definition by name or inline payload.
141 142 143 |
# File 'lib/agent_harness.rb', line 141 def sub_agent(reference) configuration.resolve_sub_agent(reference) end |
.token_tracker ⇒ TokenTracker
Returns the global token tracker
63 64 65 |
# File 'lib/agent_harness.rb', line 63 def token_tracker @token_tracker ||= TokenTracker.new end |
.token_usage_tracker ⇒ TokenUsageTracker
Returns the global token usage tracker used as a fallback when providers do not expose a proactive quota API.
70 71 72 |
# File 'lib/agent_harness.rb', line 70 def token_usage_tracker @token_usage_tracker ||= TokenUsageTracker.new end |
.translate_sub_agent(reference, provider:) ⇒ Hash
Translate a canonical sub-agent definition into a provider-specific format.
150 151 152 |
# File 'lib/agent_harness.rb', line 150 def translate_sub_agent(reference, provider:) SubAgentTranslator.for_provider(provider, sub_agent(reference)) end |