anthropic 1.37.0 → 1.38.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9eacf10bf13feb1eb221fe82ee801d2754524985991959c858db721b5cfd825e
4
- data.tar.gz: 6e70a7c6d4ee0dd18a892272017f73e524ace1a943579b9694c23c94331ad421
3
+ metadata.gz: 5053fea394cb2c14a0692837413c50fdfa520703226d15b1788234b9dd865b53
4
+ data.tar.gz: ac9ffbef339cb6713fbf68b3c4248562f527ad145e621239d9375d43d8ba8d45
5
5
  SHA512:
6
- metadata.gz: '002489936b1fa9dda322c5dd604bea0eb371ef4a25a8e091e8a7204db4acca6d3dfa7e4840666a1042b0052271215abc18499a99ab5d9a5589401ad1df9626c1'
7
- data.tar.gz: 95b904d78f29eb0b36f694c628c52c686775349ca3ba9cb6746ce33758558dc48a624ca925bc72661bf54b033272cf14d57babea6d86ffed7b6d37531fada262
6
+ metadata.gz: 74d0c247922c3ae14f23915fbdf95d1e5e66d5b785cc9c3804d594da9d28b7c1bf2d68b56bae8f56e991f18f8f74010b0abe97e8b40611eae99931293b7fa89d
7
+ data.tar.gz: fe67842d5673483fefac88cfaaa496a56a94914eefed0d947815cbcdde48fb8a9120f0cfb1dd59de37f70e8c8eeb996505e1a024b056ce22845f14704377d7f5
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.38.0 (2026-05-05)
4
+
5
+ Full Changelog: [v1.37.0...v1.38.0](https://github.com/anthropics/anthropic-sdk-ruby/compare/v1.37.0...v1.38.0)
6
+
7
+ ### Features
8
+
9
+ * **client:** allow targeting a workspace for OIDC federation token exchange ([85f4668](https://github.com/anthropics/anthropic-sdk-ruby/commit/85f46687b798714bed259e6b78e07bc4df114046))
10
+
3
11
  ## 1.37.0 (2026-05-04)
4
12
 
5
13
  Full Changelog: [v1.36.0...v1.37.0](https://github.com/anthropics/anthropic-sdk-ruby/compare/v1.36.0...v1.37.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.37.0"
18
+ gem "anthropic", "~> 1.38.0"
19
19
  ```
20
20
 
21
21
  <!-- x-release-please-end -->
@@ -74,6 +74,9 @@ module Anthropic
74
74
  headers = {}
75
75
 
76
76
  auth_type = config[:authentication][:type]
77
+ # For federation profiles workspace_id is sent in the jwt-bearer
78
+ # exchange body, not as a request header (the minted token is already
79
+ # workspace-scoped, so the header would be ignored).
77
80
  if auth_type != AUTH_TYPE_OIDC_FEDERATION
78
81
  workspace_id = config[:workspace_id]
79
82
  headers["anthropic-workspace-id"] = workspace_id.to_s if workspace_id
@@ -193,6 +196,7 @@ module Anthropic
193
196
  federation_rule_id: federation_rule_id,
194
197
  organization_id: organization_id,
195
198
  service_account_id: auth[:service_account_id],
199
+ workspace_id: @config[:workspace_id],
196
200
  scope: auth[:scope]
197
201
  )
198
202
 
@@ -394,6 +398,7 @@ module Anthropic
394
398
  def fill_missing_from_env(config, auth)
395
399
  fill(config, :base_url, ENV_BASE_URL)
396
400
  fill(config, :organization_id, ENV_ORGANIZATION_ID)
401
+ fill(config, :workspace_id, ENV_WORKSPACE_ID)
397
402
 
398
403
  auth_type = auth[:type]
399
404
  if auth_type == AUTH_TYPE_OIDC_FEDERATION
@@ -62,6 +62,9 @@ module Anthropic
62
62
  # Environment variable for service account ID.
63
63
  ENV_SERVICE_ACCOUNT_ID = "ANTHROPIC_SERVICE_ACCOUNT_ID"
64
64
 
65
+ # Environment variable for workspace ID.
66
+ ENV_WORKSPACE_ID = "ANTHROPIC_WORKSPACE_ID"
67
+
65
68
  # Environment variable for OAuth scope.
66
69
  ENV_SCOPE = "ANTHROPIC_SCOPE"
67
70
 
@@ -103,6 +103,7 @@ module Anthropic
103
103
  federation_rule_id: federation_rule_id,
104
104
  organization_id: organization_id,
105
105
  service_account_id: auth[:service_account_id],
106
+ workspace_id: config[:workspace_id],
106
107
  scope: auth[:scope]
107
108
  )
108
109
 
@@ -53,6 +53,16 @@ module Anthropic
53
53
  # @param organization_id [String] the organization's raw UUID string
54
54
  # @param service_account_id [String, nil] optional service account ID to
55
55
  # impersonate
56
+ # @param workspace_id [String, nil] Optional +wrkspc_*+ tagged ID, or the
57
+ # literal +"default"+ to scope the token to the organization's default
58
+ # workspace. When omitted the server picks the rule's sole enabled
59
+ # workspace, else the org default if the rule covers it. Required when
60
+ # the rule enables more than one non-default workspace, or to target a
61
+ # specific workspace other than the one the server would pick. The
62
+ # minted token is workspace-scoped: per-request workspace selection
63
+ # (the +anthropic-workspace-id+ header) is not supported for federation
64
+ # tokens — switching workspaces requires a new token exchange with a
65
+ # different +workspace_id+.
56
66
  # @param scope [String, nil] optional OAuth scope (informational only for
57
67
  # federation; the server derives the effective scope from the federation rule)
58
68
  def initialize(
@@ -60,12 +70,14 @@ module Anthropic
60
70
  federation_rule_id:,
61
71
  organization_id:,
62
72
  service_account_id: nil,
73
+ workspace_id: nil,
63
74
  scope: nil # rubocop:disable Lint/UnusedMethodArgument
64
75
  )
65
76
  @identity_token_provider = identity_token_provider
66
77
  @federation_rule_id = federation_rule_id
67
78
  @organization_id = organization_id
68
79
  @service_account_id = service_account_id
80
+ @workspace_id = workspace_id
69
81
  @bound_base_url = nil
70
82
  end
71
83
 
@@ -128,6 +140,7 @@ module Anthropic
128
140
  "organization_id" => @organization_id
129
141
  }
130
142
  body["service_account_id"] = @service_account_id if @service_account_id
143
+ body["workspace_id"] = @workspace_id if @workspace_id
131
144
 
132
145
  request = Net::HTTP::Post.new(uri.path)
133
146
  request["Content-Type"] = "application/json"
@@ -173,8 +186,23 @@ module Anthropic
173
186
  response.body&.slice(0, 256)
174
187
  end
175
188
 
189
+ message = "Token exchange failed (HTTP #{response.code}): #{body}"
190
+ # An ambiguous 401 is usually a federation-rule misconfiguration.
191
+ # Surface the fix in the error rather than making the user dig through docs.
192
+ if response.code.to_i == 401
193
+ hint_parts = ["Ensure your federation rule matches your identity token"]
194
+ if @workspace_id.nil?
195
+ hint_parts << "If your federation rule is scoped to multiple workspaces, set the " \
196
+ "ANTHROPIC_WORKSPACE_ID environment variable, the 'workspace_id' " \
197
+ "config key, or the workspace_id: keyword argument"
198
+ end
199
+ hint_parts << "View your authentication events in the Workload identity page of " \
200
+ "Claude Console for more details"
201
+ message += " #{hint_parts.join('. ')}."
202
+ end
203
+
176
204
  raise WorkloadIdentityError.new(
177
- "Token exchange failed (HTTP #{response.code}): #{body}",
205
+ message,
178
206
  status_code: response.code.to_i,
179
207
  body: body,
180
208
  request_id: request_id
@@ -146,6 +146,10 @@ module Anthropic
146
146
  federation_rule_id: federation_rule_id,
147
147
  organization_id: organization_id,
148
148
  service_account_id: ENV[ENV_SERVICE_ACCOUNT_ID],
149
+ # Coerce empty string to nil so a defaulted-but-empty CI variable doesn't
150
+ # put "workspace_id" => "" on the wire — matches the blank-skip in
151
+ # ConfigProvider#fill.
152
+ workspace_id: ENV[ENV_WORKSPACE_ID].then { _1 unless _1.to_s.empty? },
149
153
  scope: ENV[ENV_SCOPE]
150
154
  )
151
155
  provider.bind_base_url(base_url)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Anthropic
4
- VERSION = "1.37.0"
4
+ VERSION = "1.38.0"
5
5
  end
@@ -23,6 +23,7 @@ module Anthropic
23
23
  ENV_FEDERATION_RULE_ID = T.let("ANTHROPIC_FEDERATION_RULE_ID", String)
24
24
  ENV_ORGANIZATION_ID = T.let("ANTHROPIC_ORGANIZATION_ID", String)
25
25
  ENV_SERVICE_ACCOUNT_ID = T.let("ANTHROPIC_SERVICE_ACCOUNT_ID", String)
26
+ ENV_WORKSPACE_ID = T.let("ANTHROPIC_WORKSPACE_ID", String)
26
27
  ENV_SCOPE = T.let("ANTHROPIC_SCOPE", String)
27
28
  AUTH_TYPE_OIDC_FEDERATION = T.let("oidc_federation", String)
28
29
  AUTH_TYPE_USER_OAUTH = T.let("user_oauth", String)
@@ -166,6 +167,7 @@ module Anthropic
166
167
  federation_rule_id: String,
167
168
  organization_id: String,
168
169
  service_account_id: T.nilable(String),
170
+ workspace_id: T.nilable(String),
169
171
  scope: T.nilable(String)
170
172
  ).void
171
173
  end
@@ -174,6 +176,7 @@ module Anthropic
174
176
  federation_rule_id:,
175
177
  organization_id:,
176
178
  service_account_id: nil,
179
+ workspace_id: nil,
177
180
  scope: nil
178
181
  )
179
182
  end
@@ -20,6 +20,7 @@ module Anthropic
20
20
  ENV_FEDERATION_RULE_ID: String
21
21
  ENV_ORGANIZATION_ID: String
22
22
  ENV_SERVICE_ACCOUNT_ID: String
23
+ ENV_WORKSPACE_ID: String
23
24
  ENV_SCOPE: String
24
25
  AUTH_TYPE_OIDC_FEDERATION: String
25
26
  AUTH_TYPE_USER_OAUTH: String
@@ -113,6 +114,7 @@ module Anthropic
113
114
  @federation_rule_id: String
114
115
  @organization_id: String
115
116
  @service_account_id: String?
117
+ @workspace_id: String?
116
118
  @scope: String?
117
119
  @bound_base_url: String?
118
120
 
@@ -121,6 +123,7 @@ module Anthropic
121
123
  federation_rule_id: String,
122
124
  organization_id: String,
123
125
  ?service_account_id: String?,
126
+ ?workspace_id: String?,
124
127
  ?scope: String?
125
128
  ) -> void
126
129
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: anthropic
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.37.0
4
+ version: 1.38.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anthropic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-05-04 00:00:00.000000000 Z
11
+ date: 2026-05-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cgi