agent-harness 0.44.26 → 0.44.28

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: d7b271da3cff56d6633f7d633993c64aa186e6360d5a3442f232329a97b077e0
4
- data.tar.gz: 37f0c06a56587a2a863498a832ba3c0999f479acaa44f6354ca04f1af3246ba9
3
+ metadata.gz: e80d5408a298ecc69d9bb926850bbf11affb491c0df7cbc466196c26efbbc719
4
+ data.tar.gz: 28268cff5cf59d3aea8c38f5eca82231b531bcdf41b289e9d14ff5720ad2fbc8
5
5
  SHA512:
6
- metadata.gz: fc0d4a2152c6e7e495aea499a86c0ea5e020a7f139fa2637cd7169f4f47ad569f34042dc00146be2aeede2b700d5af9814ed9bc261896d042c9391d4d9b97322
7
- data.tar.gz: 8b40c6e8699233b221d307b7e04cc3026eb5c3107e7c9b39ca0827d9b174121baf1ea5763b212c7e8f6f9b9c164b9a125d04bb4b0fffd6f343c9d998d5323833
6
+ metadata.gz: f77240dc395e73f9eef1e052d027ee4207720e709ef378b419637c929d2ae0d3eb26004e7b440a8d6638ab8243febe43439416b1182eb1db861bc96e121e902d
7
+ data.tar.gz: cd98f25ef91e81e9636f7e70e2cdf3fe884085fde1781dc60e6593c99078e74fc6dd41aaa9f9972c99c7ab3b9f0a83f1847c6f57a8961dcc6c1b6ba09cad9bdc
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "0.44.26"
2
+ ".": "0.44.28"
3
3
  }
data/CHANGELOG.md CHANGED
@@ -12,6 +12,20 @@
12
12
 
13
13
  * close the RDR-072 upstream epic from #437's retained-scope evidence while keeping unpublished capabilities and downstream adoption behind their explicit release and integration gates ([#430](https://github.com/viamin/agent-harness/issues/430)).
14
14
 
15
+ ## [0.44.28](https://github.com/viamin/agent-harness/compare/agent-harness/v0.44.27...agent-harness/v0.44.28) (2026-10-28)
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * **opencode:** surface MiniMax Token Plan HTTP 429 during preflight ([#518](https://github.com/viamin/agent-harness/issues/518)) ([d6f6288](https://github.com/viamin/agent-harness/commit/d6f6288f239cba6ac241edf87987bec22300a7b4))
21
+
22
+ ## [0.44.27](https://github.com/viamin/agent-harness/compare/agent-harness/v0.44.26...agent-harness/v0.44.27) (2026-10-25)
23
+
24
+
25
+ ### Bug Fixes
26
+
27
+ * **deps-dev:** bump @oh-my-pi/pi-coding-agent from 18.11.2 to 18.12.6 in /vendor/pins/omp ([#509](https://github.com/viamin/agent-harness/issues/509)) ([4d4fb20](https://github.com/viamin/agent-harness/commit/4d4fb20fcf781709a36bb4e33bb981f5ee555e20))
28
+
15
29
  ## [0.44.26](https://github.com/viamin/agent-harness/compare/agent-harness/v0.44.25...agent-harness/v0.44.26) (2026-10-25)
16
30
 
17
31
 
data/README.md CHANGED
@@ -834,7 +834,13 @@ results.each do |r|
834
834
  end
835
835
 
836
836
  # Check a single provider
837
- result = AgentHarness.check_provider(:claude)
837
+ minimax_runtime = AgentHarness::ProviderRuntime.new(
838
+ api_provider: "minimax",
839
+ model: "MiniMax-M3",
840
+ base_url: ENV.fetch("MINIMAX_BASE_URL"),
841
+ env: {"MINIMAX_API_KEY" => ENV.fetch("MINIMAX_API_KEY")}
842
+ )
843
+ result = AgentHarness.check_provider(:opencode, provider_runtime: minimax_runtime)
838
844
  puts result[:status] # => "ok", "degraded", or "error"
839
845
 
840
846
  # Formatted CLI output
@@ -847,8 +853,11 @@ Each result is a hash with keys:
847
853
  - `:status` — `"ok"` (all checks passed), `"degraded"` (partial issues such as unimplemented auth status), or `"error"` (provider unavailable or authentication failed)
848
854
  - `:message` — human-readable description
849
855
  - `:latency_ms` — time taken for the check in milliseconds
856
+ - `:error_category` — structured failure category such as `:rate_limit`, `:authentication`, or `:timeout`
857
+ - `:check` — the check that produced the result, such as `:preflight` or `:smoke_test`
858
+ - `:reset_at` — provider-supplied rate-limit reset time when one is available; otherwise omitted
850
859
 
851
- Health checks run five steps per provider: registration, CLI availability, authentication, provider health status, and configuration validation. The default timeout per provider is configurable via `orchestration.health_check.timeout` (default: 5 seconds).
860
+ Health checks cover registration, CLI availability, authentication, provider health, configuration, provider-owned preflight, and a bounded smoke test. For direct MiniMax OpenCode runtimes, preflight makes one no-retry provider request so an upstream HTTP 429 is returned as `error_category: :rate_limit` before OpenCode's smoke timeout. The default timeout per provider is configurable via `orchestration.health_check.timeout` (default: 5 seconds).
852
861
 
853
862
  ## Development
854
863
 
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "securerandom"
4
+ require "time"
4
5
  require "ruby_llm"
5
6
  require_relative "attempt_report"
6
7
  require_relative "provider_error_detail"
@@ -499,7 +500,12 @@ module AgentHarness
499
500
  headers = error.response.respond_to?(:headers) ? error.response.headers : error.response[:response_headers]
500
501
  value = headers&.find { |key, _| key.to_s.casecmp?("retry-after") }&.last
501
502
  delay = Float(value, exception: false)
502
- delay if delay&.finite? && delay >= 0
503
+ return delay if delay&.finite? && delay >= 0
504
+
505
+ delay = Time.httpdate(value.to_s) - Time.now
506
+ [delay, 0].max
507
+ rescue ArgumentError, TypeError
508
+ nil
503
509
  end
504
510
  private_class_method :retry_after_seconds
505
511
 
@@ -281,7 +281,12 @@ module AgentHarness
281
281
  # when only the host cannot reach the endpoint.
282
282
  if provider_preflight_allowed
283
283
  preflight_env = build_preflight_env(provider_instance, provider_runtime)
284
- preflight = provider_instance.preflight_check(env: preflight_env, timeout: timeout)
284
+ preflight = run_provider_preflight(
285
+ provider_instance,
286
+ env: preflight_env,
287
+ timeout: timeout,
288
+ provider_runtime: provider_runtime
289
+ )
285
290
  unless preflight[:healthy]
286
291
  return build_result(
287
292
  name: provider_name,
@@ -289,7 +294,8 @@ module AgentHarness
289
294
  message: preflight[:reason] || "Preflight check failed",
290
295
  start_time: start_time,
291
296
  error_category: normalize_preflight_error_category(preflight[:error_category]),
292
- check: :preflight
297
+ check: :preflight,
298
+ reset_at: preflight[:reset_at]
293
299
  )
294
300
  end
295
301
  end
@@ -485,6 +491,16 @@ module AgentHarness
485
491
  effective_executor.is_a?(CommandExecutor) && !effective_executor.is_a?(DockerCommandExecutor)
486
492
  end
487
493
 
494
+ def run_provider_preflight(provider, env:, timeout:, provider_runtime:)
495
+ parameters = provider.method(:preflight_check).parameters
496
+ accepts_runtime = parameters.any? do |type, name|
497
+ type == :keyrest || (%i[key keyreq].include?(type) && name == :provider_runtime)
498
+ end
499
+ options = {env: env, timeout: timeout}
500
+ options[:provider_runtime] = provider_runtime if accepts_runtime
501
+ provider.preflight_check(**options)
502
+ end
503
+
488
504
  def runtime_sensitive_host_overrides?(runtime)
489
505
  runtime && (!runtime.env.empty? || !runtime.unset_env.empty? || runtime.base_url || runtime.api_provider)
490
506
  end
@@ -12,7 +12,7 @@ module AgentHarness
12
12
  # CLI.
13
13
  class OhMyPi < Base
14
14
  CLI_PACKAGE = "@oh-my-pi/pi-coding-agent"
15
- SUPPORTED_CLI_VERSION = "18.11.2"
15
+ SUPPORTED_CLI_VERSION = "18.12.6"
16
16
  SUPPORTED_CLI_REQUIREMENT = Gem::Requirement.new("= #{SUPPORTED_CLI_VERSION}").freeze
17
17
 
18
18
  # Bun runtime requirements. The omp entrypoint is
@@ -165,6 +165,11 @@ module AgentHarness
165
165
  .freeze
166
166
  }.freeze
167
167
 
168
+ def initialize(preflight_transport: Api::ChatTransport.new, **options)
169
+ super(**options)
170
+ @preflight_transport = preflight_transport
171
+ end
172
+
168
173
  def name
169
174
  "opencode"
170
175
  end
@@ -243,6 +248,21 @@ module AgentHarness
243
248
  }
244
249
  end
245
250
 
251
+ # OpenCode can silently retry MiniMax subscription limits until the CLI
252
+ # smoke timeout. Probe the same direct upstream once so callers receive a
253
+ # structured provider state without parsing CLI output.
254
+ def preflight_check(env:, timeout: 10, provider_runtime: nil)
255
+ runtime = ProviderRuntime.wrap(provider_runtime)
256
+ return {healthy: true} unless minimax_preflight?(runtime)
257
+
258
+ result = @preflight_transport.call(minimax_preflight_request(runtime, env, timeout))
259
+ return {healthy: true} if result[:status] == :succeeded
260
+
261
+ minimax_preflight_failure(result[:error])
262
+ rescue ArgumentError => e
263
+ {healthy: false, reason: e.message, error_category: :configuration}
264
+ end
265
+
246
266
  protected
247
267
 
248
268
  def build_command(prompt, options)
@@ -290,6 +310,58 @@ module AgentHarness
290
310
 
291
311
  private
292
312
 
313
+ def minimax_preflight?(runtime)
314
+ runtime && runtime.api_provider.to_s.casecmp?("minimax")
315
+ end
316
+
317
+ def minimax_preflight_request(runtime, env, timeout)
318
+ {
319
+ request_id: "opencode-minimax-preflight",
320
+ operation: :chat,
321
+ candidates: [minimax_candidate(runtime, env)],
322
+ messages: [{role: :user, content: [{type: :text, text: "Reply with exactly OK."}]}],
323
+ tools: [],
324
+ max_output_tokens: 8,
325
+ timeout: {read_seconds: timeout},
326
+ retry: {max_attempts: 1}
327
+ }
328
+ end
329
+
330
+ def minimax_candidate(runtime, env)
331
+ endpoint = runtime.chat_base_url || runtime.base_url
332
+ model = runtime.chat_model || runtime.model
333
+ api_key = runtime.chat_api_key || env["MINIMAX_API_KEY"] || env["ANTHROPIC_API_KEY"]
334
+ raise ArgumentError, "MiniMax preflight requires an API endpoint" if endpoint.to_s.empty?
335
+ raise ArgumentError, "MiniMax preflight requires a model" if model.to_s.empty?
336
+ raise ArgumentError, "MiniMax preflight requires an API credential" if api_key.to_s.empty?
337
+
338
+ {
339
+ provider: :anthropic, protocol: :messages, authentication_mode: :api_key,
340
+ model: model, endpoint: endpoint, credentials: {api_key: api_key}
341
+ }
342
+ end
343
+
344
+ def minimax_preflight_failure(error)
345
+ return minimax_rate_limit_failure(error) if error&.dig(:code)&.to_sym == :rate_limited
346
+
347
+ {
348
+ healthy: false,
349
+ reason: "MiniMax preflight request failed",
350
+ error_category: error&.dig(:category) || :transient
351
+ }
352
+ end
353
+
354
+ def minimax_rate_limit_failure(error)
355
+ result = {
356
+ healthy: false,
357
+ reason: "MiniMax Token Plan rate limit reached",
358
+ error_category: :rate_limited
359
+ }
360
+ retry_after = error[:retry_after_seconds]
361
+ result[:reset_at] = Time.now.utc + retry_after if retry_after
362
+ result
363
+ end
364
+
293
365
  def opencode_config_payload(runtime)
294
366
  metadata = runtime.metadata
295
367
  config_extras = metadata[:config] || metadata["config"] || {}
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AgentHarness
4
- VERSION = "0.44.26"
4
+ VERSION = "0.44.28"
5
5
  end
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.44.26
4
+ version: 0.44.28
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bart Agapinan