agent-harness 0.11.1 → 0.11.3

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.
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AgentHarness
4
+ module Providers
5
+ # Shared concern for writing and cleaning up MCP configuration tempfiles.
6
+ #
7
+ # Include this module in any provider that needs to write MCP config files
8
+ # for CLI processes. The including class must define an +mcp_provider_key+
9
+ # method that returns the symbol passed to +McpConfigTranslator.for_provider+.
10
+ module McpConfigFileSupport
11
+ def write_mcp_config_file(mcp_servers, working_dir: nil)
12
+ require "tempfile"
13
+ require "tmpdir"
14
+ require "securerandom"
15
+
16
+ config = McpConfigTranslator.for_provider(mcp_provider_key, mcp_servers)
17
+ config_json = JSON.generate(config)
18
+
19
+ if @executor.is_a?(DockerCommandExecutor)
20
+ # When running inside a Docker container, write the config file
21
+ # inside the container so the CLI process can read it.
22
+ # Track the path so cleanup_mcp_tempfiles! can remove it after execution.
23
+ container_path = "/tmp/agent_harness_mcp_#{SecureRandom.hex(8)}.json"
24
+ result = @executor.execute(
25
+ ["sh", "-c", "cat > #{container_path}"],
26
+ stdin_data: config_json,
27
+ timeout: 5
28
+ )
29
+ unless result.success?
30
+ raise McpConfigurationError,
31
+ "Failed to write MCP config inside container: #{result.stderr}"
32
+ end
33
+
34
+ @mcp_docker_config_paths ||= []
35
+ @mcp_docker_config_paths << container_path
36
+
37
+ container_path
38
+ else
39
+ dir = working_dir || Dir.tmpdir
40
+ file = Tempfile.new(["agent_harness_mcp_", ".json"], dir)
41
+ file.write(config_json)
42
+ file.close
43
+
44
+ # Hold a reference so the Tempfile is not garbage-collected (and
45
+ # therefore deleted) before the CLI process reads it.
46
+ # Cleaned up by cleanup_mcp_tempfiles! after execution.
47
+ @mcp_config_tempfiles ||= []
48
+ @mcp_config_tempfiles << file
49
+
50
+ file.path
51
+ end
52
+ end
53
+
54
+ def cleanup_mcp_tempfiles!
55
+ if @mcp_config_tempfiles
56
+ @mcp_config_tempfiles.each do |file|
57
+ file.close unless file.closed?
58
+ file.unlink
59
+ rescue
60
+ nil
61
+ end
62
+ @mcp_config_tempfiles = nil
63
+ end
64
+
65
+ if @mcp_docker_config_paths
66
+ @mcp_docker_config_paths.each do |path|
67
+ @executor.execute(["rm", "-f", path], timeout: 5)
68
+ rescue
69
+ nil
70
+ end
71
+ @mcp_docker_config_paths = nil
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AgentHarness
4
- VERSION = "0.11.1"
4
+ VERSION = "0.11.3"
5
5
  end
data/lib/agent_harness.rb CHANGED
@@ -77,6 +77,47 @@ module AgentHarness
77
77
  conductor.send_message(prompt, provider: provider, executor: executor, **options)
78
78
  end
79
79
 
80
+ # Resolve a canonical extension definition by name or inline object.
81
+ #
82
+ # @param reference [Symbol, String, Extensions::Base]
83
+ # @return [Extensions::Base]
84
+ def extension(reference)
85
+ configuration.resolve_extension(reference)
86
+ end
87
+
88
+ # Load one or more extensions from disk through an adapter.
89
+ #
90
+ # @param path [String] extension file, directory, or package root
91
+ # @param adapter [Symbol, String, nil] optional explicit adapter
92
+ # @return [Array<Extensions::Base>]
93
+ def load_extensions(path, adapter: nil)
94
+ configuration.load_extensions(path, adapter: adapter)
95
+ end
96
+
97
+ # Discover and register all extensions found in a directory.
98
+ #
99
+ # @param directory [String] directory to scan
100
+ # @return [Array<Extensions::Base>]
101
+ def discover_extensions(directory)
102
+ configuration.discover_extensions(directory)
103
+ end
104
+
105
+ # Build a compatibility report for extensions against a provider.
106
+ #
107
+ # @param provider [Symbol, String, Providers::Base] target provider
108
+ # @param extensions [Array<Symbol, String, Extensions::Base>] extension references
109
+ # @return [Array<Extensions::CompatibilityReport>]
110
+ def extension_compatibility(provider:, extensions:)
111
+ provider_instance = provider.is_a?(Providers::Base) ? provider : self.provider(provider)
112
+
113
+ Array(extensions).map do |extension_ref|
114
+ Extensions::Compatibility.report(
115
+ provider: provider_instance,
116
+ extension: extension(extension_ref)
117
+ )
118
+ end
119
+ end
120
+
80
121
  # Resolve a canonical sub-agent definition by name or inline payload.
81
122
  #
82
123
  # @param reference [Symbol, String, Hash, SubAgentConfig]
@@ -277,7 +318,10 @@ end
277
318
 
278
319
  # Core components
279
320
  require_relative "agent_harness/errors"
321
+ require_relative "agent_harness/extensions"
280
322
  require_relative "agent_harness/mcp_server"
323
+ require_relative "agent_harness/mcp_config_loader"
324
+ require_relative "agent_harness/mcp_config_translator"
281
325
  require_relative "agent_harness/sub_agent_config"
282
326
  require_relative "agent_harness/sub_agent_file_loader"
283
327
  require_relative "agent_harness/sub_agent_translator"
@@ -301,6 +345,7 @@ require_relative "agent_harness/providers/adapter"
301
345
  require_relative "agent_harness/providers/base"
302
346
  require_relative "agent_harness/providers/token_usage_parsing"
303
347
  require_relative "agent_harness/providers/rate_limit_reset_parsing"
348
+ require_relative "agent_harness/providers/mcp_config_file_support"
304
349
  require_relative "agent_harness/providers/anthropic"
305
350
  require_relative "agent_harness/providers/aider"
306
351
  require_relative "agent_harness/providers/codex"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: agent-harness
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.1
4
+ version: 0.11.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bart Agapinan
@@ -107,6 +107,9 @@ files:
107
107
  - lib/agent_harness/error_taxonomy.rb
108
108
  - lib/agent_harness/errors.rb
109
109
  - lib/agent_harness/execution_preparation.rb
110
+ - lib/agent_harness/extensions.rb
111
+ - lib/agent_harness/mcp_config_loader.rb
112
+ - lib/agent_harness/mcp_config_translator.rb
110
113
  - lib/agent_harness/mcp_server.rb
111
114
  - lib/agent_harness/openai_compatible_transport.rb
112
115
  - lib/agent_harness/orchestration/circuit_breaker.rb
@@ -126,6 +129,7 @@ files:
126
129
  - lib/agent_harness/providers/gemini.rb
127
130
  - lib/agent_harness/providers/github_copilot.rb
128
131
  - lib/agent_harness/providers/kilocode.rb
132
+ - lib/agent_harness/providers/mcp_config_file_support.rb
129
133
  - lib/agent_harness/providers/mistral_vibe.rb
130
134
  - lib/agent_harness/providers/opencode.rb
131
135
  - lib/agent_harness/providers/rate_limit_reset_parsing.rb