anthropic 1.48.2 → 1.49.0
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/CHANGELOG.md +14 -0
- data/README.md +1 -1
- data/lib/anthropic/client.rb +8 -2
- data/lib/anthropic/errors.rb +14 -0
- data/lib/anthropic/helpers/aws/client.rb +3 -3
- data/lib/anthropic/helpers/aws_auth.rb +39 -29
- data/lib/anthropic/helpers/bedrock/client.rb +99 -67
- data/lib/anthropic/helpers/bedrock/event_stream.rb +92 -0
- data/lib/anthropic/helpers/bedrock/mantle_client.rb +3 -3
- data/lib/anthropic/helpers/vertex/client.rb +99 -55
- data/lib/anthropic/internal/transport/base_client.rb +196 -33
- data/lib/anthropic/internal/util.rb +37 -1
- data/lib/anthropic/middleware.rb +435 -0
- data/lib/anthropic/models/beta/beta_advisor_tool_20260301.rb +3 -1
- data/lib/anthropic/models/beta/beta_code_execution_tool_20250522.rb +3 -1
- data/lib/anthropic/models/beta/beta_code_execution_tool_20250825.rb +3 -1
- data/lib/anthropic/models/beta/beta_code_execution_tool_20260120.rb +3 -1
- data/lib/anthropic/models/beta/beta_code_execution_tool_20260521.rb +86 -0
- data/lib/anthropic/models/beta/beta_content_block.rb +3 -3
- data/lib/anthropic/models/beta/beta_content_block_param.rb +10 -12
- data/lib/anthropic/models/beta/beta_fallback_block.rb +13 -5
- data/lib/anthropic/models/beta/beta_fallback_block_param.rb +22 -13
- data/lib/anthropic/models/beta/beta_fallback_refusal_trigger.rb +44 -0
- data/lib/anthropic/models/beta/beta_memory_tool_20250818.rb +3 -1
- data/lib/anthropic/models/beta/beta_raw_content_block_start_event.rb +3 -3
- data/lib/anthropic/models/beta/beta_refusal_stop_details.rb +3 -7
- data/lib/anthropic/models/beta/beta_tool.rb +3 -1
- data/lib/anthropic/models/beta/beta_tool_bash_20241022.rb +3 -1
- data/lib/anthropic/models/beta/beta_tool_bash_20250124.rb +3 -1
- data/lib/anthropic/models/beta/beta_tool_computer_use_20241022.rb +3 -1
- data/lib/anthropic/models/beta/beta_tool_computer_use_20250124.rb +3 -1
- data/lib/anthropic/models/beta/beta_tool_computer_use_20251124.rb +3 -1
- data/lib/anthropic/models/beta/beta_tool_search_tool_bm25_20251119.rb +3 -1
- data/lib/anthropic/models/beta/beta_tool_search_tool_regex_20251119.rb +3 -1
- data/lib/anthropic/models/beta/beta_tool_text_editor_20241022.rb +3 -1
- data/lib/anthropic/models/beta/beta_tool_text_editor_20250124.rb +3 -1
- data/lib/anthropic/models/beta/beta_tool_text_editor_20250429.rb +3 -1
- data/lib/anthropic/models/beta/beta_tool_text_editor_20250728.rb +3 -1
- data/lib/anthropic/models/beta/beta_tool_union.rb +4 -1
- data/lib/anthropic/models/beta/beta_web_fetch_tool_20250910.rb +3 -1
- data/lib/anthropic/models/beta/beta_web_fetch_tool_20260209.rb +3 -1
- data/lib/anthropic/models/beta/beta_web_fetch_tool_20260309.rb +3 -1
- data/lib/anthropic/models/beta/beta_web_search_tool_20250305.rb +3 -1
- data/lib/anthropic/models/beta/beta_web_search_tool_20260209.rb +3 -1
- data/lib/anthropic/models/beta/beta_webhook_event.rb +2 -2
- data/lib/anthropic/models/beta/beta_webhook_event_data.rb +3 -1
- data/lib/anthropic/models/beta/beta_webhook_session_updated_event_data.rb +41 -0
- data/lib/anthropic/models/beta/message_count_tokens_params.rb +6 -3
- data/lib/anthropic/models/beta/message_create_params.rb +2 -2
- data/lib/anthropic/models/beta/messages/batch_create_params.rb +2 -2
- data/lib/anthropic/models/beta/unwrap_webhook_event.rb +2 -2
- data/lib/anthropic/models/code_execution_tool_20250522.rb +3 -1
- data/lib/anthropic/models/code_execution_tool_20250825.rb +3 -1
- data/lib/anthropic/models/code_execution_tool_20260120.rb +3 -1
- data/lib/anthropic/models/code_execution_tool_20260521.rb +82 -0
- data/lib/anthropic/models/memory_tool_20250818.rb +3 -1
- data/lib/anthropic/models/message_count_tokens_params.rb +2 -2
- data/lib/anthropic/models/message_count_tokens_tool.rb +4 -1
- data/lib/anthropic/models/message_create_params.rb +2 -2
- data/lib/anthropic/models/messages/batch_create_params.rb +2 -2
- data/lib/anthropic/models/refusal_stop_details.rb +3 -7
- data/lib/anthropic/models/tool.rb +3 -1
- data/lib/anthropic/models/tool_bash_20250124.rb +3 -1
- data/lib/anthropic/models/tool_search_tool_bm25_20251119.rb +3 -1
- data/lib/anthropic/models/tool_search_tool_regex_20251119.rb +3 -1
- data/lib/anthropic/models/tool_text_editor_20250124.rb +3 -1
- data/lib/anthropic/models/tool_text_editor_20250429.rb +3 -1
- data/lib/anthropic/models/tool_text_editor_20250728.rb +3 -1
- data/lib/anthropic/models/tool_union.rb +4 -1
- data/lib/anthropic/models/web_fetch_tool_20250910.rb +3 -1
- data/lib/anthropic/models/web_fetch_tool_20260209.rb +3 -1
- data/lib/anthropic/models/web_fetch_tool_20260309.rb +3 -1
- data/lib/anthropic/models/web_search_tool_20250305.rb +3 -1
- data/lib/anthropic/models/web_search_tool_20260209.rb +3 -1
- data/lib/anthropic/models.rb +2 -0
- data/lib/anthropic/request_options.rb +9 -0
- data/lib/anthropic/resources/beta/messages.rb +3 -3
- data/lib/anthropic/resources/messages.rb +3 -3
- data/lib/anthropic/version.rb +1 -1
- data/lib/anthropic.rb +6 -0
- data/rbi/anthropic/client.rbi +7 -2
- data/rbi/anthropic/errors.rbi +5 -0
- data/rbi/anthropic/helpers/aws/client.rbi +3 -6
- data/rbi/anthropic/helpers/bedrock/client.rbi +24 -13
- data/rbi/anthropic/helpers/bedrock/event_stream.rbi +25 -0
- data/rbi/anthropic/helpers/bedrock/mantle_client.rbi +3 -6
- data/rbi/anthropic/helpers/vertex/client.rbi +28 -8
- data/rbi/anthropic/internal/transport/base_client.rbi +39 -4
- data/rbi/anthropic/internal/util.rbi +5 -0
- data/rbi/anthropic/middleware.rbi +338 -0
- data/rbi/anthropic/models/beta/beta_advisor_tool_20260301.rbi +7 -1
- data/rbi/anthropic/models/beta/beta_code_execution_tool_20250522.rbi +7 -1
- data/rbi/anthropic/models/beta/beta_code_execution_tool_20250825.rbi +7 -1
- data/rbi/anthropic/models/beta/beta_code_execution_tool_20260120.rbi +7 -1
- data/rbi/anthropic/models/beta/beta_code_execution_tool_20260521.rbi +178 -0
- data/rbi/anthropic/models/beta/beta_fallback_block.rbi +19 -4
- data/rbi/anthropic/models/beta/beta_fallback_block_param.rbi +23 -13
- data/rbi/anthropic/models/beta/beta_fallback_refusal_trigger.rbi +108 -0
- data/rbi/anthropic/models/beta/beta_memory_tool_20250818.rbi +7 -1
- data/rbi/anthropic/models/beta/beta_refusal_stop_details.rbi +3 -9
- data/rbi/anthropic/models/beta/beta_tool.rbi +7 -1
- data/rbi/anthropic/models/beta/beta_tool_bash_20241022.rbi +7 -1
- data/rbi/anthropic/models/beta/beta_tool_bash_20250124.rbi +7 -1
- data/rbi/anthropic/models/beta/beta_tool_computer_use_20241022.rbi +7 -1
- data/rbi/anthropic/models/beta/beta_tool_computer_use_20250124.rbi +7 -1
- data/rbi/anthropic/models/beta/beta_tool_computer_use_20251124.rbi +7 -1
- data/rbi/anthropic/models/beta/beta_tool_search_tool_bm25_20251119.rbi +7 -1
- data/rbi/anthropic/models/beta/beta_tool_search_tool_regex_20251119.rbi +7 -1
- data/rbi/anthropic/models/beta/beta_tool_text_editor_20241022.rbi +7 -1
- data/rbi/anthropic/models/beta/beta_tool_text_editor_20250124.rbi +7 -1
- data/rbi/anthropic/models/beta/beta_tool_text_editor_20250429.rbi +7 -1
- data/rbi/anthropic/models/beta/beta_tool_text_editor_20250728.rbi +7 -1
- data/rbi/anthropic/models/beta/beta_tool_union.rbi +1 -0
- data/rbi/anthropic/models/beta/beta_web_fetch_tool_20250910.rbi +7 -1
- data/rbi/anthropic/models/beta/beta_web_fetch_tool_20260209.rbi +7 -1
- data/rbi/anthropic/models/beta/beta_web_fetch_tool_20260309.rbi +7 -1
- data/rbi/anthropic/models/beta/beta_web_search_tool_20250305.rbi +7 -1
- data/rbi/anthropic/models/beta/beta_web_search_tool_20260209.rbi +7 -1
- data/rbi/anthropic/models/beta/beta_webhook_event.rbi +6 -3
- data/rbi/anthropic/models/beta/beta_webhook_event_data.rbi +2 -1
- data/rbi/anthropic/models/beta/beta_webhook_session_updated_event_data.rbi +63 -0
- data/rbi/anthropic/models/beta/message_count_tokens_params.rbi +5 -0
- data/rbi/anthropic/models/beta/message_create_params.rbi +4 -0
- data/rbi/anthropic/models/beta/messages/batch_create_params.rbi +4 -0
- data/rbi/anthropic/models/beta/unwrap_webhook_event.rbi +2 -1
- data/rbi/anthropic/models/code_execution_tool_20250522.rbi +7 -1
- data/rbi/anthropic/models/code_execution_tool_20250825.rbi +7 -1
- data/rbi/anthropic/models/code_execution_tool_20260120.rbi +7 -1
- data/rbi/anthropic/models/code_execution_tool_20260521.rbi +168 -0
- data/rbi/anthropic/models/memory_tool_20250818.rbi +7 -1
- data/rbi/anthropic/models/message_count_tokens_params.rbi +4 -0
- data/rbi/anthropic/models/message_count_tokens_tool.rbi +1 -0
- data/rbi/anthropic/models/message_create_params.rbi +4 -0
- data/rbi/anthropic/models/messages/batch_create_params.rbi +4 -0
- data/rbi/anthropic/models/refusal_stop_details.rbi +3 -9
- data/rbi/anthropic/models/tool.rbi +7 -1
- data/rbi/anthropic/models/tool_bash_20250124.rbi +7 -1
- data/rbi/anthropic/models/tool_search_tool_bm25_20251119.rbi +7 -1
- data/rbi/anthropic/models/tool_search_tool_regex_20251119.rbi +7 -1
- data/rbi/anthropic/models/tool_text_editor_20250124.rbi +7 -1
- data/rbi/anthropic/models/tool_text_editor_20250429.rbi +7 -1
- data/rbi/anthropic/models/tool_text_editor_20250728.rbi +7 -1
- data/rbi/anthropic/models/tool_union.rbi +1 -0
- data/rbi/anthropic/models/web_fetch_tool_20250910.rbi +7 -1
- data/rbi/anthropic/models/web_fetch_tool_20260209.rbi +7 -1
- data/rbi/anthropic/models/web_fetch_tool_20260309.rbi +7 -1
- data/rbi/anthropic/models/web_search_tool_20250305.rbi +7 -1
- data/rbi/anthropic/models/web_search_tool_20260209.rbi +7 -1
- data/rbi/anthropic/models.rbi +2 -0
- data/rbi/anthropic/request_options.rbi +5 -0
- data/rbi/anthropic/resources/beta/messages.rbi +3 -0
- data/rbi/anthropic/resources/messages.rbi +3 -0
- data/sig/anthropic/client.rbs +2 -1
- data/sig/anthropic/errors.rbs +3 -0
- data/sig/anthropic/helpers/bedrock/client.rbs +12 -4
- data/sig/anthropic/helpers/vertex/client.rbs +17 -4
- data/sig/anthropic/internal/transport/base_client.rbs +18 -3
- data/sig/anthropic/internal/util.rbs +2 -0
- data/sig/anthropic/middleware.rbs +117 -0
- data/sig/anthropic/models/beta/beta_advisor_tool_20260301.rbs +5 -1
- data/sig/anthropic/models/beta/beta_code_execution_tool_20250522.rbs +5 -1
- data/sig/anthropic/models/beta/beta_code_execution_tool_20250825.rbs +5 -1
- data/sig/anthropic/models/beta/beta_code_execution_tool_20260120.rbs +5 -1
- data/sig/anthropic/models/beta/beta_code_execution_tool_20260521.rbs +74 -0
- data/sig/anthropic/models/beta/beta_fallback_block.rbs +5 -0
- data/sig/anthropic/models/beta/beta_fallback_block_param.rbs +9 -2
- data/sig/anthropic/models/beta/beta_fallback_refusal_trigger.rbs +42 -0
- data/sig/anthropic/models/beta/beta_memory_tool_20250818.rbs +5 -1
- data/sig/anthropic/models/beta/beta_tool.rbs +5 -1
- data/sig/anthropic/models/beta/beta_tool_bash_20241022.rbs +5 -1
- data/sig/anthropic/models/beta/beta_tool_bash_20250124.rbs +5 -1
- data/sig/anthropic/models/beta/beta_tool_computer_use_20241022.rbs +5 -1
- data/sig/anthropic/models/beta/beta_tool_computer_use_20250124.rbs +5 -1
- data/sig/anthropic/models/beta/beta_tool_computer_use_20251124.rbs +5 -1
- data/sig/anthropic/models/beta/beta_tool_search_tool_bm25_20251119.rbs +5 -1
- data/sig/anthropic/models/beta/beta_tool_search_tool_regex_20251119.rbs +5 -1
- data/sig/anthropic/models/beta/beta_tool_text_editor_20241022.rbs +5 -1
- data/sig/anthropic/models/beta/beta_tool_text_editor_20250124.rbs +5 -1
- data/sig/anthropic/models/beta/beta_tool_text_editor_20250429.rbs +5 -1
- data/sig/anthropic/models/beta/beta_tool_text_editor_20250728.rbs +5 -1
- data/sig/anthropic/models/beta/beta_tool_union.rbs +1 -0
- data/sig/anthropic/models/beta/beta_web_fetch_tool_20250910.rbs +5 -1
- data/sig/anthropic/models/beta/beta_web_fetch_tool_20260209.rbs +5 -1
- data/sig/anthropic/models/beta/beta_web_fetch_tool_20260309.rbs +5 -1
- data/sig/anthropic/models/beta/beta_web_search_tool_20250305.rbs +5 -1
- data/sig/anthropic/models/beta/beta_web_search_tool_20260209.rbs +5 -1
- data/sig/anthropic/models/beta/beta_webhook_event_data.rbs +1 -0
- data/sig/anthropic/models/beta/beta_webhook_session_updated_event_data.rbs +39 -0
- data/sig/anthropic/models/beta/message_count_tokens_params.rbs +1 -0
- data/sig/anthropic/models/code_execution_tool_20250522.rbs +5 -1
- data/sig/anthropic/models/code_execution_tool_20250825.rbs +5 -1
- data/sig/anthropic/models/code_execution_tool_20260120.rbs +5 -1
- data/sig/anthropic/models/code_execution_tool_20260521.rbs +70 -0
- data/sig/anthropic/models/memory_tool_20250818.rbs +5 -1
- data/sig/anthropic/models/message_count_tokens_tool.rbs +1 -0
- data/sig/anthropic/models/tool.rbs +5 -1
- data/sig/anthropic/models/tool_bash_20250124.rbs +5 -1
- data/sig/anthropic/models/tool_search_tool_bm25_20251119.rbs +5 -1
- data/sig/anthropic/models/tool_search_tool_regex_20251119.rbs +5 -1
- data/sig/anthropic/models/tool_text_editor_20250124.rbs +5 -1
- data/sig/anthropic/models/tool_text_editor_20250429.rbs +5 -1
- data/sig/anthropic/models/tool_text_editor_20250728.rbs +5 -1
- data/sig/anthropic/models/tool_union.rbs +1 -0
- data/sig/anthropic/models/web_fetch_tool_20250910.rbs +5 -1
- data/sig/anthropic/models/web_fetch_tool_20260209.rbs +5 -1
- data/sig/anthropic/models/web_fetch_tool_20260309.rbs +5 -1
- data/sig/anthropic/models/web_search_tool_20250305.rbs +5 -1
- data/sig/anthropic/models/web_search_tool_20260209.rbs +5 -1
- data/sig/anthropic/models.rbs +2 -0
- data/sig/anthropic/request_options.rbs +4 -1
- metadata +19 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 45df9830dd4224180e2702068ad79b01ad5f045a6499969bbddfc5a49f29cec9
|
|
4
|
+
data.tar.gz: f501463bdb25da9354140ada09b8c638064fcf1c57ae751e9156c526b5281acb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d4521d3d6191009cd99cd92898d6cfdca44ae99908d06ddaafee22665f21ba4751c6c02c5fb705ddea04827251769b69c53e62734e9edb04f60f9aa7dffe6802
|
|
7
|
+
data.tar.gz: 7d917f565b12839a5755d0e9638d2d57a05a489bd022d3284f2ba4bd812d488f5b2b635e38f8a3ad12fb24f8c305a7dcb16aed77d9c7ca17f66386183e607c39
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.49.0 (2026-06-18)
|
|
4
|
+
|
|
5
|
+
Full Changelog: [v1.48.2...v1.49.0](https://github.com/anthropics/anthropic-sdk-ruby/compare/v1.48.2...v1.49.0)
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
|
|
9
|
+
* **api:** add support for new code_execution_20260120 tool ([9e4d388](https://github.com/anthropics/anthropic-sdk-ruby/commit/9e4d388649bb020e66ebac13ae4ad90450a3f293))
|
|
10
|
+
* **client:** add HTTP middleware ([#30](https://github.com/anthropics/anthropic-sdk-ruby/issues/30)) ([e6c7245](https://github.com/anthropics/anthropic-sdk-ruby/commit/e6c7245b1539a08d7ec5ad103f0ee291c2bbcb52))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* **bedrock:** decode AWS event-stream framing on streaming responses ([2f8d31c](https://github.com/anthropics/anthropic-sdk-ruby/commit/2f8d31cff8ea7119b6271e926c83733bf8297106))
|
|
16
|
+
|
|
3
17
|
## 1.48.2 (2026-06-15)
|
|
4
18
|
|
|
5
19
|
Full Changelog: [v1.48.1...v1.48.2](https://github.com/anthropics/anthropic-sdk-ruby/compare/v1.48.1...v1.48.2)
|
data/README.md
CHANGED
data/lib/anthropic/client.rb
CHANGED
|
@@ -175,6 +175,10 @@ module Anthropic
|
|
|
175
175
|
# @param initial_retry_delay [Float]
|
|
176
176
|
#
|
|
177
177
|
# @param max_retry_delay [Float]
|
|
178
|
+
#
|
|
179
|
+
# @param middleware [Array<#call>, #call, nil] Per-attempt HTTP around-middleware. Each
|
|
180
|
+
# entry is a `#call(req, nxt) -> Anthropic::APIResponse` callable. See
|
|
181
|
+
# {Anthropic::Middleware}.
|
|
178
182
|
def initialize(
|
|
179
183
|
api_key: nil,
|
|
180
184
|
auth_token: nil,
|
|
@@ -185,7 +189,8 @@ module Anthropic
|
|
|
185
189
|
max_retries: self.class::DEFAULT_MAX_RETRIES,
|
|
186
190
|
timeout: self.class::DEFAULT_TIMEOUT_IN_SECONDS,
|
|
187
191
|
initial_retry_delay: self.class::DEFAULT_INITIAL_RETRY_DELAY,
|
|
188
|
-
max_retry_delay: self.class::DEFAULT_MAX_RETRY_DELAY
|
|
192
|
+
max_retry_delay: self.class::DEFAULT_MAX_RETRY_DELAY,
|
|
193
|
+
middleware: nil
|
|
189
194
|
)
|
|
190
195
|
if config && credentials
|
|
191
196
|
raise ArgumentError, "Pass at most one of `credentials:` or `config:`."
|
|
@@ -265,7 +270,8 @@ module Anthropic
|
|
|
265
270
|
max_retries: max_retries,
|
|
266
271
|
initial_retry_delay: initial_retry_delay,
|
|
267
272
|
max_retry_delay: max_retry_delay,
|
|
268
|
-
headers: headers
|
|
273
|
+
headers: headers,
|
|
274
|
+
middleware: middleware
|
|
269
275
|
)
|
|
270
276
|
|
|
271
277
|
@completions = Anthropic::Resources::Completions.new(client: self)
|
data/lib/anthropic/errors.rb
CHANGED
|
@@ -8,6 +8,20 @@ module Anthropic
|
|
|
8
8
|
# @return [StandardError, nil]
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
+
# Raise from a middleware to explicitly opt a middleware-origin failure
|
|
12
|
+
# into the SDK's retry loop. Retry classification walks `Exception#cause`,
|
|
13
|
+
# so a middleware may wrap with its own error class and still have the SDK
|
|
14
|
+
# retry as long as `RetryableError` is reachable via the cause chain.
|
|
15
|
+
#
|
|
16
|
+
# @example
|
|
17
|
+
# begin
|
|
18
|
+
# backend.call
|
|
19
|
+
# rescue BackendUnavailable => e
|
|
20
|
+
# raise Anthropic::Errors::RetryableError, cause: e
|
|
21
|
+
# end
|
|
22
|
+
class RetryableError < Anthropic::Errors::Error
|
|
23
|
+
end
|
|
24
|
+
|
|
11
25
|
class ConversionError < Anthropic::Errors::Error
|
|
12
26
|
# @return [StandardError, nil]
|
|
13
27
|
def cause = @cause.nil? ? super : @cause
|
|
@@ -108,9 +108,9 @@ module Anthropic
|
|
|
108
108
|
end
|
|
109
109
|
|
|
110
110
|
# @api private
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
111
|
+
#
|
|
112
|
+
# @return [#call]
|
|
113
|
+
private def provider_middleware = method(:aws_auth_provider)
|
|
114
114
|
end
|
|
115
115
|
end
|
|
116
116
|
end
|
|
@@ -147,42 +147,52 @@ module Anthropic
|
|
|
147
147
|
super
|
|
148
148
|
end
|
|
149
149
|
|
|
150
|
-
#
|
|
151
|
-
#
|
|
150
|
+
# The AWS provider middleware entry: applies the workspace-id header and
|
|
151
|
+
# SigV4 signing per attempt. Return from the including class's
|
|
152
|
+
# `provider_middleware`. Pure — requests are reused across retry
|
|
153
|
+
# attempts, so the incoming `req` is never mutated.
|
|
152
154
|
#
|
|
153
|
-
# @param
|
|
154
|
-
# @
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
#
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
155
|
+
# @param req [Anthropic::APIRequest]
|
|
156
|
+
# @param nxt [#call]
|
|
157
|
+
# @return [Anthropic::APIResponse]
|
|
158
|
+
private def aws_auth_provider(req, nxt)
|
|
159
|
+
if @workspace_id
|
|
160
|
+
req = req.with(headers: {**req.headers, "anthropic-workspace-id" => @workspace_id})
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# `follow_redirect` stripped `authorization` for a cross-origin hop —
|
|
164
|
+
# don't re-sign and leak credentials to the new origin.
|
|
165
|
+
req = sign_aws_request(req) if @use_sig_v4 && !req.metadata[:cross_origin_redirect]
|
|
166
|
+
nxt.call(req)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# SigV4 signs over the body bytes, so the canonical body is encoded here
|
|
170
|
+
# and the signed bytes ride down to the transport. `Aws::Sigv4::Signer`
|
|
171
|
+
# only accepts `String` / `IO` / `nil` bodies, and multipart/JSONL
|
|
172
|
+
# encodings are lazy single-consumer enumerables — materialize those into
|
|
173
|
+
# a `StringIO`, which the terminal's encoding passes through untouched,
|
|
174
|
+
# so the signed payload is exactly the bytes that go over the wire.
|
|
175
|
+
#
|
|
176
|
+
# @param req [Anthropic::APIRequest]
|
|
177
|
+
# @return [Anthropic::APIRequest]
|
|
178
|
+
private def sign_aws_request(req)
|
|
179
|
+
headers, encoded = Anthropic::Internal::Util.encode_content(req.headers, req.body)
|
|
169
180
|
body =
|
|
170
|
-
case
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
181
|
+
case encoded
|
|
182
|
+
in nil | StringIO | IO
|
|
183
|
+
encoded
|
|
184
|
+
in String
|
|
185
|
+
StringIO.new(encoded)
|
|
186
|
+
in Enumerable
|
|
187
|
+
StringIO.new(encoded.to_a.join)
|
|
177
188
|
else
|
|
178
|
-
|
|
189
|
+
StringIO.new(encoded.to_s)
|
|
179
190
|
end
|
|
180
191
|
|
|
181
|
-
|
|
182
|
-
signed = @signer.sign_request({**sliced, headers: headers})
|
|
192
|
+
signed = @signer.sign_request(http_method: req.method, url: req.url, body: body, headers: headers)
|
|
183
193
|
headers = Anthropic::Internal::Util.normalized_headers(headers, signed.headers)
|
|
184
194
|
headers.delete("connection")
|
|
185
|
-
|
|
195
|
+
req.with(headers: headers, body: body)
|
|
186
196
|
end
|
|
187
197
|
|
|
188
198
|
# Resolves AWS credentials from explicit args, profile, env vars, or default chain.
|
|
@@ -4,6 +4,8 @@ module Anthropic
|
|
|
4
4
|
module Helpers
|
|
5
5
|
module Bedrock
|
|
6
6
|
class Client < Anthropic::Client
|
|
7
|
+
include Anthropic::Helpers::AWSAuth
|
|
8
|
+
|
|
7
9
|
DEFAULT_VERSION = "bedrock-2023-05-31"
|
|
8
10
|
|
|
9
11
|
# @return [Anthropic::Resources::Messages]
|
|
@@ -53,6 +55,11 @@ module Anthropic
|
|
|
53
55
|
#
|
|
54
56
|
# @param max_retry_delay [Float] The maximum number of seconds to wait before retrying a request
|
|
55
57
|
#
|
|
58
|
+
# @param middleware [Array<#call>, #call, nil] Per-attempt HTTP around-middleware. See
|
|
59
|
+
# {Anthropic::Middleware}. Middleware sees the canonical Anthropic request shape;
|
|
60
|
+
# the Bedrock URL rewrite and SigV4 signing happen inside the continuation, per
|
|
61
|
+
# attempt.
|
|
62
|
+
#
|
|
56
63
|
def initialize( # rubocop:disable Lint/MissingSuper
|
|
57
64
|
aws_region: nil,
|
|
58
65
|
base_url: nil,
|
|
@@ -64,7 +71,8 @@ module Anthropic
|
|
|
64
71
|
aws_secret_key: nil,
|
|
65
72
|
aws_session_token: nil,
|
|
66
73
|
aws_profile: nil,
|
|
67
|
-
api_key: nil
|
|
74
|
+
api_key: nil,
|
|
75
|
+
middleware: nil
|
|
68
76
|
)
|
|
69
77
|
api_key ||= ENV["AWS_BEARER_TOKEN_BEDROCK"]
|
|
70
78
|
|
|
@@ -122,6 +130,10 @@ module Anthropic
|
|
|
122
130
|
@auth_token = @signer ? nil : api_key
|
|
123
131
|
@credentials = nil
|
|
124
132
|
@token_cache = nil
|
|
133
|
+
# For AWSAuth#auth_headers: suppress key headers in SigV4 mode; in
|
|
134
|
+
# API-key mode fall through to the base bearer-token handling.
|
|
135
|
+
@use_sig_v4 = !@signer.nil?
|
|
136
|
+
@use_bearer_auth = false
|
|
125
137
|
|
|
126
138
|
# Skip Anthropic::Client#initialize and bind BaseClient#initialize directly:
|
|
127
139
|
# the parent's initializer runs OIDC/credential-provider resolution that does
|
|
@@ -132,7 +144,8 @@ module Anthropic
|
|
|
132
144
|
max_retries: max_retries,
|
|
133
145
|
initial_retry_delay: initial_retry_delay,
|
|
134
146
|
max_retry_delay: max_retry_delay,
|
|
135
|
-
headers: {"anthropic-version" => "2023-06-01"}
|
|
147
|
+
headers: {"anthropic-version" => "2023-06-01"},
|
|
148
|
+
middleware: middleware
|
|
136
149
|
)
|
|
137
150
|
|
|
138
151
|
@messages = Anthropic::Resources::Messages.new(client: self)
|
|
@@ -178,36 +191,51 @@ module Anthropic
|
|
|
178
191
|
#
|
|
179
192
|
# @return [Hash{Symbol=>Object}]
|
|
180
193
|
private def build_request(req, opts)
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
body = req.fetch(:body)
|
|
184
|
-
req[:body] = StringIO.new(body.to_a.join) if body.is_a?(Enumerator)
|
|
185
|
-
req
|
|
194
|
+
validate_bedrock_request!(req)
|
|
195
|
+
super
|
|
186
196
|
end
|
|
187
197
|
|
|
188
198
|
# @api private
|
|
189
199
|
#
|
|
190
|
-
#
|
|
191
|
-
#
|
|
192
|
-
#
|
|
193
|
-
#
|
|
194
|
-
#
|
|
195
|
-
#
|
|
196
|
-
#
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
200
|
+
# The Bedrock provider middleware: rewrites the canonical request into
|
|
201
|
+
# Bedrock's shape and SigV4-signs it. Appended innermost on every
|
|
202
|
+
# dispatch (below user middleware) and runs per attempt, so each retry
|
|
203
|
+
# or middleware-re-issued leg is re-adapted and re-signed for its own
|
|
204
|
+
# model and URL.
|
|
205
|
+
#
|
|
206
|
+
# @return [#call]
|
|
207
|
+
private def provider_middleware
|
|
208
|
+
lambda do |req, nxt|
|
|
209
|
+
req = adapt_request(req)
|
|
210
|
+
# `follow_redirect` stripped `authorization` for a cross-origin
|
|
211
|
+
# hop — don't re-sign and leak credentials to the new origin.
|
|
212
|
+
req = sign_aws_request(req) if @signer && !req.metadata[:cross_origin_redirect]
|
|
213
|
+
res = nxt.call(req)
|
|
214
|
+
# `invoke-with-response-stream` returns AWS event-stream framing,
|
|
215
|
+
# not SSE — transcode so `Util.decode_sse` and the streaming
|
|
216
|
+
# helpers work unchanged.
|
|
217
|
+
res = adapt_stream_response(res) if EventStream::AWS_CONTENT_TYPE.match?(res.headers["content-type"].to_s)
|
|
218
|
+
res
|
|
219
|
+
end
|
|
220
|
+
end
|
|
205
221
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
222
|
+
# @api private
|
|
223
|
+
#
|
|
224
|
+
# Rebuilds the response with the body transcoded from AWS event-stream
|
|
225
|
+
# framing to SSE bytes and the `content-type` rewritten so
|
|
226
|
+
# {Anthropic::Internal::Util.decode_content} dispatches to `decode_sse`.
|
|
227
|
+
#
|
|
228
|
+
# @param res [Anthropic::APIResponse]
|
|
229
|
+
# @return [Anthropic::APIResponse]
|
|
230
|
+
private def adapt_stream_response(res)
|
|
231
|
+
Anthropic::APIResponse.new(
|
|
232
|
+
status: res.status,
|
|
233
|
+
headers: res.headers.merge("content-type" => "text/event-stream"),
|
|
234
|
+
body: EventStream.to_sse(res.body),
|
|
235
|
+
raw: res.raw,
|
|
236
|
+
streaming: true,
|
|
237
|
+
request: res.request
|
|
238
|
+
)
|
|
211
239
|
end
|
|
212
240
|
|
|
213
241
|
# @param aws_region [String, nil]
|
|
@@ -243,35 +271,14 @@ module Anthropic
|
|
|
243
271
|
|
|
244
272
|
# @private
|
|
245
273
|
#
|
|
246
|
-
#
|
|
247
|
-
#
|
|
248
|
-
# @param request_components [Hash{Symbol=>Object}] .
|
|
249
|
-
#
|
|
250
|
-
# @option request_components [Symbol] :method
|
|
251
|
-
#
|
|
252
|
-
# @option request_components [String, Array<String>] :path
|
|
253
|
-
#
|
|
254
|
-
# @option request_components [Hash{String=>Array<String>, String, nil}, nil] :query
|
|
255
|
-
#
|
|
256
|
-
# @option request_components [Hash{String=>String, nil}, nil] :headers
|
|
274
|
+
# Fail fast at request-build time on routes Bedrock does not support.
|
|
257
275
|
#
|
|
258
|
-
#
|
|
259
|
-
#
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
# @option request_components [Anthropic::Converter, Class, nil] :model
|
|
265
|
-
#
|
|
266
|
-
# @return [Hash{Symbol=>Object}]
|
|
267
|
-
#
|
|
268
|
-
private def fit_req_to_bedrock_specs!(request_components)
|
|
269
|
-
if (body = request_components[:body]).is_a?(Hash)
|
|
270
|
-
body[:anthropic_version] ||= DEFAULT_VERSION
|
|
271
|
-
body.transform_keys!("anthropic-beta": :anthropic_beta)
|
|
272
|
-
end
|
|
273
|
-
|
|
274
|
-
case request_components[:path]
|
|
276
|
+
# @param request_components [Hash{Symbol=>Object}]
|
|
277
|
+
# @return [void]
|
|
278
|
+
private def validate_bedrock_request!(request_components)
|
|
279
|
+
# Id-parameterized routes pass `path` as an Array whose first element
|
|
280
|
+
# is the format string (e.g. `["v1/messages/batches/%1$s", id]`).
|
|
281
|
+
case Array(request_components[:path]).first.to_s
|
|
275
282
|
in %r{^v1/messages/batches}
|
|
276
283
|
message = "The Batch API is not supported in Bedrock yet"
|
|
277
284
|
raise NotImplementedError.new(message)
|
|
@@ -285,20 +292,45 @@ module Anthropic
|
|
|
285
292
|
raise NotImplementedError.new(message)
|
|
286
293
|
else
|
|
287
294
|
end
|
|
295
|
+
end
|
|
288
296
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
297
|
+
# @api private
|
|
298
|
+
#
|
|
299
|
+
# Rewrites the canonical Anthropic request into Bedrock's shape — drops
|
|
300
|
+
# `:model`/`:stream` from the body and retargets the URL to
|
|
301
|
+
# `/model/{model}/invoke[-with-response-stream]`. Called from
|
|
302
|
+
# {#provider_middleware}, so user middleware sees the canonical
|
|
303
|
+
# request. Pure: the incoming request, its body, and its URI are never
|
|
304
|
+
# mutated (they are reused across retry attempts).
|
|
305
|
+
#
|
|
306
|
+
# @param req [Anthropic::APIRequest]
|
|
307
|
+
# @return [Anthropic::APIRequest]
|
|
308
|
+
private def adapt_request(req)
|
|
309
|
+
body = req.body
|
|
310
|
+
return req unless body.is_a?(Hash)
|
|
311
|
+
|
|
312
|
+
body = body.transform_keys("anthropic-beta": :anthropic_beta)
|
|
313
|
+
body[:anthropic_version] ||= DEFAULT_VERSION
|
|
314
|
+
|
|
315
|
+
path = req.url.path.to_s
|
|
316
|
+
query = req.url.query
|
|
317
|
+
messages_route =
|
|
318
|
+
(path.end_with?("/v1/messages") && (query.nil? || query == "beta=true")) ||
|
|
319
|
+
(path.end_with?("/v1/complete") && query.nil?)
|
|
320
|
+
|
|
321
|
+
return req.with(body: body) unless req.method == :post && messages_route
|
|
322
|
+
|
|
323
|
+
model = URI.encode_www_form_component(body.delete(:model).to_s)
|
|
324
|
+
stream = body.delete(:stream) || false
|
|
325
|
+
|
|
326
|
+
url = req.url.dup
|
|
327
|
+
url.path = path.sub(
|
|
328
|
+
%r{v1/(?:messages|complete)\z},
|
|
329
|
+
stream ? "model/#{model}/invoke-with-response-stream" : "model/#{model}/invoke"
|
|
330
|
+
)
|
|
331
|
+
url.query = nil
|
|
300
332
|
|
|
301
|
-
|
|
333
|
+
req.with(body: body, url: url)
|
|
302
334
|
end
|
|
303
335
|
end
|
|
304
336
|
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Anthropic
|
|
4
|
+
module Helpers
|
|
5
|
+
module Bedrock
|
|
6
|
+
# @api private
|
|
7
|
+
#
|
|
8
|
+
# Bedrock's `invoke-with-response-stream` returns
|
|
9
|
+
# `application/vnd.amazon.eventstream` (AWS binary event-stream framing),
|
|
10
|
+
# not SSE. The SDK's stream consumer parses SSE only — without this
|
|
11
|
+
# transcoder a Bedrock stream silently yields zero events. Each frame's
|
|
12
|
+
# payload is `{"bytes": "<base64>"}` wrapping a standard Anthropic event
|
|
13
|
+
# JSON; this re-emits those as `event:`/`data:` SSE bytes so the existing
|
|
14
|
+
# `Internal::Util.decode_sse` and the streaming helpers work unchanged.
|
|
15
|
+
module EventStream
|
|
16
|
+
AWS_CONTENT_TYPE = %r{^application/vnd\.amazon\.eventstream}
|
|
17
|
+
|
|
18
|
+
class << self
|
|
19
|
+
# @api private
|
|
20
|
+
#
|
|
21
|
+
# Transcodes the raw AWS event-stream byte chunks into SSE-formatted
|
|
22
|
+
# byte chunks. Incremental: each input chunk is fed to
|
|
23
|
+
# `Aws::EventStream::Decoder` and any complete frames are emitted
|
|
24
|
+
# immediately, so the stream is not buffered end-to-end.
|
|
25
|
+
#
|
|
26
|
+
# @param chunks [Enumerable<String>] raw response body chunks
|
|
27
|
+
# @return [Enumerable<String>] SSE-formatted body chunks
|
|
28
|
+
def to_sse(chunks)
|
|
29
|
+
# `aws-eventstream` ships with `aws-sdk-core`, which the Bedrock
|
|
30
|
+
# client already lazy-requires before any request can fire.
|
|
31
|
+
require("aws-eventstream")
|
|
32
|
+
decoder = Aws::EventStream::Decoder.new
|
|
33
|
+
Anthropic::Internal::Util.chain_fused(chunks) do |y|
|
|
34
|
+
chunks.each { |chunk| drain(decoder, chunk, y) }
|
|
35
|
+
drain(decoder, nil, y)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# @api private
|
|
40
|
+
#
|
|
41
|
+
# Feeds one chunk (or `nil` to flush) into the decoder and emits any
|
|
42
|
+
# complete frames as SSE bytes.
|
|
43
|
+
#
|
|
44
|
+
# @param decoder [Aws::EventStream::Decoder]
|
|
45
|
+
# @param chunk [String, nil]
|
|
46
|
+
# @param y [Enumerator::Yielder]
|
|
47
|
+
# @return [void]
|
|
48
|
+
def drain(decoder, chunk, y)
|
|
49
|
+
loop do
|
|
50
|
+
msg, eof = decoder.decode_chunk(chunk)
|
|
51
|
+
chunk = nil
|
|
52
|
+
break if msg.nil?
|
|
53
|
+
emit(msg, y)
|
|
54
|
+
break if eof
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# @api private
|
|
59
|
+
#
|
|
60
|
+
# Emit one decoded AWS event-stream message as SSE bytes.
|
|
61
|
+
#
|
|
62
|
+
# `:message-type: event` frames carry a JSON payload
|
|
63
|
+
# `{"bytes": "<base64>"}` wrapping the Anthropic event; emit it as
|
|
64
|
+
# an `event:`/`data:` pair. `:message-type: exception` frames carry an
|
|
65
|
+
# error payload and a `:exception-type` header — re-emit as the same
|
|
66
|
+
# `event: error` / `data: {"type":"error",...}` SSE shape the API
|
|
67
|
+
# would have sent, so the stream consumer's existing error path fires.
|
|
68
|
+
#
|
|
69
|
+
# @param msg [Aws::EventStream::Message]
|
|
70
|
+
# @param y [Enumerator::Yielder]
|
|
71
|
+
# @return [void]
|
|
72
|
+
def emit(msg, y)
|
|
73
|
+
case msg.headers[":message-type"]&.value
|
|
74
|
+
in "event"
|
|
75
|
+
payload = JSON.parse(msg.payload.read, symbolize_names: true)
|
|
76
|
+
inner = Base64.decode64(payload.fetch(:bytes))
|
|
77
|
+
type = JSON.parse(inner, symbolize_names: true).fetch(:type)
|
|
78
|
+
y << "event: #{type}\ndata: #{inner}\n\n"
|
|
79
|
+
in "exception"
|
|
80
|
+
exc_type = msg.headers[":exception-type"]&.value
|
|
81
|
+
body = msg.payload.read
|
|
82
|
+
data = JSON.generate(type: "error", error: {type: exc_type, message: body})
|
|
83
|
+
y << "event: error\ndata: #{data}\n\n"
|
|
84
|
+
else
|
|
85
|
+
# Unknown message-type — drop. AWS may add prelude/metadata frames.
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
@@ -114,9 +114,9 @@ module Anthropic
|
|
|
114
114
|
end
|
|
115
115
|
|
|
116
116
|
# @api private
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
117
|
+
#
|
|
118
|
+
# @return [#call]
|
|
119
|
+
private def provider_middleware = method(:aws_auth_provider)
|
|
120
120
|
|
|
121
121
|
# Restricted Beta service that only exposes messages. Other beta resources
|
|
122
122
|
# (models, files, skills) are not supported on Bedrock Mantle.
|