anthropic 1.9.0 → 1.10.1

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.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +44 -0
  3. data/README.md +12 -12
  4. data/lib/anthropic/errors.rb +25 -11
  5. data/lib/anthropic/file_part.rb +10 -7
  6. data/lib/anthropic/helpers/bedrock/client.rb +8 -24
  7. data/lib/anthropic/internal/page.rb +1 -1
  8. data/lib/anthropic/internal/stream.rb +1 -0
  9. data/lib/anthropic/internal/transport/base_client.rb +16 -12
  10. data/lib/anthropic/internal/transport/pooled_net_requester.rb +7 -10
  11. data/lib/anthropic/internal/type/base_page.rb +1 -1
  12. data/lib/anthropic/internal/type/base_stream.rb +8 -17
  13. data/lib/anthropic/internal/type/file_input.rb +7 -4
  14. data/lib/anthropic/internal/util.rb +2 -1
  15. data/lib/anthropic/models/anthropic_beta.rb +6 -0
  16. data/lib/anthropic/models/beta/beta_clear_tool_uses_20250919_edit.rb +98 -0
  17. data/lib/anthropic/models/beta/beta_clear_tool_uses_20250919_edit_response.rb +38 -0
  18. data/lib/anthropic/models/beta/beta_context_management_config.rb +22 -0
  19. data/lib/anthropic/models/beta/beta_context_management_response.rb +23 -0
  20. data/lib/anthropic/models/beta/beta_count_tokens_context_management_response.rb +20 -0
  21. data/lib/anthropic/models/beta/beta_input_tokens_clear_at_least.rb +25 -0
  22. data/lib/anthropic/models/beta/beta_input_tokens_trigger.rb +25 -0
  23. data/lib/anthropic/models/beta/beta_memory_tool_20250818.rb +40 -0
  24. data/lib/anthropic/models/beta/beta_memory_tool_20250818_command.rb +30 -0
  25. data/lib/anthropic/models/beta/beta_memory_tool_20250818_create_command.rb +36 -0
  26. data/lib/anthropic/models/beta/beta_memory_tool_20250818_delete_command.rb +28 -0
  27. data/lib/anthropic/models/beta/beta_memory_tool_20250818_insert_command.rb +44 -0
  28. data/lib/anthropic/models/beta/beta_memory_tool_20250818_rename_command.rb +36 -0
  29. data/lib/anthropic/models/beta/beta_memory_tool_20250818_str_replace_command.rb +44 -0
  30. data/lib/anthropic/models/beta/beta_memory_tool_20250818_view_command.rb +36 -0
  31. data/lib/anthropic/models/beta/beta_message.rb +9 -1
  32. data/lib/anthropic/models/beta/beta_message_tokens_count.rb +13 -1
  33. data/lib/anthropic/models/beta/beta_raw_message_delta_event.rb +9 -1
  34. data/lib/anthropic/models/beta/beta_stop_reason.rb +1 -0
  35. data/lib/anthropic/models/beta/beta_tool_union.rb +3 -1
  36. data/lib/anthropic/models/beta/beta_tool_uses_keep.rb +25 -0
  37. data/lib/anthropic/models/beta/beta_tool_uses_trigger.rb +25 -0
  38. data/lib/anthropic/models/beta/message_count_tokens_params.rb +14 -4
  39. data/lib/anthropic/models/beta/message_create_params.rb +11 -3
  40. data/lib/anthropic/models/beta/messages/batch_create_params.rb +11 -3
  41. data/lib/anthropic/models/model.rb +10 -0
  42. data/lib/anthropic/models/stop_reason.rb +1 -0
  43. data/lib/anthropic/resources/beta/messages.rb +12 -6
  44. data/lib/anthropic/version.rb +1 -1
  45. data/lib/anthropic.rb +17 -0
  46. data/rbi/anthropic/errors.rbi +29 -2
  47. data/rbi/anthropic/file_part.rbi +1 -1
  48. data/rbi/anthropic/internal/transport/base_client.rbi +4 -5
  49. data/rbi/anthropic/internal/type/base_page.rbi +1 -1
  50. data/rbi/anthropic/internal/type/base_stream.rbi +15 -15
  51. data/rbi/anthropic/internal/util.rbi +1 -1
  52. data/rbi/anthropic/models/anthropic_beta.rbi +10 -0
  53. data/rbi/anthropic/models/beta/beta_clear_tool_uses_20250919_edit.rbi +183 -0
  54. data/rbi/anthropic/models/beta/beta_clear_tool_uses_20250919_edit_response.rbi +62 -0
  55. data/rbi/anthropic/models/beta/beta_context_management_config.rbi +56 -0
  56. data/rbi/anthropic/models/beta/beta_context_management_response.rbi +53 -0
  57. data/rbi/anthropic/models/beta/beta_count_tokens_context_management_response.rbi +35 -0
  58. data/rbi/anthropic/models/beta/beta_input_tokens_clear_at_least.rbi +33 -0
  59. data/rbi/anthropic/models/beta/beta_input_tokens_trigger.rbi +33 -0
  60. data/rbi/anthropic/models/beta/beta_memory_tool_20250818.rbi +72 -0
  61. data/rbi/anthropic/models/beta/beta_memory_tool_20250818_command.rbi +33 -0
  62. data/rbi/anthropic/models/beta/beta_memory_tool_20250818_create_command.rbi +53 -0
  63. data/rbi/anthropic/models/beta/beta_memory_tool_20250818_delete_command.rbi +41 -0
  64. data/rbi/anthropic/models/beta/beta_memory_tool_20250818_insert_command.rbi +69 -0
  65. data/rbi/anthropic/models/beta/beta_memory_tool_20250818_rename_command.rbi +55 -0
  66. data/rbi/anthropic/models/beta/beta_memory_tool_20250818_str_replace_command.rbi +64 -0
  67. data/rbi/anthropic/models/beta/beta_memory_tool_20250818_view_command.rbi +59 -0
  68. data/rbi/anthropic/models/beta/beta_message.rbi +20 -0
  69. data/rbi/anthropic/models/beta/beta_message_tokens_count.rbi +40 -2
  70. data/rbi/anthropic/models/beta/beta_raw_message_delta_event.rbi +20 -0
  71. data/rbi/anthropic/models/beta/beta_stop_reason.rbi +5 -0
  72. data/rbi/anthropic/models/beta/beta_tool_union.rbi +1 -0
  73. data/rbi/anthropic/models/beta/beta_tool_uses_keep.rbi +33 -0
  74. data/rbi/anthropic/models/beta/beta_tool_uses_trigger.rbi +33 -0
  75. data/rbi/anthropic/models/beta/message_count_tokens_params.rbi +23 -0
  76. data/rbi/anthropic/models/beta/message_create_params.rbi +22 -0
  77. data/rbi/anthropic/models/beta/messages/batch_create_params.rbi +28 -0
  78. data/rbi/anthropic/models/model.rbi +8 -0
  79. data/rbi/anthropic/models/stop_reason.rbi +5 -0
  80. data/rbi/anthropic/resources/beta/messages.rbi +15 -0
  81. data/sig/anthropic/errors.rbs +7 -0
  82. data/sig/anthropic/file_part.rbs +1 -1
  83. data/sig/anthropic/internal/type/base_stream.rbs +4 -3
  84. data/sig/anthropic/models/anthropic_beta.rbs +4 -0
  85. data/sig/anthropic/models/beta/beta_clear_tool_uses_20250919_edit.rbs +77 -0
  86. data/sig/anthropic/models/beta/beta_clear_tool_uses_20250919_edit_response.rbs +34 -0
  87. data/sig/anthropic/models/beta/beta_context_management_config.rbs +26 -0
  88. data/sig/anthropic/models/beta/beta_context_management_response.rbs +24 -0
  89. data/sig/anthropic/models/beta/beta_count_tokens_context_management_response.rbs +18 -0
  90. data/sig/anthropic/models/beta/beta_input_tokens_clear_at_least.rbs +20 -0
  91. data/sig/anthropic/models/beta/beta_input_tokens_trigger.rbs +19 -0
  92. data/sig/anthropic/models/beta/beta_memory_tool_20250818.rbs +34 -0
  93. data/sig/anthropic/models/beta/beta_memory_tool_20250818_command.rbs +21 -0
  94. data/sig/anthropic/models/beta/beta_memory_tool_20250818_create_command.rbs +26 -0
  95. data/sig/anthropic/models/beta/beta_memory_tool_20250818_delete_command.rbs +20 -0
  96. data/sig/anthropic/models/beta/beta_memory_tool_20250818_insert_command.rbs +39 -0
  97. data/sig/anthropic/models/beta/beta_memory_tool_20250818_rename_command.rbs +26 -0
  98. data/sig/anthropic/models/beta/beta_memory_tool_20250818_str_replace_command.rbs +39 -0
  99. data/sig/anthropic/models/beta/beta_memory_tool_20250818_view_command.rbs +32 -0
  100. data/sig/anthropic/models/beta/beta_message.rbs +5 -0
  101. data/sig/anthropic/models/beta/beta_message_tokens_count.rbs +15 -3
  102. data/sig/anthropic/models/beta/beta_raw_message_delta_event.rbs +5 -0
  103. data/sig/anthropic/models/beta/beta_stop_reason.rbs +2 -0
  104. data/sig/anthropic/models/beta/beta_tool_union.rbs +1 -0
  105. data/sig/anthropic/models/beta/beta_tool_uses_keep.rbs +19 -0
  106. data/sig/anthropic/models/beta/beta_tool_uses_trigger.rbs +19 -0
  107. data/sig/anthropic/models/beta/message_count_tokens_params.rbs +6 -0
  108. data/sig/anthropic/models/beta/message_create_params.rbs +5 -0
  109. data/sig/anthropic/models/beta/messages/batch_create_params.rbs +5 -0
  110. data/sig/anthropic/models/model.rbs +8 -0
  111. data/sig/anthropic/models/stop_reason.rbs +2 -0
  112. data/sig/anthropic/resources/beta/messages.rbs +3 -0
  113. metadata +53 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9508f2174591353cfaa66f66d1ec7d72fbd3dced9f88e64aae101ad0b370ec51
4
- data.tar.gz: 4e10f3b7dcdfe9e1fc2bf5efec9bb8578d63f2d49a0ed36b08db2153109a0ada
3
+ metadata.gz: 4749c4c57431c6592426ac4a7a7c5897c5f197accdc4974e52a3ee28c57bd44b
4
+ data.tar.gz: b8bf6c80d6b001ad703ff57684cee3eddbc45fdbb5afbcd74d1cabd3aa7b993c
5
5
  SHA512:
6
- metadata.gz: b5eeb2c0701c8ab45b86c58f28c4fd49344ae4b9ac1539486ba282ce3b9154cd3b7e8466fb933b61206f18ef2024f50de8366d5aa89336e86307e2ab22a8f1c2
7
- data.tar.gz: c6f369c9cd95b5501e4416dd8c46ba936f2b09134ccb1a7fec65e7a7948b0e734db46bc3836dee43deac948c4fd216162a5395301c71b837e6277cdbabbbc7a9
6
+ metadata.gz: a28ab8518fe39e5710cd7dc264c7a6e327b596095991a6818805bad0ba868bb37ca6f2a301310919a823084b1ebb34eafb87973f943818f808e2ad90556585d2
7
+ data.tar.gz: b7e39572bd1d841360ac7e28de3610c907526523fad8ccb7ea882e5a0945cad383ee7f47431707ff38e525649e82d516a39c9949b9e2393fe18562e13050faaa
data/CHANGELOG.md CHANGED
@@ -1,5 +1,49 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.10.1 (2025-10-06)
4
+
5
+ Full Changelog: [v1.10.0...v1.10.1](https://github.com/anthropics/anthropic-sdk-ruby/compare/v1.10.0...v1.10.1)
6
+
7
+ ### Bug Fixes
8
+
9
+ * always send `filename=...` for multipart requests where a file is expected ([0ffb017](https://github.com/anthropics/anthropic-sdk-ruby/commit/0ffb017c542b98891c6fcee76d7e3f3cb7ae5f26))
10
+ * bedrock signing issue with retried requests ([#719](https://github.com/anthropics/anthropic-sdk-ruby/issues/719)) ([69372ed](https://github.com/anthropics/anthropic-sdk-ruby/commit/69372edca8cca2529d04baafa58160890c7b95a4))
11
+ * coroutine leaks from connection pool ([7b9fb31](https://github.com/anthropics/anthropic-sdk-ruby/commit/7b9fb31c9d7d5407dee7203263001ba1050750b4))
12
+
13
+
14
+ ### Chores
15
+
16
+ * **client:** add context-management-2025-06-27 beta header ([067535d](https://github.com/anthropics/anthropic-sdk-ruby/commit/067535dbcc44cc244497faeca7943a435f09c49f))
17
+ * **client:** add model-context-window-exceeded-2025-08-26 beta header ([b12c86f](https://github.com/anthropics/anthropic-sdk-ruby/commit/b12c86f80f45b6dee023c2bfc14895bf93348105))
18
+
19
+ ## 1.10.0 (2025-09-29)
20
+
21
+ Full Changelog: [v1.9.0...v1.10.0](https://github.com/anthropics/anthropic-sdk-ruby/compare/v1.9.0...v1.10.0)
22
+
23
+ ### Features
24
+
25
+ * **api:** adds support for Claude Sonnet 4.5 and context management features ([3a3cad6](https://github.com/anthropics/anthropic-sdk-ruby/commit/3a3cad636f05c4e395e6078aa7b429c464ad66aa))
26
+ * expose response headers for both streams and errors ([9bfbae1](https://github.com/anthropics/anthropic-sdk-ruby/commit/9bfbae1483ce10852f7d89f1a598ed41a3f057e5))
27
+
28
+
29
+ ### Bug Fixes
30
+
31
+ * always send filename in content-disposition headers ([#126](https://github.com/anthropics/anthropic-sdk-ruby/issues/126)) ([0e665f3](https://github.com/anthropics/anthropic-sdk-ruby/commit/0e665f34f0d736a400e0ab8b82cad7ccaf0845b1))
32
+ * **internal:** use null byte as file separator in the fast formatting script ([beae717](https://github.com/anthropics/anthropic-sdk-ruby/commit/beae717a7ce89349456e6a50b261c606ffce7759))
33
+ * shorten multipart boundary sep to less than RFC specificed max length ([40226f9](https://github.com/anthropics/anthropic-sdk-ruby/commit/40226f94c36291e84b0aef86a9058080ba94640b))
34
+
35
+
36
+ ### Performance Improvements
37
+
38
+ * faster code formatting ([47de8dd](https://github.com/anthropics/anthropic-sdk-ruby/commit/47de8dd9fc0f10dcd623cbe394d802c5e2dc00af))
39
+
40
+
41
+ ### Chores
42
+
43
+ * allow fast-format to use bsd sed as well ([ea0324c](https://github.com/anthropics/anthropic-sdk-ruby/commit/ea0324c0f1aadfc870b0ddc6438728fed44b12f2))
44
+ * do not install brew dependencies in ./scripts/bootstrap by default ([2091081](https://github.com/anthropics/anthropic-sdk-ruby/commit/209108181b9ab99ff224cf15910af674451ed477))
45
+ * **internal:** fix tests ([59ce934](https://github.com/anthropics/anthropic-sdk-ruby/commit/59ce9348b0d17c9ecd8ccb83fd16c8aff743dc8b))
46
+
3
47
  ## 1.9.0 (2025-09-10)
4
48
 
5
49
  Full Changelog: [v1.8.0...v1.9.0](https://github.com/anthropics/anthropic-sdk-ruby/compare/v1.8.0...v1.9.0)
data/README.md CHANGED
@@ -15,7 +15,7 @@ To use this gem, install via Bundler by adding the following to your application
15
15
  <!-- x-release-please-start-version -->
16
16
 
17
17
  ```ruby
18
- gem "anthropic", "~> 1.9.0"
18
+ gem "anthropic", "~> 1.10.1"
19
19
  ```
20
20
 
21
21
  <!-- x-release-please-end -->
@@ -39,7 +39,7 @@ anthropic = Anthropic::Client.new(
39
39
  message = anthropic.messages.create(
40
40
  max_tokens: 1024,
41
41
  messages: [{role: "user", content: "Hello, Claude"}],
42
- model: :"claude-sonnet-4-20250514"
42
+ model: :"claude-sonnet-4-5-20250929"
43
43
  )
44
44
 
45
45
  puts(message.content)
@@ -53,7 +53,7 @@ We provide support for streaming responses using Server-Sent Events (SSE).
53
53
  stream = anthropic.messages.stream(
54
54
  max_tokens: 1024,
55
55
  messages: [{role: "user", content: "Hello, Claude"}],
56
- model: :"claude-sonnet-4-20250514"
56
+ model: :"claude-sonnet-4-5-20250929"
57
57
  )
58
58
 
59
59
  stream.each do |message|
@@ -69,7 +69,7 @@ This library provides several conveniences for streaming messages, for example:
69
69
  stream = anthropic.messages.stream(
70
70
  max_tokens: 1024,
71
71
  messages: [{role: :user, content: "Say hello there!"}],
72
- model: :"claude-sonnet-4-20250514"
72
+ model: :"claude-sonnet-4-5-20250929"
73
73
  )
74
74
 
75
75
  stream.text.each do |text|
@@ -138,7 +138,7 @@ begin
138
138
  message = anthropic.messages.create(
139
139
  max_tokens: 1024,
140
140
  messages: [{role: "user", content: "Hello, Claude"}],
141
- model: :"claude-sonnet-4-20250514"
141
+ model: :"claude-sonnet-4-5-20250929"
142
142
  )
143
143
  rescue Anthropic::Errors::APIConnectionError => e
144
144
  puts("The server could not be reached")
@@ -185,7 +185,7 @@ anthropic = Anthropic::Client.new(
185
185
  anthropic.messages.create(
186
186
  max_tokens: 1024,
187
187
  messages: [{role: "user", content: "Hello, Claude"}],
188
- model: :"claude-sonnet-4-20250514",
188
+ model: :"claude-sonnet-4-5-20250929",
189
189
  request_options: {max_retries: 5}
190
190
  )
191
191
  ```
@@ -204,7 +204,7 @@ anthropic = Anthropic::Client.new(
204
204
  anthropic.messages.create(
205
205
  max_tokens: 1024,
206
206
  messages: [{role: "user", content: "Hello, Claude"}],
207
- model: :"claude-sonnet-4-20250514",
207
+ model: :"claude-sonnet-4-5-20250929",
208
208
  request_options: {timeout: 5}
209
209
  )
210
210
  ```
@@ -235,7 +235,7 @@ message = anthropic.messages.create(
235
235
  content: "Hello, Claude"
236
236
  }
237
237
  ],
238
- model: "anthropic.claude-sonnet-4-20250514-v2:0"
238
+ model: "anthropic.claude-sonnet-4-5-20250929-v2:0"
239
239
  )
240
240
 
241
241
  puts(message)
@@ -300,7 +300,7 @@ message =
300
300
  anthropic.messages.create(
301
301
  max_tokens: 1024,
302
302
  messages: [{role: "user", content: "Hello, Claude"}],
303
- model: :"claude-sonnet-4-20250514",
303
+ model: :"claude-sonnet-4-5-20250929",
304
304
  request_options: {
305
305
  extra_query: {my_query_parameter: value},
306
306
  extra_body: {my_body_parameter: value},
@@ -349,7 +349,7 @@ You can provide typesafe request parameters like so:
349
349
  anthropic.messages.create(
350
350
  max_tokens: 1024,
351
351
  messages: [Anthropic::MessageParam.new(role: "user", content: "Hello, Claude")],
352
- model: :"claude-sonnet-4-20250514"
352
+ model: :"claude-sonnet-4-5-20250929"
353
353
  )
354
354
  ```
355
355
 
@@ -360,14 +360,14 @@ Or, equivalently:
360
360
  anthropic.messages.create(
361
361
  max_tokens: 1024,
362
362
  messages: [{role: "user", content: "Hello, Claude"}],
363
- model: :"claude-sonnet-4-20250514"
363
+ model: :"claude-sonnet-4-5-20250929"
364
364
  )
365
365
 
366
366
  # You can also splat a full Params class:
367
367
  params = Anthropic::MessageCreateParams.new(
368
368
  max_tokens: 1024,
369
369
  messages: [Anthropic::MessageParam.new(role: "user", content: "Hello, Claude")],
370
- model: :"claude-sonnet-4-20250514"
370
+ model: :"claude-sonnet-4-5-20250929"
371
371
  )
372
372
  anthropic.messages.create(**params)
373
373
  ```
@@ -40,6 +40,9 @@ module Anthropic
40
40
  # @return [Integer, nil]
41
41
  attr_accessor :status
42
42
 
43
+ # @return [Hash{String=>String}, nil]
44
+ attr_accessor :headers
45
+
43
46
  # @return [Object, nil]
44
47
  attr_accessor :body
45
48
 
@@ -47,13 +50,15 @@ module Anthropic
47
50
  #
48
51
  # @param url [URI::Generic]
49
52
  # @param status [Integer, nil]
53
+ # @param headers [Hash{String=>String}, nil]
50
54
  # @param body [Object, nil]
51
55
  # @param request [nil]
52
56
  # @param response [nil]
53
57
  # @param message [String, nil]
54
- def initialize(url:, status: nil, body: nil, request: nil, response: nil, message: nil)
58
+ def initialize(url:, status: nil, headers: nil, body: nil, request: nil, response: nil, message: nil)
55
59
  @url = url
56
60
  @status = status
61
+ @headers = headers
57
62
  @body = body
58
63
  @request = request
59
64
  @response = response
@@ -74,6 +79,7 @@ module Anthropic
74
79
  #
75
80
  # @param url [URI::Generic]
76
81
  # @param status [nil]
82
+ # @param headers [Hash{String=>String}, nil]
77
83
  # @param body [nil]
78
84
  # @param request [nil]
79
85
  # @param response [nil]
@@ -81,6 +87,7 @@ module Anthropic
81
87
  def initialize(
82
88
  url:,
83
89
  status: nil,
90
+ headers: nil,
84
91
  body: nil,
85
92
  request: nil,
86
93
  response: nil,
@@ -95,6 +102,7 @@ module Anthropic
95
102
  #
96
103
  # @param url [URI::Generic]
97
104
  # @param status [nil]
105
+ # @param headers [Hash{String=>String}, nil]
98
106
  # @param body [nil]
99
107
  # @param request [nil]
100
108
  # @param response [nil]
@@ -102,6 +110,7 @@ module Anthropic
102
110
  def initialize(
103
111
  url:,
104
112
  status: nil,
113
+ headers: nil,
105
114
  body: nil,
106
115
  request: nil,
107
116
  response: nil,
@@ -116,21 +125,24 @@ module Anthropic
116
125
  #
117
126
  # @param url [URI::Generic]
118
127
  # @param status [Integer]
128
+ # @param headers [Hash{String=>String}, nil]
119
129
  # @param body [Object, nil]
120
130
  # @param request [nil]
121
131
  # @param response [nil]
122
132
  # @param message [String, nil]
123
133
  #
124
134
  # @return [self]
125
- def self.for(url:, status:, body:, request:, response:, message: nil)
126
- kwargs = {
127
- url: url,
128
- status: status,
129
- body: body,
130
- request: request,
131
- response: response,
132
- message: message
133
- }
135
+ def self.for(url:, status:, headers:, body:, request:, response:, message: nil)
136
+ kwargs =
137
+ {
138
+ url: url,
139
+ status: status,
140
+ headers: headers,
141
+ body: body,
142
+ request: request,
143
+ response: response,
144
+ message: message
145
+ }
134
146
 
135
147
  case status
136
148
  in 400
@@ -162,15 +174,17 @@ module Anthropic
162
174
  #
163
175
  # @param url [URI::Generic]
164
176
  # @param status [Integer]
177
+ # @param headers [Hash{String=>String}, nil]
165
178
  # @param body [Object, nil]
166
179
  # @param request [nil]
167
180
  # @param response [nil]
168
181
  # @param message [String, nil]
169
- def initialize(url:, status:, body:, request:, response:, message: nil)
182
+ def initialize(url:, status:, headers:, body:, request:, response:, message: nil)
170
183
  message ||= {url: url.to_s, status: status, body: body}
171
184
  super(
172
185
  url: url,
173
186
  status: status,
187
+ headers: headers,
174
188
  body: body,
175
189
  request: request,
176
190
  response: response,
@@ -38,18 +38,21 @@ module Anthropic
38
38
  def to_yaml(*a) = read.to_yaml(*a)
39
39
 
40
40
  # @param content [Pathname, StringIO, IO, String]
41
- # @param filename [String, nil]
41
+ # @param filename [Pathname, String, nil]
42
42
  # @param content_type [String, nil]
43
43
  def initialize(content, filename: nil, content_type: nil)
44
- @content = content
44
+ @content_type = content_type
45
45
  @filename =
46
- case content
47
- in Pathname
48
- filename.nil? ? content.basename.to_path : ::File.basename(filename)
46
+ case [filename, (@content = content)]
47
+ in [String | Pathname, _]
48
+ ::File.basename(filename)
49
+ in [nil, Pathname]
50
+ content.basename.to_path
51
+ in [nil, IO]
52
+ content.to_path
49
53
  else
50
- filename.nil? ? nil : ::File.basename(filename)
54
+ filename
51
55
  end
52
- @content_type = content_type
53
56
  end
54
57
  end
55
58
  end
@@ -150,19 +150,10 @@ module Anthropic
150
150
  # @return [Hash{Symbol=>Object}]
151
151
  private def build_request(req, opts)
152
152
  fit_req_to_bedrock_specs!(req)
153
-
154
- request_input = super
155
-
156
- signed_request = @signer.sign_request(
157
- http_method: request_input[:method],
158
- url: request_input[:url],
159
- headers: request_input[:headers],
160
- body: request_input[:body]
161
- )
162
-
163
- request_input[:headers].merge!(signed_request.headers)
164
-
165
- request_input
153
+ req = super
154
+ body = req.fetch(:body)
155
+ req[:body] = StringIO.new(body.to_a.join) if body.is_a?(Enumerator)
156
+ req
166
157
  end
167
158
 
168
159
  # @api private
@@ -181,17 +172,10 @@ module Anthropic
181
172
  #
182
173
  # @return [Hash{Symbol, Object}]
183
174
  private def transform_request(request)
184
- sliced = super.slice(
185
- :method,
186
- :url,
187
- :headers,
188
- :body
189
- ).transform_keys(method: :http_method)
190
- body = StringIO.new(body.to_a.join) if (body = sliced.fetch(:body)).is_a?(Enumerator)
191
-
192
- signed = @signer.sign_request({**sliced, body: body})
193
-
194
- headers = Anthropic::Internal::Util.normalized_headers(request.fetch(:headers), signed.headers)
175
+ headers = request.fetch(:headers)
176
+ sliced = super.slice(:method, :url, :body).transform_keys(method: :http_method)
177
+ signed = @signer.sign_request({**sliced, headers: headers})
178
+ headers = Anthropic::Internal::Util.normalized_headers(headers, signed.headers)
195
179
  {**request, headers: headers}
196
180
  end
197
181
 
@@ -69,7 +69,7 @@ module Anthropic
69
69
  #
70
70
  # @param client [Anthropic::Internal::Transport::BaseClient]
71
71
  # @param req [Hash{Symbol=>Object}]
72
- # @param headers [Hash{String=>String}, Net::HTTPHeader]
72
+ # @param headers [Hash{String=>String}]
73
73
  # @param page_data [Hash{Symbol=>Object}]
74
74
  def initialize(client:, req:, headers:, page_data:)
75
75
  super
@@ -43,6 +43,7 @@ module Anthropic
43
43
  err = Anthropic::Errors::APIStatusError.for(
44
44
  url: @url,
45
45
  status: @status,
46
+ headers: @headers,
46
47
  body: decoded,
47
48
  request: nil,
48
49
  response: @response
@@ -47,7 +47,7 @@ module Anthropic
47
47
  # @api private
48
48
  #
49
49
  # @param status [Integer]
50
- # @param headers [Hash{String=>String}, Net::HTTPHeader]
50
+ # @param headers [Hash{String=>String}]
51
51
  #
52
52
  # @return [Boolean]
53
53
  def should_retry?(status, headers:)
@@ -85,7 +85,7 @@ module Anthropic
85
85
  #
86
86
  # @param status [Integer]
87
87
  #
88
- # @param response_headers [Hash{String=>String}, Net::HTTPHeader]
88
+ # @param response_headers [Hash{String=>String}]
89
89
  #
90
90
  # @return [Hash{Symbol=>Object}]
91
91
  def follow_redirect(request, status:, response_headers:)
@@ -383,19 +383,20 @@ module Anthropic
383
383
  # @raise [Anthropic::Errors::APIError]
384
384
  # @return [Array(Integer, Net::HTTPResponse, Enumerable<String>)]
385
385
  def send_request(request, redirect_count:, retry_count:, send_retry_header:)
386
- request = transform_request(request)
387
- url, headers, max_retries, timeout = request.fetch_values(:url, :headers, :max_retries, :timeout)
388
- input = {**request.except(:timeout), deadline: Anthropic::Internal::Util.monotonic_secs + timeout}
389
-
390
386
  if send_retry_header
391
- headers["x-stainless-retry-count"] = retry_count.to_s
387
+ request.fetch(:headers)["x-stainless-retry-count"] = retry_count.to_s
392
388
  end
393
389
 
390
+ request = transform_request(request)
391
+ url, max_retries, timeout = request.fetch_values(:url, :max_retries, :timeout)
392
+ input = {**request.except(:timeout), deadline: Anthropic::Internal::Util.monotonic_secs + timeout}
393
+
394
394
  begin
395
395
  status, response, stream = @requester.execute(input)
396
396
  rescue Anthropic::Errors::APIConnectionError => e
397
397
  status = e
398
398
  end
399
+ headers = Anthropic::Internal::Util.normalized_headers(response&.each_header&.to_h)
399
400
 
400
401
  case status
401
402
  in ..299
@@ -408,7 +409,7 @@ module Anthropic
408
409
  in 300..399
409
410
  self.class.reap_connection!(status, stream: stream)
410
411
 
411
- request = self.class.follow_redirect(request, status: status, response_headers: response)
412
+ request = self.class.follow_redirect(request, status: status, response_headers: headers)
412
413
  send_request(
413
414
  request,
414
415
  redirect_count: redirect_count + 1,
@@ -417,9 +418,9 @@ module Anthropic
417
418
  )
418
419
  in Anthropic::Errors::APIConnectionError if retry_count >= max_retries
419
420
  raise status
420
- in (400..) if retry_count >= max_retries || !self.class.should_retry?(status, headers: response)
421
+ in (400..) if retry_count >= max_retries || !self.class.should_retry?(status, headers: headers)
421
422
  decoded = Kernel.then do
422
- Anthropic::Internal::Util.decode_content(response, stream: stream, suppress_error: true)
423
+ Anthropic::Internal::Util.decode_content(headers, stream: stream, suppress_error: true)
423
424
  ensure
424
425
  self.class.reap_connection!(status, stream: stream)
425
426
  end
@@ -427,6 +428,7 @@ module Anthropic
427
428
  raise Anthropic::Errors::APIStatusError.for(
428
429
  url: url,
429
430
  status: status,
431
+ headers: headers,
430
432
  body: decoded,
431
433
  request: nil,
432
434
  response: response
@@ -503,19 +505,21 @@ module Anthropic
503
505
  send_retry_header: send_retry_header
504
506
  )
505
507
 
506
- decoded = Anthropic::Internal::Util.decode_content(response, stream: stream)
508
+ headers = Anthropic::Internal::Util.normalized_headers(response.each_header.to_h)
509
+ decoded = Anthropic::Internal::Util.decode_content(headers, stream: stream)
507
510
  case req
508
511
  in {stream: Class => st}
509
512
  st.new(
510
513
  model: model,
511
514
  url: url,
512
515
  status: status,
516
+ headers: headers,
513
517
  response: response,
514
518
  unwrap: unwrap,
515
519
  stream: decoded
516
520
  )
517
521
  in {page: Class => page}
518
- page.new(client: self, req: req, headers: response, page_data: decoded)
522
+ page.new(client: self, req: req, headers: headers, page_data: decoded)
519
523
  else
520
524
  unwrapped = Anthropic::Internal::Util.dig(decoded, unwrap)
521
525
  Anthropic::Internal::Type::Converter.coerce(model, unwrapped)
@@ -134,9 +134,9 @@ module Anthropic
134
134
 
135
135
  # rubocop:disable Metrics/BlockLength
136
136
  enum = Enumerator.new do |y|
137
- with_pool(url, deadline: deadline) do |conn|
138
- next if finished
137
+ next if finished
139
138
 
139
+ with_pool(url, deadline: deadline) do |conn|
140
140
  req, closing = self.class.build_request(request) do
141
141
  self.class.calibrate_socket_timeout(conn, deadline)
142
142
  end
@@ -149,7 +149,7 @@ module Anthropic
149
149
 
150
150
  self.class.calibrate_socket_timeout(conn, deadline)
151
151
  conn.request(req) do |rsp|
152
- y << [conn, req, rsp]
152
+ y << [req, rsp]
153
153
  break if finished
154
154
 
155
155
  rsp.read_body do |bytes|
@@ -160,6 +160,8 @@ module Anthropic
160
160
  end
161
161
  eof = true
162
162
  end
163
+ ensure
164
+ conn.finish if !eof && conn&.started?
163
165
  end
164
166
  rescue Timeout::Error
165
167
  raise Anthropic::Errors::APITimeoutError.new(url: url, request: req)
@@ -168,16 +170,11 @@ module Anthropic
168
170
  end
169
171
  # rubocop:enable Metrics/BlockLength
170
172
 
171
- conn, _, response = enum.next
173
+ _, response = enum.next
172
174
  body = Anthropic::Internal::Util.fused_enum(enum, external: true) do
173
175
  finished = true
174
- tap do
175
- enum.next
176
- rescue StopIteration
177
- nil
178
- end
176
+ loop { enum.next }
179
177
  ensure
180
- conn.finish if !eof && conn&.started?
181
178
  closing&.call
182
179
  end
183
180
  [Integer(response.code), response, body]
@@ -39,7 +39,7 @@ module Anthropic
39
39
  #
40
40
  # @param client [Anthropic::Internal::Transport::BaseClient]
41
41
  # @param req [Hash{Symbol=>Object}]
42
- # @param headers [Hash{String=>String}, Net::HTTPHeader]
42
+ # @param headers [Hash{String=>String}]
43
43
  # @param page_data [Object]
44
44
  def initialize(client:, req:, headers:, page_data:)
45
45
  @client = client
@@ -13,20 +13,11 @@ module Anthropic
13
13
  module BaseStream
14
14
  include Enumerable
15
15
 
16
- class << self
17
- # Attempt to close the underlying transport when the stream itself is garbage
18
- # collected.
19
- #
20
- # This should not be relied upon for resource clean up, as the garbage collector
21
- # is not guaranteed to run.
22
- #
23
- # @param stream [Enumerable<Object>]
24
- #
25
- # @return [Proc]
26
- #
27
- # @see https://rubyapi.org/3.2/o/objectspace#method-c-define_finalizer
28
- def defer_closing(stream) = ->(_id) { Anthropic::Internal::Util.close_fused!(stream) }
29
- end
16
+ # @return [Integer]
17
+ attr_reader :status
18
+
19
+ # @return [Hash{String=>String}]
20
+ attr_reader :headers
30
21
 
31
22
  # @api public
32
23
  #
@@ -63,19 +54,19 @@ module Anthropic
63
54
  # @param model [Class, Anthropic::Internal::Type::Converter]
64
55
  # @param url [URI::Generic]
65
56
  # @param status [Integer]
57
+ # @param headers [Hash{String=>String}]
66
58
  # @param response [Net::HTTPResponse]
67
59
  # @param unwrap [Symbol, Integer, Array<Symbol, Integer>, Proc]
68
60
  # @param stream [Enumerable<Object>]
69
- def initialize(model:, url:, status:, response:, unwrap:, stream:)
61
+ def initialize(model:, url:, status:, headers:, response:, unwrap:, stream:)
70
62
  @model = model
71
63
  @url = url
72
64
  @status = status
65
+ @headers = headers
73
66
  @response = response
74
67
  @unwrap = unwrap
75
68
  @stream = stream
76
69
  @iterator = iterator
77
-
78
- ObjectSpace.define_finalizer(self, Anthropic::Internal::Type::BaseStream.defer_closing(@stream))
79
70
  end
80
71
 
81
72
  # @api private
@@ -82,17 +82,20 @@ module Anthropic
82
82
  #
83
83
  # @return [Pathname, StringIO, IO, String, Object]
84
84
  def dump(value, state:)
85
- # rubocop:disable Lint/DuplicateBranch
86
85
  case value
86
+ in StringIO | String
87
+ # https://datatracker.ietf.org/doc/html/rfc7578#section-4.2
88
+ # while not required, a filename is recommended, and in practice many servers do expect this
89
+ Anthropic::FilePart.new(value, filename: "upload")
87
90
  in IO
88
91
  state[:can_retry] = false
92
+ value.to_path.nil? ? Anthropic::FilePart.new(value, filename: "upload") : value
89
93
  in Anthropic::FilePart if value.content.is_a?(IO)
90
94
  state[:can_retry] = false
95
+ value
91
96
  else
97
+ value
92
98
  end
93
- # rubocop:enable Lint/DuplicateBranch
94
-
95
- value
96
99
  end
97
100
 
98
101
  # @api private
@@ -566,6 +566,7 @@ module Anthropic
566
566
  #
567
567
  # @return [Array(String, Enumerable<String>)]
568
568
  private def encode_multipart_streaming(body)
569
+ # RFC 1521 Section 7.2.1 says we should have 70 char maximum for boundary length
569
570
  boundary = SecureRandom.urlsafe_base64(30)
570
571
 
571
572
  closing = []
@@ -647,7 +648,7 @@ module Anthropic
647
648
  #
648
649
  # Assumes each chunk in stream has `Encoding::BINARY`.
649
650
  #
650
- # @param headers [Hash{String=>String}, Net::HTTPHeader]
651
+ # @param headers [Hash{String=>String}]
651
652
  # @param stream [Enumerable<String>]
652
653
  # @param suppress_error [Boolean]
653
654
  #
@@ -37,6 +37,10 @@ module Anthropic
37
37
 
38
38
  variant const: -> { Anthropic::Models::AnthropicBeta::CONTEXT_1M_2025_08_07 }
39
39
 
40
+ variant const: -> { Anthropic::Models::AnthropicBeta::CONTEXT_MANAGEMENT_2025_06_27 }
41
+
42
+ variant const: -> { Anthropic::Models::AnthropicBeta::MODEL_CONTEXT_WINDOW_EXCEEDED_2025_08_26 }
43
+
40
44
  # @!method self.variants
41
45
  # @return [Array(String, Symbol)]
42
46
 
@@ -61,6 +65,8 @@ module Anthropic
61
65
  CODE_EXECUTION_2025_05_22 = :"code-execution-2025-05-22"
62
66
  EXTENDED_CACHE_TTL_2025_04_11 = :"extended-cache-ttl-2025-04-11"
63
67
  CONTEXT_1M_2025_08_07 = :"context-1m-2025-08-07"
68
+ CONTEXT_MANAGEMENT_2025_06_27 = :"context-management-2025-06-27"
69
+ MODEL_CONTEXT_WINDOW_EXCEEDED_2025_08_26 = :"model-context-window-exceeded-2025-08-26"
64
70
 
65
71
  # @!endgroup
66
72
  end