agent-harness 0.5.6 → 0.5.8

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 946d7c425aff8c96536bc30def7e0abdba7ff7d82020f4941674a8c93be63526
4
- data.tar.gz: ffc9d707f89ab60bf9cc59b4e5ccbcd2570a3aaa07e97c5a10bfb731f5dc07a0
3
+ metadata.gz: 93f5a11872f464b3eb9834c849f076d9f393f9e1174bc9824952f4c217c9278f
4
+ data.tar.gz: 25bbd835fd6739f84597d0d5653443ecd238b0e89f20f5e0b20029cb5d8bb119
5
5
  SHA512:
6
- metadata.gz: c7b0dcef83c7a31be09a87884211a8ba03c0c93fb845e666423cd17eb70a358dd122db7e57ce04271fa5e114013adbc0007394211286c23b03cfa6a2a600c68f
7
- data.tar.gz: a8f14eb24039afd0a93ec1eb064b59ebbe6d03aafd61ab1859c64729d2253140afebacc5c8ee761578337c671c074425784c33676808534cdf7b8ad809a2df32
6
+ metadata.gz: '081955132b518b5d94498bfeb54ddd7641f1d6968fcb53debf143f7762a666edd40dde6a1369553a42c0dc4985cbff9cb41d7ade8dd727fa80572e7a7293cd2f'
7
+ data.tar.gz: 0345fc32a87b27ba001ae0a6cd26c5b1cc2765f64d7d81bad025b461182cdb0a814c8cdd031478b4e7dcf8bbe1f6b2638e3814cbf3c9537e038dc8bca1255a1f
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "0.5.6"
2
+ ".": "0.5.8"
3
3
  }
data/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.5.8](https://github.com/viamin/agent-harness/compare/agent-harness/v0.5.7...agent-harness/v0.5.8) (2026-04-07)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * 64: feat(installers): make Claude CLI installation/version support a first-class provider contract ([#78](https://github.com/viamin/agent-harness/issues/78)) ([0d83590](https://github.com/viamin/agent-harness/commit/0d83590dc9bb9bc7c8d621660bcd73b8eb613d43))
9
+ * 70: feat(installers): make Cursor agent CLI installation/version support a first-class provider contract ([#82](https://github.com/viamin/agent-harness/issues/82)) ([483e9be](https://github.com/viamin/agent-harness/commit/483e9be752de9548020135a86170d978d2a23ae8))
10
+ * 71: feat(installers): make Aider CLI installation/version support a first-class provider contract ([#84](https://github.com/viamin/agent-harness/issues/84)) ([3cfcc1c](https://github.com/viamin/agent-harness/commit/3cfcc1cac831060c12fd8a39130ee7bb9b048aa5))
11
+ * 74: feat(providers): expose provider capability/installability/auth metadata for downstream apps ([#88](https://github.com/viamin/agent-harness/issues/88)) ([4f9b3ba](https://github.com/viamin/agent-harness/commit/4f9b3ba6a53c830eaf53e9233e8df38970c52c8c))
12
+
13
+ ## [0.5.7](https://github.com/viamin/agent-harness/compare/agent-harness/v0.5.6...agent-harness/v0.5.7) (2026-04-07)
14
+
15
+
16
+ ### Bug Fixes
17
+
18
+ * 59: fix(codex): replace invalid '--sandbox none' for externally sandboxed runs ([#89](https://github.com/viamin/agent-harness/issues/89)) ([6b0fac5](https://github.com/viamin/agent-harness/commit/6b0fac5e9b83c70c3a55004d9c5ad354a6d3dced))
19
+ * 60: feat: support per-request executor overrides for orchestrated send_message ([#87](https://github.com/viamin/agent-harness/issues/87)) ([7711770](https://github.com/viamin/agent-harness/commit/7711770ab3c9a6659171df1033038acf08b8d5a9))
20
+ * 61: feat: support idle-timeout and streaming execution hooks for long-running provider runs ([#90](https://github.com/viamin/agent-harness/issues/90)) ([adf7558](https://github.com/viamin/agent-harness/commit/adf75583994f78af9d6f5b44eba729b616b46f02))
21
+ * 62: feat: support per-request environment unsets for provider execution ([#76](https://github.com/viamin/agent-harness/issues/76)) ([2dfdb8e](https://github.com/viamin/agent-harness/commit/2dfdb8e6138f21ca0dd1a9e0b2d7cc17d1776612))
22
+ * 63: fix(copilot): align GithubCopilot provider with a real installable CLI contract ([#75](https://github.com/viamin/agent-harness/issues/75)) ([9e585e7](https://github.com/viamin/agent-harness/commit/9e585e79252ac8431fb99bc16bc9ebbecb83439e))
23
+ * 65: feat(installers): make Codex CLI installation/version support a first-class provider contract ([#79](https://github.com/viamin/agent-harness/issues/79)) ([a3f5849](https://github.com/viamin/agent-harness/commit/a3f5849db1bcfa162af98fa5339cf8b8f5314920))
24
+ * 66: feat(installers): make Gemini CLI installation/version support a first-class provider contract ([#80](https://github.com/viamin/agent-harness/issues/80)) ([e349ab6](https://github.com/viamin/agent-harness/commit/e349ab64601cb2fe9bafb488e6b4f96fbcbf012b))
25
+ * 67: feat(installers): make Kilocode CLI installation/version support a first-class provider contract ([#81](https://github.com/viamin/agent-harness/issues/81)) ([547baf5](https://github.com/viamin/agent-harness/commit/547baf5be93939a00cdac1e3d17824eb6dbfb324))
26
+ * 68: feat(installers): make OpenCode CLI installation/version support a first-class provider contract ([#83](https://github.com/viamin/agent-harness/issues/83)) ([21caaf4](https://github.com/viamin/agent-harness/commit/21caaf4e003c41a7fa127e7244c4a61abad7f1cb))
27
+ * 72: feat(providers): add first-class smoke-test/health-check execution contracts for CLI providers ([#85](https://github.com/viamin/agent-harness/issues/85)) ([7c0db3a](https://github.com/viamin/agent-harness/commit/7c0db3a5aa93e62e38240821dfb00b489ad3793b))
28
+
3
29
  ## [0.5.6](https://github.com/viamin/agent-harness/compare/agent-harness/v0.5.5...agent-harness/v0.5.6) (2026-03-30)
4
30
 
5
31
 
data/README.md CHANGED
@@ -5,7 +5,7 @@ A unified Ruby interface for CLI-based AI coding agents like Claude Code, Cursor
5
5
  ## Features
6
6
 
7
7
  - **Unified Interface**: Single API for multiple AI coding agents
8
- - **8 Built-in Providers**: Claude Code, Cursor, Gemini CLI, GitHub Copilot, Codex, Aider, OpenCode, Kilocode
8
+ - **9 Built-in Providers**: Claude Code, Cursor, Gemini CLI, GitHub Copilot, Codex, Aider, OpenCode, Kilocode, Mistral Vibe
9
9
  - **Full Orchestration**: Provider switching, circuit breakers, rate limiting, and health monitoring
10
10
  - **Flexible Configuration**: YAML, Ruby DSL, or environment variables
11
11
  - **Token Tracking**: Monitor usage across providers for cost and limit management
@@ -106,7 +106,61 @@ end
106
106
  | `:codex` | `codex` | OpenAI Codex CLI |
107
107
  | `:aider` | `aider` | Aider coding assistant |
108
108
  | `:opencode` | `opencode` | OpenCode CLI |
109
- | `:kilocode` | `kilocode` | Kilocode CLI |
109
+ | `:kilocode` | `kilo` | Kilocode CLI |
110
+ | `:mistral_vibe` | `mistral-vibe` | Mistral Vibe CLI |
111
+
112
+ ### Provider Install Contracts
113
+
114
+ Provider classes can expose install metadata for downstream apps that build
115
+ their own agent images.
116
+
117
+ ```ruby
118
+ contract = AgentHarness.provider_install_contract(:gemini)
119
+
120
+ contract[:package_name]
121
+ # => "@google/gemini-cli"
122
+
123
+ contract[:default_version]
124
+ # => "0.35.3"
125
+
126
+ contract[:install_command]
127
+ # => ["npm", "install", "-g", "--ignore-scripts", "@google/gemini-cli@0.35.3"]
128
+ ```
129
+
130
+ Cursor also exposes a first-class install contract for container/image builds.
131
+ The contract publishes checksums for both the installer script and the default
132
+ Linux x64 artifact so consumers can verify downloads independently:
133
+
134
+ ```ruby
135
+ cursor_install = AgentHarness::Providers::Cursor.install_metadata
136
+
137
+ cursor_install
138
+ # => {
139
+ # source: {
140
+ # type: :shell_script,
141
+ # url: "https://cursor.com/install",
142
+ # resolved_version: "2026.03.30-a5d3e17",
143
+ # default_artifact_url: "https://downloads.cursor.com/lab/2026.03.30-a5d3e17/linux/x64/agent-cli-package.tar.gz"
144
+ # },
145
+ # checksum: {
146
+ # strategy: :sha256,
147
+ # targets: {
148
+ # script: { url: "https://cursor.com/install", value: "8371..." },
149
+ # artifacts: { "linux/x64" => { url: "https://downloads.cursor.com/...", value: "e0d4..." } }
150
+ # }
151
+ # },
152
+ # binary: {
153
+ # name: "cursor-agent",
154
+ # path: "$HOME/.local/bin/cursor-agent",
155
+ # suggested_global_path: "/usr/local/bin/cursor-agent"
156
+ # },
157
+ # version: {
158
+ # default: "latest",
159
+ # supported: "latest",
160
+ # command: ["cursor-agent", "--version"]
161
+ # }
162
+ # }
163
+ ```
110
164
 
111
165
  ### Direct Provider Access
112
166
 
@@ -120,11 +174,157 @@ if AgentHarness::Providers::Registry.instance.get(:claude).available?
120
174
  puts "Claude CLI is installed"
121
175
  end
122
176
 
177
+ # Ask the harness which Claude CLI install contract it supports
178
+ contract = AgentHarness.install_contract(:claude)
179
+ puts contract[:install][:command]
180
+ # => "tmp_script=$(mktemp) && ... && bash \"$tmp_script\" 2.1.92"
181
+ puts contract[:install][:post_install_binary_path]
182
+ # => "$HOME/.local/bin/claude"
183
+ puts contract[:supported_versions][:default]
184
+ # => "2.1.92"
185
+ puts contract[:supported_versions][:requirement]
186
+ # => ">= 2.1.92, < 2.2.0"
187
+
123
188
  # List all registered providers
124
189
  AgentHarness::Providers::Registry.instance.all
125
- # => [:claude, :cursor, :gemini, :github_copilot, :codex, :opencode, :kilocode, :aider]
190
+ # => [:claude, :cursor, :gemini, :github_copilot, :codex, :opencode, :kilocode, :aider, :mistral_vibe]
126
191
  ```
127
192
 
193
+ For Claude, the install contract is the first-class source of truth for:
194
+
195
+ - the official install recipe the current harness release expects
196
+ - the expected binary name and normalized PATH entry that recipe leaves behind
197
+ - the supported Claude CLI version boundary the current harness release validates (`default` plus the compatible version range)
198
+
199
+ ### Provider Installation Contracts
200
+
201
+ Downstream apps can ask `agent-harness` for provider-specific CLI install
202
+ metadata instead of hardcoding package names, binary names, or supported
203
+ versions out-of-band.
204
+
205
+ ```ruby
206
+ contract = AgentHarness.provider_installation_contract(:kilocode, version: "7.1.3")
207
+
208
+ contract
209
+ # {
210
+ # source: { type: :npm, package: "@kilocode/cli" },
211
+ # install_command: ["npm", "install", "-g", "--ignore-scripts", "@kilocode/cli@7.1.3"],
212
+ # binary_name: "kilo",
213
+ # default_version: "7.1.3",
214
+ # supported_version_requirement: "= 7.1.3"
215
+ # }
216
+ ```
217
+
218
+ The Kilocode runtime adapter expects the `kilo` binary and executes prompts via
219
+ `kilo run ...`, so the install contract and runtime behavior stay aligned in
220
+ tests.
221
+
222
+ Providers that expose installation contracts can also be queried through the
223
+ generic API:
224
+
225
+ ```ruby
226
+ codex_install = AgentHarness.installation_contract(:codex)
227
+ aider_install = AgentHarness.installation_contract(:aider)
228
+ opencode_install = AgentHarness.installation_contract(:opencode)
229
+
230
+ opencode_install
231
+ # => {
232
+ # source: :npm,
233
+ # package_name: "opencode-ai",
234
+ # version: "1.3.2",
235
+ # version_requirement: [">= 1.3.2", "< 1.4.0"],
236
+ # binary_name: "opencode",
237
+ # install_command: ["npm", "install", "-g", "--ignore-scripts", "opencode-ai@1.3.2"]
238
+ # }
239
+
240
+ aider_install
241
+ # => {
242
+ # source: :uv_tool,
243
+ # bootstrap_package: "uv==0.8.17",
244
+ # package_name: "aider-chat",
245
+ # version: "0.86.2",
246
+ # binary_name: "aider",
247
+ # binary_path: "/usr/local/bin/aider",
248
+ # install_environment: {
249
+ # "UV_TOOL_BIN_DIR" => "/usr/local/bin",
250
+ # "UV_TOOL_DIR" => "/opt/uv/tools",
251
+ # "UV_PYTHON_INSTALL_DIR" => "/opt/uv/python"
252
+ # },
253
+ # bootstrap_commands: [
254
+ # ["python3", "-m", "pip", "install", "--no-cache-dir", "--break-system-packages", "uv==0.8.17"]
255
+ # ],
256
+ # install_command: ["uv", "tool", "install", "--force", "--python", "python3.12", "--with", "pip", "aider-chat==0.86.2"]
257
+ # }
258
+ ```
259
+
260
+ For supported providers like Codex and Aider, the install contract tracks
261
+ the CLI version supported by the current `agent-harness` release. The
262
+ contract includes bootstrap requirements, install command shape, and the
263
+ expected runtime binary, and the provider specs assert that runtime
264
+ expectations remain aligned with the published install metadata.
265
+
266
+ ### Provider Metadata
267
+
268
+ Downstream apps can also query a consolidated provider metadata contract for
269
+ configuration UIs and policy decisions.
270
+
271
+ The following example shows how to retrieve metadata for the Anthropic provider:
272
+
273
+ ```ruby
274
+ metadata = AgentHarness.provider_metadata(:anthropic)
275
+
276
+ metadata
277
+ # => {
278
+ # provider: :claude,
279
+ # canonical_provider: :claude,
280
+ # aliases: [:anthropic],
281
+ # auth: {
282
+ # default_mode: :oauth,
283
+ # supported_modes: [:oauth],
284
+ # service: :anthropic,
285
+ # api_family: :anthropic
286
+ # },
287
+ # runtime: {
288
+ # interface: :cli,
289
+ # requires_cli: true,
290
+ # installable: false,
291
+ # installation: nil,
292
+ # supports_mcp: true,
293
+ # supports_dangerous_mode: true
294
+ # },
295
+ # health_check: {
296
+ # supports_registry_checks: true,
297
+ # auth_check_supported: true,
298
+ # lightweight: true
299
+ # },
300
+ # identity: {
301
+ # bot_usernames: ["claude", "anthropic"]
302
+ # }
303
+ # }
304
+ ```
305
+
306
+ To enumerate the full catalog:
307
+
308
+ ```ruby
309
+ AgentHarness.provider_metadata_catalog
310
+ # => { claude: {...}, cursor: {...}, gemini: {...}, ... }
311
+ ```
312
+
313
+ Provider metadata is cached so repeated catalog reads stay cheap.
314
+ Pass `refresh: true` to rebuild metadata and re-run live availability checks when needed:
315
+
316
+ ```ruby
317
+ AgentHarness.provider_metadata(:anthropic, refresh: true)
318
+ AgentHarness.provider_metadata_catalog(refresh: true)
319
+ ```
320
+
321
+ For providers with install contracts, the metadata tracks the CLI version
322
+ supported by the current `agent-harness` release, and the runtime adapter
323
+ tests assert that the expected binary remains aligned with that contract.
324
+ `runtime[:installation]` is normalized to a stable shape with
325
+ `source_type`, `package_name`, version fields, and install commands so
326
+ downstream apps do not need provider-specific branching.
327
+
128
328
  ### Custom Providers
129
329
 
130
330
  ```ruby
@@ -138,6 +338,19 @@ class MyProvider < AgentHarness::Providers::Base
138
338
  "my-cli"
139
339
  end
140
340
 
341
+ def install_contract(version: "1.2.3")
342
+ {
343
+ provider: provider_name,
344
+ source_type: :npm,
345
+ package_name: "@acme/my-cli",
346
+ supported_version_requirement: Gem::Requirement.new("~> 1.2"),
347
+ default_version: "1.2.3",
348
+ resolved_version: version,
349
+ binary_name: binary_name,
350
+ install_command: ["npm", "install", "-g", "@acme/my-cli@#{version}"]
351
+ }
352
+ end
353
+
141
354
  def available?
142
355
  system("which my-cli > /dev/null 2>&1")
143
356
  end
@@ -94,15 +94,26 @@ module AgentHarness
94
94
 
95
95
  def resolve_provider(provider_name)
96
96
  klass = Providers::Registry.instance.get(provider_name)
97
- # Construct the provider with config/executor/logger to match
98
- # ProviderManager#create_provider and support custom providers
99
- # that may rely on these initializer arguments.
100
- config = AgentHarness.configuration.providers[provider_name]
101
- klass.new(
102
- config: config,
103
- executor: AgentHarness.configuration.command_executor,
104
- logger: AgentHarness.logger
105
- )
97
+ canonical_name = Providers::Registry.instance.canonical_name(provider_name)
98
+ config = provider_config_for(provider_name, canonical_name: canonical_name)
99
+ executor = AgentHarness.configuration.command_executor
100
+ logger = AgentHarness.logger
101
+
102
+ provider = if klass.respond_to?(:build_provider_instance, true)
103
+ klass.send(:build_provider_instance, config: config, executor: executor, logger: logger)
104
+ else
105
+ klass.new(config: config, executor: executor, logger: logger)
106
+ end
107
+
108
+ # Ensure the executor is available even when the provider constructor
109
+ # accepts only a subset of keywords (e.g. config: only).
110
+ if provider.respond_to?(:executor=) && provider.executor.nil?
111
+ provider.executor = executor
112
+ elsif !provider.respond_to?(:executor)
113
+ provider.define_singleton_method(:executor) { executor }
114
+ end
115
+
116
+ provider
106
117
  rescue ConfigurationError
107
118
  raise ProviderNotFoundError, "Unknown provider: #{provider_name}"
108
119
  end
@@ -152,6 +163,14 @@ module AgentHarness
152
163
  "https://claude.ai/oauth/authorize"
153
164
  end
154
165
 
166
+ def provider_config_for(requested_name, canonical_name:)
167
+ requested_key = requested_name.to_sym
168
+ canonical_key = canonical_name.to_sym
169
+
170
+ AgentHarness.configuration.providers[requested_key] ||
171
+ AgentHarness.configuration.providers[canonical_key]
172
+ end
173
+
155
174
  def refresh_claude_auth(token: nil)
156
175
  raise ArgumentError, "token must be a non-empty string" unless token.is_a?(String) && !token.strip.empty?
157
176