anthropic 1.62.0 → 1.63.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.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -0
  3. data/README.md +1 -1
  4. data/lib/anthropic/client.rb +13 -3
  5. data/lib/anthropic/errors.rb +6 -0
  6. data/lib/anthropic/helpers/aws/client.rb +9 -17
  7. data/lib/anthropic/helpers/aws_auth.rb +13 -2
  8. data/lib/anthropic/helpers/bedrock/client.rb +2 -13
  9. data/lib/anthropic/helpers/bedrock/mantle_client.rb +0 -10
  10. data/lib/anthropic/helpers/google_cloud/client.rb +16 -27
  11. data/lib/anthropic/helpers/messages.rb +18 -12
  12. data/lib/anthropic/helpers/tools/base_tool.rb +69 -10
  13. data/lib/anthropic/helpers/tools/mcp.rb +2 -2
  14. data/lib/anthropic/helpers/tools/runner.rb +33 -19
  15. data/lib/anthropic/helpers/vertex/client.rb +14 -13
  16. data/lib/anthropic/internal/type/base_stream.rb +10 -0
  17. data/lib/anthropic/models/anthropic_beta.rb +3 -0
  18. data/lib/anthropic/models/beta/agent_create_params.rb +2 -2
  19. data/lib/anthropic/models/beta/agent_update_params.rb +2 -2
  20. data/lib/anthropic/models/beta/beta_content_block_param.rb +3 -11
  21. data/lib/anthropic/models/beta/beta_dream_model_config.rb +2 -2
  22. data/lib/anthropic/models/beta/beta_dream_model_config_param.rb +2 -2
  23. data/lib/anthropic/models/beta/beta_environment.rb +4 -4
  24. data/lib/anthropic/models/beta/beta_managed_agents_agent_with_overrides_params.rb +3 -3
  25. data/lib/anthropic/models/beta/beta_message_param.rb +3 -3
  26. data/lib/anthropic/models/beta/beta_user_profile.rb +54 -24
  27. data/lib/anthropic/models/beta/environment_update_params.rb +3 -2
  28. data/lib/anthropic/models/beta/memory_stores/beta_managed_agents_actor.rb +9 -2
  29. data/lib/anthropic/models/beta/memory_stores/beta_managed_agents_memory_version.rb +4 -4
  30. data/lib/anthropic/models/beta/memory_stores/beta_managed_agents_service_account_actor.rb +30 -0
  31. data/lib/anthropic/models/beta/memory_stores/memory_version_list_params.rb +9 -1
  32. data/lib/anthropic/models/beta/user_profile_create_params.rb +31 -3
  33. data/lib/anthropic/models/beta/user_profile_update_params.rb +28 -1
  34. data/lib/anthropic/models/content_block_param.rb +2 -10
  35. data/lib/anthropic/models/message_param.rb +3 -3
  36. data/lib/anthropic/models.rb +0 -2
  37. data/lib/anthropic/resources/beta/environments.rb +1 -1
  38. data/lib/anthropic/resources/beta/memory_stores/memory_versions.rb +4 -1
  39. data/lib/anthropic/resources/beta/user_profiles.rb +11 -7
  40. data/lib/anthropic/version.rb +1 -1
  41. data/lib/anthropic.rb +1 -2
  42. data/rbi/anthropic/errors.rbi +8 -0
  43. data/rbi/anthropic/helpers/bedrock/client.rbi +0 -4
  44. data/rbi/anthropic/helpers/bedrock/mantle_client.rbi +0 -4
  45. data/rbi/anthropic/helpers/google_cloud/client.rbi +5 -9
  46. data/rbi/anthropic/helpers/tools/base_tool.rbi +17 -0
  47. data/rbi/anthropic/internal/type/base_stream.rbi +8 -0
  48. data/rbi/anthropic/models/anthropic_beta.rbi +5 -0
  49. data/rbi/anthropic/models/beta/agent_create_params.rbi +3 -3
  50. data/rbi/anthropic/models/beta/agent_update_params.rbi +3 -3
  51. data/rbi/anthropic/models/beta/beta_content_block_param.rbi +1 -9
  52. data/rbi/anthropic/models/beta/beta_dream_model_config.rbi +2 -2
  53. data/rbi/anthropic/models/beta/beta_dream_model_config_param.rbi +2 -2
  54. data/rbi/anthropic/models/beta/beta_environment.rbi +5 -5
  55. data/rbi/anthropic/models/beta/beta_managed_agents_agent_with_overrides_params.rbi +3 -3
  56. data/rbi/anthropic/models/beta/beta_user_profile.rbi +123 -43
  57. data/rbi/anthropic/models/beta/environment_update_params.rbi +4 -2
  58. data/rbi/anthropic/models/beta/memory_stores/beta_managed_agents_actor.rbi +7 -3
  59. data/rbi/anthropic/models/beta/memory_stores/beta_managed_agents_memory_version.rbi +8 -4
  60. data/rbi/anthropic/models/beta/memory_stores/beta_managed_agents_service_account_actor.rbi +44 -0
  61. data/rbi/anthropic/models/beta/memory_stores/memory_version_list_params.rbi +11 -0
  62. data/rbi/anthropic/models/beta/user_profile_create_params.rbi +77 -4
  63. data/rbi/anthropic/models/beta/user_profile_update_params.rbi +67 -0
  64. data/rbi/anthropic/models/content_block_param.rbi +1 -2
  65. data/rbi/anthropic/models.rbi +0 -3
  66. data/rbi/anthropic/resources/beta/agents.rbi +2 -2
  67. data/rbi/anthropic/resources/beta/environments.rbi +2 -1
  68. data/rbi/anthropic/resources/beta/memory_stores/memory_versions.rbi +3 -0
  69. data/rbi/anthropic/resources/beta/user_profiles.rbi +21 -2
  70. data/sig/anthropic/errors.rbs +4 -0
  71. data/sig/anthropic/helpers/bedrock/client.rbs +0 -2
  72. data/sig/anthropic/helpers/google_cloud/client.rbs +2 -6
  73. data/sig/anthropic/internal/type/base_stream.rbs +4 -0
  74. data/sig/anthropic/models/anthropic_beta.rbs +2 -0
  75. data/sig/anthropic/models/beta/beta_content_block_param.rbs +1 -8
  76. data/sig/anthropic/models/beta/beta_environment.rbs +4 -4
  77. data/sig/anthropic/models/beta/beta_user_profile.rbs +42 -18
  78. data/sig/anthropic/models/beta/memory_stores/beta_managed_agents_actor.rbs +7 -1
  79. data/sig/anthropic/models/beta/memory_stores/beta_managed_agents_service_account_actor.rbs +26 -0
  80. data/sig/anthropic/models/beta/memory_stores/memory_version_list_params.rbs +7 -0
  81. data/sig/anthropic/models/beta/user_profile_create_params.rbs +20 -0
  82. data/sig/anthropic/models/beta/user_profile_update_params.rbs +16 -0
  83. data/sig/anthropic/models/content_block_param.rbs +0 -6
  84. data/sig/anthropic/models.rbs +0 -2
  85. data/sig/anthropic/resources/beta/memory_stores/memory_versions.rbs +1 -0
  86. data/sig/anthropic/resources/beta/user_profiles.rbs +2 -0
  87. metadata +5 -8
  88. data/lib/anthropic/models/beta/beta_mid_conversation_system_block_param.rb +0 -105
  89. data/lib/anthropic/models/mid_conversation_system_block_param.rb +0 -37
  90. data/rbi/anthropic/models/beta/beta_mid_conversation_system_block_param.rbi +0 -168
  91. data/rbi/anthropic/models/mid_conversation_system_block_param.rbi +0 -66
  92. data/sig/anthropic/models/beta/beta_mid_conversation_system_block_param.rbs +0 -71
  93. data/sig/anthropic/models/mid_conversation_system_block_param.rbs +0 -30
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 68e6d71ef0a8a1c6dba5ce56ca4c950073401b65fe3311ff8b305bb50f3e1895
4
- data.tar.gz: ed43b20d2eb03cc4f7651213e403bb1eedd4ef682304524d82c535a9a04d680c
3
+ metadata.gz: e9a5ec69ebe4f2fe1d743013098cb879401a601825c244fdb587b36c055ebfc5
4
+ data.tar.gz: de874bbfc686b83f328bccdc1a95f8a4e5211ad6f73895d4f117ffd9e6faf260
5
5
  SHA512:
6
- metadata.gz: 211153854d618da94e0d1c6cc4a7f8a28b4cbb6982df843301c293167115c12b4dcabea8ba618871150ba9cdebab08c4a6a17b0db164035ed907a54537713e16
7
- data.tar.gz: 4df9827fe320d1f15bbdbcbfbcf2d77865506001d2b64314de497161700763fa86b500d9a114c7a8e1cb23d1a439aa0deef53e6ed16916da2e4d76ef7276fcff
6
+ metadata.gz: 79022be4b042788f7586f77a3ab32f3036bd82733505afbe387aae2f709e3db1de135ab2de906f561915a417aa73c19576c8564c7ba1632e746b620ec358b8e4
7
+ data.tar.gz: cd8af8f0f3577f4558b8126607b2de05bd994584fe549792af7434eb7b791f25eda4ead4ea583b233b3bf73c2f07ed4f03ebf21338dd55af1a33bee77dd150e5
data/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.63.0 (2026-08-18)
4
+
5
+ Full Changelog: [v1.62.0...v1.63.0](https://github.com/anthropics/anthropic-sdk-ruby/compare/v1.62.0...v1.63.0)
6
+
7
+ ### Features
8
+
9
+ * **api:** additions to files and memory stores ([f4baf57](https://github.com/anthropics/anthropic-sdk-ruby/commit/f4baf57eaf96b098ec63c895c84c701294583240))
10
+ * **api:** updates to skill, files, and user profiles ([ba0844b](https://github.com/anthropics/anthropic-sdk-ruby/commit/ba0844b290a2036cba7c0a79e500497d48096c5f))
11
+ * **tools:** add `tool_options` to `BaseTool` (strict, cache_control, …) ([#161](https://github.com/anthropics/anthropic-sdk-ruby/issues/161)) ([df278f9](https://github.com/anthropics/anthropic-sdk-ruby/commit/df278f9170ce5ff130433602b18470248dcfa3f4))
12
+
13
+
14
+ ### Bug Fixes
15
+
16
+ * **api:** remove unsupported mid_conv_system content block ([687a6da](https://github.com/anthropics/anthropic-sdk-ruby/commit/687a6da56fe9cb85753f6a819d7978580bed61c9))
17
+ * **aws,google_cloud:** adopt the default-credentials hook in the AWS and Google Cloud clients ([#170](https://github.com/anthropics/anthropic-sdk-ruby/issues/170)) ([169fea9](https://github.com/anthropics/anthropic-sdk-ruby/commit/169fea9f5ef8d0798bc0e795e0579eae367939e2))
18
+ * **client:** never fall back to the first-party base URL when default credentials are disabled ([#193](https://github.com/anthropics/anthropic-sdk-ruby/issues/193)) ([b6e9f56](https://github.com/anthropics/anthropic-sdk-ruby/commit/b6e9f562c2872dc5f3ca3a4d6c4025e0e75397d1))
19
+ * **tool-runner:** forward the server-assigned container on follow-up requests ([#189](https://github.com/anthropics/anthropic-sdk-ruby/issues/189)) ([891ac9b](https://github.com/anthropics/anthropic-sdk-ruby/commit/891ac9b8f12234bfe6938086937505e27175df46))
20
+ * **tool-runner:** replay unknown tool_use input verbatim ([#173](https://github.com/anthropics/anthropic-sdk-ruby/issues/173)) ([566a881](https://github.com/anthropics/anthropic-sdk-ruby/commit/566a8817fbe8aad5a25b4111021e39d20451ef03))
21
+ * **tool-runner:** stop on refusal instead of executing tools ([#174](https://github.com/anthropics/anthropic-sdk-ruby/issues/174)) ([4b8d2e4](https://github.com/anthropics/anthropic-sdk-ruby/commit/4b8d2e43265d31b55eb9a6f0d3241b62fa510b2d))
22
+
23
+
24
+ ### Chores
25
+
26
+ * **internal:** remove leftover prism references ([5a416d3](https://github.com/anthropics/anthropic-sdk-ruby/commit/5a416d3f2c784d697a8f9fbc99f5620102ea0c84))
27
+
3
28
  ## 1.62.0 (2026-08-13)
4
29
 
5
30
  Full Changelog: [v1.61.0...v1.62.0](https://github.com/anthropics/anthropic-sdk-ruby/compare/v1.61.0...v1.62.0)
data/README.md CHANGED
@@ -15,7 +15,7 @@ Add to your application's Gemfile:
15
15
  <!-- x-release-please-start-version -->
16
16
 
17
17
  ```ruby
18
- gem "anthropic", "~> 1.62.0"
18
+ gem "anthropic", "~> 1.63.0"
19
19
  ```
20
20
 
21
21
  <!-- x-release-please-end -->
@@ -208,7 +208,7 @@ module Anthropic
208
208
  @token_cache = nil
209
209
 
210
210
  base_url_is_explicit = base_url && !base_url.empty?
211
- base_url ||= ENV["ANTHROPIC_BASE_URL"]
211
+ base_url ||= ENV["ANTHROPIC_BASE_URL"] if resolve_default_credentials?
212
212
 
213
213
  credential_headers = {}
214
214
 
@@ -240,7 +240,14 @@ module Anthropic
240
240
  @token_cache = Anthropic::Credentials::TokenCache.new(@credentials)
241
241
  end
242
242
 
243
- base_url ||= "https://api.anthropic.com"
243
+ if resolve_default_credentials?
244
+ base_url ||= "https://api.anthropic.com"
245
+ elsif base_url.to_s.empty?
246
+ raise ArgumentError.new(
247
+ "No base_url was resolved for #{self.class.name}; " \
248
+ "platform clients must supply their own endpoint."
249
+ )
250
+ end
244
251
 
245
252
  if @credentials.respond_to?(:bind_base_url)
246
253
  @credentials.bind_base_url(base_url)
@@ -304,7 +311,10 @@ module Anthropic
304
311
  # {#initialize}, so overrides must not depend on subclass instance state.
305
312
  # Subclasses that bring their own auth scheme override this to +false+ so
306
313
  # ambient first-party credentials are never resolved or folded into
307
- # requests bound for another platform's endpoint.
314
+ # requests bound for another platform's endpoint. Returning +false+ also
315
+ # withholds the +ANTHROPIC_BASE_URL+ / +https://api.anthropic.com+
316
+ # base-URL fallback, so such a subclass must pass its own +base_url+ or
317
+ # {#initialize} raises +ArgumentError+.
308
318
  #
309
319
  # @return [Boolean]
310
320
  def resolve_default_credentials? = true
@@ -60,6 +60,12 @@ module Anthropic
60
60
  # @return [Object, nil]
61
61
  attr_accessor :body
62
62
 
63
+ # @return [String, nil]
64
+ def request_id = headers&.[]("request-id")
65
+
66
+ # @return [String, nil]
67
+ def workspace_id = headers&.[]("anthropic-workspace-id")
68
+
63
69
  # @api private
64
70
  #
65
71
  # @param url [URI::Generic]
@@ -53,7 +53,7 @@ module Anthropic
53
53
  #
54
54
  # @param max_retry_delay [Float]
55
55
  #
56
- def initialize( # rubocop:disable Lint/MissingSuper
56
+ def initialize(
57
57
  api_key: nil,
58
58
  aws_access_key: nil,
59
59
  aws_secret_access_key: nil,
@@ -84,27 +84,19 @@ module Anthropic
84
84
  derive_base_url: ->(region) { "https://aws-external-anthropic.#{region}.api.aws" }
85
85
  )
86
86
 
87
- @api_key = effective_api_key
88
- @auth_token = nil
89
- @credentials = nil
90
- @token_cache = nil
91
-
92
- # Skip Anthropic::Client#initialize and bind BaseClient#initialize directly:
93
- # the parent's initializer runs OIDC/credential-provider resolution that does
94
- # not apply here.
95
- Anthropic::Internal::Transport::BaseClient.instance_method(:initialize).bind(self).call(
87
+ # In API-key mode the gateway key rides the base client's `api_key`
88
+ # slot; {#resolve_default_credentials?} keeps first-party credential
89
+ # auto-discovery out of the picture when it is absent. The gateway
90
+ # serves the full first-party API, so every resource the parent wires
91
+ # up stays available.
92
+ super(
93
+ api_key: effective_api_key,
96
94
  base_url: resolved_base_url,
97
95
  timeout: timeout,
98
96
  max_retries: max_retries,
99
97
  initial_retry_delay: initial_retry_delay,
100
- max_retry_delay: max_retry_delay,
101
- headers: {"anthropic-version" => "2023-06-01"}
98
+ max_retry_delay: max_retry_delay
102
99
  )
103
-
104
- @completions = Anthropic::Resources::Completions.new(client: self)
105
- @messages = Anthropic::Resources::Messages.new(client: self)
106
- @models = Anthropic::Resources::Models.new(client: self)
107
- @beta = Anthropic::Resources::Beta.new(client: self)
108
100
  end
109
101
 
110
102
  # @api private
@@ -44,6 +44,7 @@ module Anthropic
44
44
  use_bearer_auth: false
45
45
  )
46
46
  @use_bearer_auth = use_bearer_auth
47
+ base_url = nil if base_url.to_s.empty?
47
48
  begin
48
49
  require("aws-sdk-core")
49
50
  rescue LoadError
@@ -119,12 +120,12 @@ module Anthropic
119
120
  end
120
121
  end
121
122
 
122
- if base_url.nil? && !aws_region.to_s.empty?
123
+ if !base_url && !aws_region.to_s.empty?
123
124
  @aws_region ||= aws_region
124
125
  base_url = derive_base_url.call(aws_region)
125
126
  end
126
127
 
127
- if base_url.nil?
128
+ unless base_url
128
129
  # rubocop:disable Layout/LineLength
129
130
  raise ArgumentError.new("No base_url was given and no aws_region is available to derive one. Set the `base_url` argument or provide an `aws_region`.")
130
131
  # rubocop:enable Layout/LineLength
@@ -147,6 +148,16 @@ module Anthropic
147
148
  super
148
149
  end
149
150
 
151
+ # @api private
152
+ #
153
+ # AWS-authenticated clients never resolve ambient first-party
154
+ # credentials, which would fold the shared config store's headers and
155
+ # bearer into requests bound for a third-party endpoint.
156
+ #
157
+ # @return [Boolean]
158
+ # @see Anthropic::Client#resolve_default_credentials?
159
+ private def resolve_default_credentials? = false
160
+
150
161
  # The AWS provider middleware entry: applies the workspace-id header and
151
162
  # SigV4 signing per attempt. Return from the including class's
152
163
  # `provider_middleware`. Pure — requests are reused across retry
@@ -121,10 +121,8 @@ module Anthropic
121
121
  @aws_region = aws_region
122
122
  end
123
123
 
124
- base_url ||= ENV.fetch(
125
- "ANTHROPIC_BEDROCK_BASE_URL",
126
- "https://bedrock-runtime.#{@aws_region}.amazonaws.com"
127
- )
124
+ base_url = ENV["ANTHROPIC_BEDROCK_BASE_URL"] if base_url.to_s.empty?
125
+ base_url = "https://bedrock-runtime.#{@aws_region}.amazonaws.com" if base_url.to_s.empty?
128
126
 
129
127
  # For AWSAuth#auth_headers: suppress key headers in SigV4 mode; in
130
128
  # API-key mode fall through to the base bearer-token handling.
@@ -145,15 +143,6 @@ module Anthropic
145
143
  )
146
144
  end
147
145
 
148
- # @api private
149
- #
150
- # Auth is SigV4 or the Bedrock bearer only — never resolve ambient
151
- # first-party credentials, which would fold the shared config store's
152
- # headers and bearer into requests bound for a third-party endpoint.
153
- #
154
- # @return [Boolean]
155
- private def resolve_default_credentials? = false
156
-
157
146
  # The Models API is not available on Bedrock, so the resource the
158
147
  # parent wires up would target routes the Bedrock host does not serve
159
148
  # — keep it unavailable, matching the SDK's other Bedrock clients.
@@ -113,16 +113,6 @@ module Anthropic
113
113
  "Models listing is not supported on Bedrock Mantle. Only Messages (/v1/messages) is supported."
114
114
  end
115
115
 
116
- # @api private
117
- #
118
- # Auth is SigV4 or the Bedrock bearer only (or skipped entirely) —
119
- # never resolve ambient first-party credentials, which would fold the
120
- # shared config store's headers and bearer into requests bound for a
121
- # third-party endpoint.
122
- #
123
- # @return [Boolean]
124
- private def resolve_default_credentials? = false
125
-
126
116
  # @api private
127
117
  #
128
118
  # @return [#call]
@@ -31,15 +31,6 @@ module Anthropic
31
31
  # @return [String, nil]
32
32
  attr_reader :workspace_id
33
33
 
34
- # @return [Anthropic::Resources::Messages]
35
- attr_reader :messages
36
-
37
- # @return [Anthropic::Resources::Models]
38
- attr_reader :models
39
-
40
- # @return [Anthropic::Resources::Beta]
41
- attr_reader :beta
42
-
43
34
  # Creates a new client for the Anthropic API on the Google Cloud gateway.
44
35
  #
45
36
  # Authentication uses Google credentials by precedence (unless
@@ -95,7 +86,7 @@ module Anthropic
95
86
  # is applied per attempt, after user middleware.
96
87
  #
97
88
  # @raise [ArgumentError]
98
- def initialize( # rubocop:disable Lint/MissingSuper
89
+ def initialize(
99
90
  project: ENV["ANTHROPIC_GOOGLE_CLOUD_PROJECT"] || ENV["GOOGLE_CLOUD_PROJECT"],
100
91
  location: ENV["ANTHROPIC_GOOGLE_CLOUD_LOCATION"] || "global",
101
92
  workspace_id: ENV["ANTHROPIC_GOOGLE_CLOUD_WORKSPACE_ID"],
@@ -144,33 +135,31 @@ module Anthropic
144
135
  end
145
136
  @workspace_id = workspace_id
146
137
 
147
- base_url = derive_base_url if base_url.nil?
148
-
149
- # Never inherit first-party Anthropic credentials from the
150
- # environment: clear the ivars `Anthropic::Client#auth_headers` reads,
151
- # and bind `BaseClient#initialize` directly so the parent's
152
- # credential-provider / `ANTHROPIC_BASE_URL` resolution is skipped
153
- # entirely.
154
- @api_key = nil
155
- @auth_token = nil
156
- @credentials = nil
157
- @token_cache = nil
138
+ base_url = nil if base_url.to_s.empty?
139
+ base_url ||= derive_base_url
158
140
 
159
- Anthropic::Internal::Transport::BaseClient.instance_method(:initialize).bind(self).call(
141
+ # No first-party credential is ever passed up, and
142
+ # {#resolve_default_credentials?} keeps the parent from discovering
143
+ # one; `base_url` is always resolved by this point, so the parent's
144
+ # `ANTHROPIC_BASE_URL` fallback never applies. The parent wires up
145
+ # every resource; {#completions} withholds the one the gateway does
146
+ # not serve.
147
+ super(
160
148
  base_url: base_url,
161
149
  timeout: timeout,
162
150
  max_retries: max_retries,
163
151
  initial_retry_delay: initial_retry_delay,
164
152
  max_retry_delay: max_retry_delay,
165
- headers: {"anthropic-version" => "2023-06-01"},
166
153
  middleware: middleware
167
154
  )
168
-
169
- @messages = Anthropic::Resources::Messages.new(client: self)
170
- @models = Anthropic::Resources::Models.new(client: self)
171
- @beta = Anthropic::Resources::Beta.new(client: self)
172
155
  end
173
156
 
157
+ # @api private
158
+ #
159
+ # @return [Boolean]
160
+ # @see Anthropic::Client#resolve_default_credentials?
161
+ private def resolve_default_credentials? = false
162
+
174
163
  # The deprecated text Completions endpoint is not supported on the
175
164
  # Google Cloud gateway.
176
165
  #
@@ -38,26 +38,27 @@ module Anthropic
38
38
  # rubocop:disable Metrics/BlockLength
39
39
  mapped = tool_array.map do |tool|
40
40
  case tool
41
- # BaseTool whose class declares an explicit `tool_name` (e.g. MCP-built tools):
42
- in Anthropic::Helpers::Tools::BaseTool if tool.class.tool_name
41
+ # Runnable tool instance (an `Anthropic::BaseTool` subclass, hand-written or helper-built):
42
+ in Anthropic::Helpers::Tools::BaseTool
43
43
  name = tool_api_name(tool)
44
+ # Helper-built tools (e.g. MCP) declare an explicit `tool_name` and only send the
45
+ # description they were given; hand-written tools fall back to their name.
44
46
  description = tool.class.doc_string
47
+ description ||= name unless tool.class.tool_name
45
48
  tools.store(name, tool)
46
49
  input_schema = Anthropic::Helpers::InputSchema::JsonSchemaConverter.to_json_schema(tool)
47
- extras = tool.class.tool_extra_props || {}
48
- result = {name:, input_schema:, **extras}
49
- result[:description] = description if description
50
- result[:strict] = strict if strict
51
- result
52
- # Direct tool class:
50
+ # On a clash the derived keys win, so nothing in `tool_options` can shadow them.
51
+ definition =
52
+ {name:, description:, input_schema:}
53
+ .merge(tool.class.tool_options) { |_key, derived, _option| derived }
54
+ .compact
55
+ definition.tap { _1.update(strict:) if strict }
56
+ # Input schema class used directly as a tool:
53
57
  in Anthropic::Helpers::InputSchema::JsonSchemaConverter
54
- name =
55
- tool.is_a?(Anthropic::Helpers::Tools::BaseTool) ? tool_api_name(tool) : model_name(tool.name)
58
+ name = model_name(tool.name)
56
59
 
57
60
  description =
58
61
  case tool
59
- in Anthropic::Helpers::Tools::BaseTool
60
- tool.class.doc_string || name
61
62
  in Class if tool <= Anthropic::Helpers::InputSchema::BaseModel
62
63
  tool.doc_string || name
63
64
  else
@@ -82,6 +83,11 @@ module Anthropic
82
83
  end
83
84
  # rubocop:enable Metrics/BlockLength
84
85
  tool_array.replace(mapped)
86
+ else
87
+ end
88
+
89
+ # Matched separately from `tools:` so a request can carry both tools and a structured output format.
90
+ case data
85
91
  # GA: output_config with BaseModel class as format
86
92
  in {output_config: {format: Anthropic::Helpers::InputSchema::JsonSchemaConverter => model} => output_config}
87
93
  name = model_name(model.name)
@@ -25,15 +25,6 @@ module Anthropic
25
25
  # @return [String, nil]
26
26
  attr_accessor :tool_name
27
27
 
28
- # @api private
29
- #
30
- # Extra tool-definition properties merged into the API payload (e.g.
31
- # `cache_control`, `defer_loading`, `allowed_callers`, `eager_input_streaming`,
32
- # `input_examples`, `strict`).
33
- #
34
- # @return [Hash{Symbol=>Object}, nil]
35
- attr_accessor :tool_extra_props
36
-
37
28
  # @api public
38
29
  #
39
30
  # @param description [String]
@@ -46,10 +37,78 @@ module Anthropic
46
37
  # @model [Class<Anthropic::Helpers::InputSchema::BaseModel>]
47
38
  def input_schema(model) = (@model = model)
48
39
 
40
+ # @api public
41
+ #
42
+ # Declares additional properties for this tool's API definition, sent alongside the
43
+ # `name`, `description` and `input_schema` — e.g. `strict`, `cache_control`,
44
+ # `defer_loading`, `allowed_callers`, `eager_input_streaming` or `input_examples`.
45
+ #
46
+ # Options accumulate: each call merges into what was already declared, and a subclass
47
+ # starts from its superclass's options. Called without an argument, returns the declared
48
+ # options as a frozen hash.
49
+ #
50
+ # @example
51
+ # class GetWeather < Anthropic::BaseTool
52
+ # doc "Get the current weather in a given location"
53
+ # input_schema GetWeatherInput
54
+ # tool_options strict: true, cache_control: {type: :ephemeral}
55
+ # end
56
+ #
57
+ # @param options [Hash{Symbol=>Object}, nil]
58
+ #
59
+ # @return [Hash{Symbol=>Object}]
60
+ def tool_options(options = nil)
61
+ if options.nil?
62
+ return @tool_options if @tool_options
63
+
64
+ # Nothing declared on this class: read through to the superclass (`BaseTool` has none).
65
+ return superclass.respond_to?(:tool_options) ? superclass.tool_options : {}.freeze
66
+ end
67
+
68
+ options = Anthropic::Internal::Util.coerce_hash!(options).to_h.transform_keys(&:to_sym)
69
+ # These either have their own declaration or are derived from the class; letting them
70
+ # through would desync the definition sent to the API from how responses are parsed.
71
+ reserved = options.keys & [:name, :description, :input_schema]
72
+ unless reserved.empty?
73
+ message =
74
+ "#{reserved.map { "`#{_1}`" }.join(', ')} cannot be set through `tool_options`; " \
75
+ "use `doc` and `input_schema` instead (the tool name is derived from the class name)."
76
+ raise ArgumentError.new(message)
77
+ end
78
+
79
+ # Frozen so the stored declaration can't drift from what was validated above.
80
+ @tool_options = Anthropic::Internal::Util.deep_frozen_copy(tool_options.merge(options))
81
+ end
82
+
83
+ # @api private
84
+ #
85
+ # @deprecated Use {.tool_options}.
86
+ #
87
+ # @return [Hash{Symbol=>Object}]
88
+ def tool_extra_props = tool_options
89
+
90
+ # @api private
91
+ #
92
+ # @deprecated Use {.tool_options}.
93
+ #
94
+ # @param props [Hash{Symbol=>Object}, nil]
95
+ def tool_extra_props=(props)
96
+ warn(
97
+ "[DEPRECATION] `tool_extra_props=` is deprecated. Use `tool_options` instead.",
98
+ category: :deprecated
99
+ )
100
+ tool_options(props.to_h)
101
+ end
102
+
49
103
  # @api private
50
104
  #
51
105
  # @param depth [Integer]
52
- def inspect(depth: 0) = "#{name}[#{model.inspect(depth:)}]"
106
+ def inspect(depth: 0)
107
+ # Only hand-written tools carry an input schema class here; helper-built tools (e.g. MCP)
108
+ # hold a plain class and an undeclared schema is nil, neither of which takes `depth:`.
109
+ schema = model.is_a?(Anthropic::Internal::Type::Converter) ? model.inspect(depth:) : model.inspect
110
+ "#{name || tool_name}[#{schema}]"
111
+ end
53
112
  end
54
113
 
55
114
  # @api private
@@ -61,7 +61,7 @@ module Anthropic
61
61
  api_name, description, raw_schema = Mcp.send(:extract_tool_fields, mcp_tool)
62
62
  raise ArgumentError, "MCP tool is missing a `name`" if api_name.to_s.empty?
63
63
 
64
- extras = {
64
+ options = {
65
65
  cache_control: cache_control,
66
66
  defer_loading: defer_loading,
67
67
  allowed_callers: allowed_callers,
@@ -75,7 +75,7 @@ module Anthropic
75
75
  klass = Class.new(self)
76
76
  klass.description(description) if description
77
77
  klass.tool_name = api_name
78
- klass.tool_extra_props = extras
78
+ klass.tool_options(options)
79
79
  klass.mcp_input_schema = Mcp.send(:normalize_schema, raw_schema)
80
80
  klass.mcp_client = mcp_client
81
81
  klass.instance_variable_set(:@model, input_class)
@@ -92,6 +92,14 @@ module Anthropic
92
92
  next unless current_messages.equal?(messages)
93
93
  break if compacted
94
94
 
95
+ # Refusal-terminated turns are terminal: executing their tool_use blocks would fire
96
+ # side effects the model never confirmed, and the resulting tool_results could not be
97
+ # replayed coherently. Surface the refusal as the final message instead.
98
+ if response.stop_reason == :refusal
99
+ @finished = true
100
+ break
101
+ end
102
+
95
103
  # A `tool_removal` block only hints the model, so a call to a withdrawn tool can still
96
104
  # arrive; a name missing from this set routes down the same "not found" path as an
97
105
  # undeclared tool.
@@ -130,7 +138,10 @@ module Anthropic
130
138
  content = response.content.map do
131
139
  case _1
132
140
  in Anthropic::Beta::BetaToolUseBlock
133
- raw = {**_1, input: _1.parsed}.except(:parsed)
141
+ # `parsed` is only set for calls to a declared tool; any other call (e.g. to an
142
+ # unregistered tool) must replay the `input` the API sent, never a null.
143
+ input = _1.parsed.nil? ? _1.input : _1.parsed
144
+ raw = {**_1, input:}.except(:parsed)
134
145
  Anthropic::Internal::Type::Converter.dump(Anthropic::Beta::BetaToolUseBlock, raw)
135
146
  else
136
147
  _1
@@ -139,6 +150,7 @@ module Anthropic
139
150
 
140
151
  messages << {role: :assistant, content:}
141
152
  messages << {role: :user, content: mapped}
153
+ adopt_container(response)
142
154
 
143
155
  @iteration_count += 1
144
156
 
@@ -148,6 +160,26 @@ module Anthropic
148
160
  # rubocop:enable Metrics/BlockLength
149
161
  end
150
162
 
163
+ # @api private
164
+ #
165
+ # Container-bound server tools reject a follow-up that drops the container the previous
166
+ # turn ran in, so its id is forwarded unless the caller pinned one themselves.
167
+ #
168
+ # @param response [Anthropic::Models::BetaMessage]
169
+ private def adopt_container(response)
170
+ id = response.container&.id
171
+ return if id.nil? || id.empty?
172
+
173
+ case (pinned = params[:container])
174
+ in nil
175
+ params[:container] = id
176
+ in Hash | Anthropic::Beta::BetaContainerParams if read_field(pinned, :id).nil?
177
+ params[:container] = {**pinned, id:}
178
+ else
179
+ nil
180
+ end
181
+ end
182
+
151
183
  # @api private
152
184
  #
153
185
  # Replays `tool_removal` / `tool_addition` blocks from `role: :system` messages to
@@ -175,24 +207,6 @@ module Anthropic
175
207
  #
176
208
  # @param available [Set<String>]
177
209
  private def apply_tool_change(block, available)
178
- case read_field(block, :type)&.to_sym
179
- in :tool_removal | :tool_addition
180
- apply_tool_delta(block, available)
181
- in :mid_conv_system
182
- # `mid_conv_system` content is limited by the API schema to text / tool_addition /
183
- # tool_removal blocks, so exactly one level is walked; anything else inside is a no-op.
184
- Array(read_field(block, :content)).each { apply_tool_delta(_1, available) }
185
- else
186
- nil # other and unknown block types leave the set untouched (forward compatibility)
187
- end
188
- end
189
-
190
- # @api private
191
- #
192
- # @param block [Anthropic::Beta::BetaContentBlockParam, Hash{Symbol=>Object}]
193
- #
194
- # @param available [Set<String>]
195
- private def apply_tool_delta(block, available)
196
210
  case read_field(block, :type)&.to_sym
197
211
  in :tool_removal
198
212
  name = referenced_tool_name(read_field(block, :tool))
@@ -89,19 +89,20 @@ module Anthropic
89
89
  @project_id = project_id
90
90
  @authorization = nil
91
91
 
92
- base_url ||= ENV.fetch(
93
- "ANTHROPIC_VERTEX_BASE_URL",
94
- case @region.to_s
95
- when "global"
96
- "https://aiplatform.googleapis.com/v1"
97
- when "us"
98
- "https://aiplatform.us.rep.googleapis.com/v1"
99
- when "eu"
100
- "https://aiplatform.eu.rep.googleapis.com/v1"
101
- else
102
- "https://#{@region}-aiplatform.googleapis.com/v1"
103
- end
104
- )
92
+ base_url = ENV["ANTHROPIC_VERTEX_BASE_URL"] if base_url.to_s.empty?
93
+ if base_url.to_s.empty?
94
+ base_url =
95
+ case @region.to_s
96
+ when "global"
97
+ "https://aiplatform.googleapis.com/v1"
98
+ when "us"
99
+ "https://aiplatform.us.rep.googleapis.com/v1"
100
+ when "eu"
101
+ "https://aiplatform.eu.rep.googleapis.com/v1"
102
+ else
103
+ "https://#{@region}-aiplatform.googleapis.com/v1"
104
+ end
105
+ end
105
106
 
106
107
  super(
107
108
  base_url: base_url,
@@ -19,6 +19,16 @@ module Anthropic
19
19
  # @return [Hash{String=>String}]
20
20
  attr_reader :headers
21
21
 
22
+ # @api public
23
+ #
24
+ # @return [String, nil]
25
+ def request_id = headers["request-id"]
26
+
27
+ # @api public
28
+ #
29
+ # @return [String, nil]
30
+ def workspace_id = headers["anthropic-workspace-id"]
31
+
22
32
  # @api public
23
33
  #
24
34
  # @return [void]
@@ -51,6 +51,8 @@ module Anthropic
51
51
 
52
52
  variant const: -> { Anthropic::Models::AnthropicBeta::USER_PROFILES_2026_03_24 }
53
53
 
54
+ variant const: -> { Anthropic::Models::AnthropicBeta::USER_PROFILES_2026_08_18 }
55
+
54
56
  variant const: -> { Anthropic::Models::AnthropicBeta::ADVISOR_TOOL_2026_03_01 }
55
57
 
56
58
  variant const: -> { Anthropic::Models::AnthropicBeta::MANAGED_AGENTS_2026_04_01 }
@@ -104,6 +106,7 @@ module Anthropic
104
106
  FAST_MODE_2026_02_01 = :"fast-mode-2026-02-01"
105
107
  OUTPUT_300K_2026_03_24 = :"output-300k-2026-03-24"
106
108
  USER_PROFILES_2026_03_24 = :"user-profiles-2026-03-24"
109
+ USER_PROFILES_2026_08_18 = :"user-profiles-2026-08-18"
107
110
  ADVISOR_TOOL_2026_03_01 = :"advisor-tool-2026-03-01"
108
111
  MANAGED_AGENTS_2026_04_01 = :"managed-agents-2026-04-01"
109
112
  CACHE_DIAGNOSIS_2026_04_07 = :"cache-diagnosis-2026-04-07"
@@ -11,7 +11,7 @@ module Anthropic
11
11
  # @!attribute model
12
12
  # Model identifier. Accepts the
13
13
  # [model string](https://platform.claude.com/docs/en/about-claude/models/overview#latest-models-comparison),
14
- # e.g. `claude-opus-4-6`, or a `model_config` object for additional configuration
14
+ # e.g. `claude-opus-5`, or a `model_config` object for additional configuration
15
15
  # control
16
16
  #
17
17
  # @return [Symbol, String, Anthropic::Models::Beta::BetaManagedAgentsModel, Anthropic::Models::Beta::BetaManagedAgentsModelConfigParams]
@@ -108,7 +108,7 @@ module Anthropic
108
108
 
109
109
  # Model identifier. Accepts the
110
110
  # [model string](https://platform.claude.com/docs/en/about-claude/models/overview#latest-models-comparison),
111
- # e.g. `claude-opus-4-6`, or a `model_config` object for additional configuration
111
+ # e.g. `claude-opus-5`, or a `model_config` object for additional configuration
112
112
  # control
113
113
  module Model
114
114
  extend Anthropic::Internal::Type::Union