agent-harness 0.44.21 → 0.44.22

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: 79e4e172d70ecba9f4f3249a6d1ee93af4f47ba444991beea77f1a0d152cc0af
4
- data.tar.gz: '0489867bae0853510e78ff6251aab2980048be0de24f10fdba9c8ef2b816f90f'
3
+ metadata.gz: bd3556ae8d2b4d460344b7479ad613d978baec38b54a7261bc4024314b2a5fd6
4
+ data.tar.gz: e5db97cdc1f923b2791d80bd3ca7b3dcf1060adc30a0c979f96da94e93740f63
5
5
  SHA512:
6
- metadata.gz: 6657b638390c5f3ae19c5100d33e78b8ed8b26292d90bfad5e649479c5e7e4b0619a6c20118c9a68d9fa1f216379d4c2d25f62cea82a4c82b61d858d09ddc309
7
- data.tar.gz: c52577902c4a2852afcceda0f76da39e1f829a4a191051cd5978934955c577830b6ac4281d95d6b563bf3f8c2bf62732b9efe70a1636797b6af014b43b5596d6
6
+ metadata.gz: 38cba9849f8f085fe92b6c9bb5a7de4df67d4c3591a6d6a48459d391aaf4dc79ccbd8dbc684d667e103df3b2e3661dc82da8e4d88df9327ccf231741c1058525
7
+ data.tar.gz: 2567485b7f2c3f181d61d9124d43c6e6dd13bdf3ac6158687e6b5ebd0f75a8506a9e0b5dc0157ccc4fa4ff9a06ee52483b0f7571c4442de8fc3bdc59cdaef712
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "0.44.21"
2
+ ".": "0.44.22"
3
3
  }
data/CHANGELOG.md CHANGED
@@ -12,6 +12,13 @@
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.22](https://github.com/viamin/agent-harness/compare/agent-harness/v0.44.21...agent-harness/v0.44.22) (2026-10-21)
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * Preserve safe actionable provider error details in API chat failures ([#502](https://github.com/viamin/agent-harness/issues/502)) ([509a877](https://github.com/viamin/agent-harness/commit/509a8773e330cdc4bccb53edfe51bafef6b8e20f))
21
+
15
22
  ## [0.44.21](https://github.com/viamin/agent-harness/compare/agent-harness/v0.44.20...agent-harness/v0.44.21) (2026-10-21)
16
23
 
17
24
 
@@ -490,7 +490,13 @@ result/usage where available. Categories are:
490
490
 
491
491
  Adapters MUST use the following category and code mappings. A provider-specific
492
492
  status or error name may be retained as sanitized metadata, but MUST NOT replace
493
- these values or change fallback eligibility.
493
+ these values or change fallback eligibility. The normalized `message` may append
494
+ bounded, actionable detail for request, capability, configuration, and
495
+ response-shape failures. Such detail MUST redact credentials, headers, request
496
+ bodies, conversation content, and URLs, and MUST never copy an unparsed provider
497
+ response body or a message derived from one. Parser diagnostics are also omitted
498
+ because they can quote request or conversation content. Attempt reports retain
499
+ the same sanitized error object as the public result.
494
500
 
495
501
  | Failure | Category | Code |
496
502
  | --- | --- | --- |
@@ -3,6 +3,7 @@
3
3
  require "securerandom"
4
4
  require "ruby_llm"
5
5
  require_relative "attempt_report"
6
+ require_relative "provider_error_detail"
6
7
  require_relative "ruby_llm_chat_adapter"
7
8
  require_relative "schema_response"
8
9
 
@@ -443,6 +444,11 @@ module AgentHarness
443
444
  end
444
445
 
445
446
  module ErrorClassifier
447
+ ACTIONABLE_DETAIL_ERRORS = [
448
+ RubyLLM::BadRequestError,
449
+ RubyLlmChatAdapter::UnsupportedOptionError
450
+ ].freeze
451
+
446
452
  TRANSIENT = {
447
453
  Faraday::TimeoutError => :timeout,
448
454
  Faraday::ConnectionFailed => :connection_failed,
@@ -480,7 +486,7 @@ module AgentHarness
480
486
  end
481
487
 
482
488
  def self.payload(error, category, code, retryable)
483
- payload = {category: category, code: code, retryable: retryable, message: safe_message(category, code)}
489
+ payload = {category: category, code: code, retryable: retryable, message: safe_message(error, category, code)}
484
490
  retry_after = retry_after_seconds(error)
485
491
  payload[:retry_after_seconds] = retry_after if retry_after
486
492
  payload
@@ -497,8 +503,12 @@ module AgentHarness
497
503
  end
498
504
  private_class_method :retry_after_seconds
499
505
 
500
- def self.safe_message(category, code)
501
- "Chat request failed (#{category}/#{code})"
506
+ def self.safe_message(error, category, code)
507
+ summary = "Chat request failed (#{category}/#{code})"
508
+ return summary unless ACTIONABLE_DETAIL_ERRORS.any? { |klass| error.is_a?(klass) }
509
+
510
+ detail = ProviderErrorDetail.call(error)
511
+ detail.to_s.empty? ? summary : "#{summary}: #{detail}"
502
512
  end
503
513
  private_class_method :safe_message
504
514
  end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AgentHarness
4
+ module Api
5
+ # Extracts allowlisted, actionable text from provider errors without
6
+ # retaining response bodies or caller-controlled message content.
7
+ module ProviderErrorDetail
8
+ LOCAL_DETAILS = [
9
+ "RubyLLM does not support request-local connect timeouts",
10
+ "provider state does not match the selected protocol",
11
+ "provider state must carry at least one Responses output item",
12
+ "unsupported content type"
13
+ ].freeze
14
+ TOOL_REASONING_DETAIL = "Function tools with reasoning_effort are not supported for gpt-5.6-luna " \
15
+ "in /v1/chat/completions. To use function tools, use /v1/responses or set reasoning_effort to 'none'."
16
+
17
+ module_function
18
+
19
+ def call(error)
20
+ message = normalized(error.message)
21
+ return if message.empty? || structured_body?(message) || !safe_source?(error, message)
22
+
23
+ message
24
+ end
25
+
26
+ def normalized(value)
27
+ value.to_s.encode("UTF-8", invalid: :replace, undef: :replace, replace: "�")
28
+ .gsub(/[[:cntrl:]]+/, " ").gsub(/\s+/, " ").strip
29
+ end
30
+ private_class_method :normalized
31
+
32
+ def safe_source?(error, message)
33
+ safe_local_detail?(error, message) || safe_provider_detail?(error, message)
34
+ end
35
+ private_class_method :safe_source?
36
+
37
+ def safe_local_detail?(error, message)
38
+ error.is_a?(RubyLlmChatAdapter::UnsupportedOptionError) && LOCAL_DETAILS.include?(message)
39
+ end
40
+ private_class_method :safe_local_detail?
41
+
42
+ # RubyLLM parses this provider diagnostic from a JSON error field before
43
+ # constructing BadRequestError. Checking both the structured body and its
44
+ # fixed, non-content-bearing shape avoids exposing raw bodies or arbitrary
45
+ # provider prose that may echo request or conversation content.
46
+ def safe_provider_detail?(error, message)
47
+ error.is_a?(RubyLLM::BadRequestError) && message == TOOL_REASONING_DETAIL &&
48
+ structured_messages(error.response).include?(message)
49
+ end
50
+ private_class_method :safe_provider_detail?
51
+
52
+ def structured_messages(response)
53
+ body = response&.body
54
+ parsed = body.is_a?(String) ? JSON.parse(body) : body
55
+ return [] unless parsed.is_a?(Hash)
56
+
57
+ error = parsed["error"] || parsed[:error]
58
+ [error, parsed].filter_map { |part| part["message"] || part[:message] if part.is_a?(Hash) }
59
+ rescue JSON::ParserError
60
+ []
61
+ end
62
+ private_class_method :structured_messages
63
+
64
+ def structured_body?(message)
65
+ message.start_with?("{", "[", "<")
66
+ end
67
+ private_class_method :structured_body?
68
+ end
69
+ end
70
+ end
@@ -303,7 +303,7 @@ module AgentHarness
303
303
 
304
304
  Array(content).map do |part|
305
305
  unless part[:type]&.to_sym == :text
306
- raise UnsupportedOptionError, "unsupported content type: #{part[:type]}"
306
+ raise UnsupportedOptionError, "unsupported content type"
307
307
  end
308
308
 
309
309
  part[:text].to_s
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AgentHarness
4
- VERSION = "0.44.21"
4
+ VERSION = "0.44.22"
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.21
4
+ version: 0.44.22
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bart Agapinan
@@ -145,6 +145,7 @@ files:
145
145
  - lib/agent_harness.rb
146
146
  - lib/agent_harness/api/attempt_report.rb
147
147
  - lib/agent_harness/api/chat_transport.rb
148
+ - lib/agent_harness/api/provider_error_detail.rb
148
149
  - lib/agent_harness/api/ruby_llm_chat_adapter.rb
149
150
  - lib/agent_harness/api/schema_response.rb
150
151
  - lib/agent_harness/authentication.rb