agent-harness 0.5.7 → 0.5.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.release-please-manifest.json +1 -1
- data/AUDIT_DISPOSITION.md +111 -0
- data/CHANGELOG.md +21 -0
- data/README.md +140 -2
- data/lib/agent_harness/authentication.rb +28 -9
- data/lib/agent_harness/command_executor.rb +450 -13
- data/lib/agent_harness/docker_command_executor.rb +499 -8
- data/lib/agent_harness/error_taxonomy.rb +4 -4
- data/lib/agent_harness/execution_preparation.rb +64 -0
- data/lib/agent_harness/orchestration/provider_manager.rb +26 -6
- data/lib/agent_harness/provider_health_check.rb +28 -6
- data/lib/agent_harness/provider_runtime.rb +38 -11
- data/lib/agent_harness/providers/adapter.rb +596 -8
- data/lib/agent_harness/providers/aider.rb +71 -0
- data/lib/agent_harness/providers/anthropic.rb +110 -7
- data/lib/agent_harness/providers/base.rb +34 -5
- data/lib/agent_harness/providers/codex.rb +40 -9
- data/lib/agent_harness/providers/cursor.rb +76 -2
- data/lib/agent_harness/providers/gemini.rb +21 -6
- data/lib/agent_harness/providers/github_copilot.rb +12 -0
- data/lib/agent_harness/providers/kilocode.rb +16 -1
- data/lib/agent_harness/providers/mistral_vibe.rb +9 -0
- data/lib/agent_harness/providers/opencode.rb +64 -3
- data/lib/agent_harness/providers/registry.rb +392 -18
- data/lib/agent_harness/version.rb +1 -1
- data/lib/agent_harness.rb +29 -0
- metadata +3 -1
|
@@ -431,17 +431,39 @@ module AgentHarness
|
|
|
431
431
|
end
|
|
432
432
|
|
|
433
433
|
def build_provider(provider_name, klass, executor:)
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
)
|
|
434
|
+
canonical_name = Providers::Registry.instance.canonical_name(provider_name)
|
|
435
|
+
config = provider_config_for(provider_name, canonical_name: canonical_name)
|
|
436
|
+
executor ||= AgentHarness.configuration.command_executor
|
|
437
|
+
logger = AgentHarness.logger
|
|
438
|
+
|
|
439
|
+
provider = if klass.respond_to?(:build_provider_instance, true)
|
|
440
|
+
klass.send(:build_provider_instance, config: config, executor: executor, logger: logger)
|
|
441
|
+
else
|
|
442
|
+
klass.new(config: config, executor: executor, logger: logger)
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
# Ensure the executor is available even when the provider constructor
|
|
446
|
+
# accepts only a subset of keywords (e.g. config: only).
|
|
447
|
+
if provider.respond_to?(:executor=) && provider.executor.nil?
|
|
448
|
+
provider.executor = executor
|
|
449
|
+
elsif !provider.respond_to?(:executor)
|
|
450
|
+
provider.define_singleton_method(:executor) { executor }
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
provider
|
|
440
454
|
end
|
|
441
455
|
|
|
442
456
|
def monotonic_now
|
|
443
457
|
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
444
458
|
end
|
|
459
|
+
|
|
460
|
+
def provider_config_for(requested_name, canonical_name:)
|
|
461
|
+
requested_key = requested_name.to_sym
|
|
462
|
+
canonical_key = canonical_name.to_sym
|
|
463
|
+
|
|
464
|
+
AgentHarness.configuration.providers[requested_key] ||
|
|
465
|
+
AgentHarness.configuration.providers[canonical_key]
|
|
466
|
+
end
|
|
445
467
|
end
|
|
446
468
|
end
|
|
447
469
|
end
|
|
@@ -35,11 +35,15 @@ module AgentHarness
|
|
|
35
35
|
# @param unset_env [Array<String>] environment variable names to remove from inherited env
|
|
36
36
|
# @param metadata [Hash] arbitrary provider-specific data
|
|
37
37
|
def initialize(model: nil, base_url: nil, api_provider: nil, env: {}, flags: [], unset_env: [], metadata: {})
|
|
38
|
+
validate_optional_string!(:model, model)
|
|
39
|
+
validate_optional_string!(:base_url, base_url)
|
|
40
|
+
validate_optional_string!(:api_provider, api_provider)
|
|
41
|
+
|
|
38
42
|
@model = model
|
|
39
43
|
@base_url = base_url
|
|
40
44
|
@api_provider = api_provider
|
|
41
45
|
|
|
42
|
-
env_hash = env
|
|
46
|
+
env_hash = env.nil? ? {} : env
|
|
43
47
|
unless env_hash.is_a?(Hash)
|
|
44
48
|
raise ArgumentError, "env must be a Hash (got #{env_hash.class})"
|
|
45
49
|
end
|
|
@@ -52,7 +56,7 @@ module AgentHarness
|
|
|
52
56
|
end
|
|
53
57
|
@env = normalized_env.freeze
|
|
54
58
|
|
|
55
|
-
normalized_flags = flags
|
|
59
|
+
normalized_flags = flags.nil? ? [] : flags
|
|
56
60
|
unless normalized_flags.is_a?(Array)
|
|
57
61
|
raise ArgumentError, "flags must be an Array (got #{normalized_flags.class})"
|
|
58
62
|
end
|
|
@@ -65,7 +69,7 @@ module AgentHarness
|
|
|
65
69
|
end
|
|
66
70
|
@flags = normalized_flags.freeze
|
|
67
71
|
|
|
68
|
-
metadata_hash = metadata
|
|
72
|
+
metadata_hash = metadata.nil? ? {} : metadata
|
|
69
73
|
unless metadata_hash.is_a?(Hash)
|
|
70
74
|
raise ArgumentError, "metadata must be a Hash (got #{metadata_hash.class})"
|
|
71
75
|
end
|
|
@@ -74,7 +78,7 @@ module AgentHarness
|
|
|
74
78
|
# Unset environment variables for the request. These are variable names that
|
|
75
79
|
# should be removed from the inherited environment before the provider
|
|
76
80
|
# command runs.
|
|
77
|
-
unset_array = unset_env
|
|
81
|
+
unset_array = unset_env.nil? ? [] : unset_env
|
|
78
82
|
unless unset_array.is_a?(Array)
|
|
79
83
|
raise ArgumentError, "unset_env must be an Array (got #{unset_array.class})"
|
|
80
84
|
end
|
|
@@ -96,14 +100,19 @@ module AgentHarness
|
|
|
96
100
|
def self.from_hash(hash)
|
|
97
101
|
raise ArgumentError, "expected a Hash, got #{hash.class}" unless hash.is_a?(Hash)
|
|
98
102
|
|
|
103
|
+
env_val = hash_value(hash, :env)
|
|
104
|
+
flags_val = hash_value(hash, :flags)
|
|
105
|
+
unset_env_val = hash_value(hash, :unset_env)
|
|
106
|
+
metadata_val = hash_value(hash, :metadata)
|
|
107
|
+
|
|
99
108
|
new(
|
|
100
|
-
model: hash
|
|
101
|
-
base_url: hash
|
|
102
|
-
api_provider: hash
|
|
103
|
-
env:
|
|
104
|
-
flags:
|
|
105
|
-
unset_env:
|
|
106
|
-
metadata:
|
|
109
|
+
model: hash_value(hash, :model),
|
|
110
|
+
base_url: hash_value(hash, :base_url),
|
|
111
|
+
api_provider: hash_value(hash, :api_provider),
|
|
112
|
+
env: env_val.nil? ? {} : env_val,
|
|
113
|
+
flags: flags_val.nil? ? [] : flags_val,
|
|
114
|
+
unset_env: unset_env_val.nil? ? [] : unset_env_val,
|
|
115
|
+
metadata: metadata_val.nil? ? {} : metadata_val
|
|
107
116
|
)
|
|
108
117
|
end
|
|
109
118
|
|
|
@@ -128,5 +137,23 @@ module AgentHarness
|
|
|
128
137
|
model.nil? && base_url.nil? && api_provider.nil? &&
|
|
129
138
|
env.empty? && flags.empty? && metadata.empty? && unset_env.empty?
|
|
130
139
|
end
|
|
140
|
+
|
|
141
|
+
private_class_method def self.hash_value(hash, key)
|
|
142
|
+
sym_value = hash[key]
|
|
143
|
+
str_value = hash[key.to_s]
|
|
144
|
+
# Prefer the symbol key; fall back to the string key only when the
|
|
145
|
+
# symbol key is nil (not just falsy) so that an explicit `false` is
|
|
146
|
+
# not silently discarded.
|
|
147
|
+
sym_value.nil? ? str_value : sym_value
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
private
|
|
151
|
+
|
|
152
|
+
def validate_optional_string!(name, value)
|
|
153
|
+
return if value.nil?
|
|
154
|
+
return if value.is_a?(String)
|
|
155
|
+
|
|
156
|
+
raise ArgumentError, "#{name} must be a String or nil (got #{value.class})"
|
|
157
|
+
end
|
|
131
158
|
end
|
|
132
159
|
end
|