Class: Anthropic::Client

Inherits:
Internal::Transport::BaseClient show all
Defined in:
lib/anthropic/client.rb

Constant Summary collapse

DEFAULT_MAX_RETRIES =

Default max number of retries to attempt after a failed retryable request.

2
DEFAULT_TIMEOUT_IN_SECONDS =

Default per-request timeout.

600.0
DEFAULT_INITIAL_RETRY_DELAY =

Default initial retry delay in seconds. Overall delay is calculated using exponential backoff + jitter.

0.5
DEFAULT_MAX_RETRY_DELAY =

Default max retry delay in seconds.

8.0
MODEL_NONSTREAMING_TOKENS =

Models that have specific non-streaming token limits

{
  "claude-opus-4-20250514": 8_192,
  "claude-opus-4-0": 8_192,
  "claude-4-opus-20250514": 8_192,
  "anthropic.claude-opus-4-20250514-v1:0": 8_192,
  "claude-opus-4@20250514": 8_192,
  "claude-opus-4-1-20250805": 8192,
  "anthropic.claude-opus-4-1-20250805-v1:0": 8192,
  "claude-opus-4-1@20250805": 8192
}.freeze

Constants inherited from Internal::Transport::BaseClient

Internal::Transport::BaseClient::MAX_REDIRECTS, Internal::Transport::BaseClient::PLATFORM_HEADERS

Instance Attribute Summary collapse

Attributes inherited from Internal::Transport::BaseClient

#base_url, #headers, #idempotency_header, #initial_retry_delay, #max_retries, #max_retry_delay, #requester, #timeout

Instance Method Summary collapse

Methods inherited from Internal::Transport::BaseClient

follow_redirect, #inspect, reap_connection!, #request, #send_request, should_retry?, validate!

Methods included from Internal::Util::SorbetRuntimeSupport

#const_missing, #define_sorbet_constant!, #sorbet_constant_defined?, #to_sorbet_type, to_sorbet_type

Constructor Details

#initialize(api_key: nil, auth_token: nil, credentials: nil, config: nil, base_url: nil, max_retries: self.class::DEFAULT_MAX_RETRIES, timeout: self.class::DEFAULT_TIMEOUT_IN_SECONDS, initial_retry_delay: self.class::DEFAULT_INITIAL_RETRY_DELAY, max_retry_delay: self.class::DEFAULT_MAX_RETRY_DELAY) ⇒ Client

Creates and returns a new client for interacting with the API.

Credential precedence, matching the credential-resolution spec and the Workload Identity Federation user guide:

  1. Explicit constructor arguments — api_key:, auth_token:, credentials:, config:. If the caller passed any of these, the SDK uses it and does not read credential env vars.

  2. ANTHROPIC_API_KEY / ANTHROPIC_AUTH_TOKEN env vars. Only consulted when no explicit credential argument was passed.

  3. ANTHROPIC_PROFILE — explicit profile selection.

  4. Direct env-var federation (ANTHROPIC_IDENTITY_TOKEN[_FILE] + ANTHROPIC_FEDERATION_RULE_ID + ANTHROPIC_ORGANIZATION_ID).

  5. Fallback active profile from disk (active_config pointer or the literal default).

A static env credential (step 2) shadows steps 3–5, silently disabling profile / federation auto-discovery.

Passing an explicit api_key: or auth_token: argument alongside an explicit credentials: is supported: the static credential takes precedence at the request-header level and the credentials provider is silently disabled.

Parameters:

  • api_key (String, nil) (defaults to: nil)

    Defaults to ENV when no explicit credential argument is passed.

  • auth_token (String, nil) (defaults to: nil)

    Defaults to ENV when no explicit credential argument is passed.

  • credentials (#call, nil) (defaults to: nil)

    Credential provider — any callable returning AccessToken.new(token:, expires_at:). The provider is wrapped in a TokenCache for thread-safe caching and proactive refresh (120s advisory / 30s mandatory before expiry). Common providers: WorkloadIdentity, CredentialsFile, StaticToken, or a custom lambda.

  • config (Hash, nil) (defaults to: nil)

    In-memory configuration hash with the same shape as configs/<profile>.json. Must include an authentication object with a type field (oidc_federation or user_oauth). Mutually exclusive with credentials:. For user_oauth, must also include authentication.credentials_path.

  • base_url (String, nil) (defaults to: nil)

    Override the default base URL for the API, e.g., api.example.com/v2/”. Defaults to ENV, then to the profile’s base_url if present, then to https://api.anthropic.com.

  • max_retries (Integer) (defaults to: self.class::DEFAULT_MAX_RETRIES)

    Max number of retries to attempt after a failed retryable request.

  • timeout (Float) (defaults to: self.class::DEFAULT_TIMEOUT_IN_SECONDS)
  • initial_retry_delay (Float) (defaults to: self.class::DEFAULT_INITIAL_RETRY_DELAY)
  • max_retry_delay (Float) (defaults to: self.class::DEFAULT_MAX_RETRY_DELAY)


173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
# File 'lib/anthropic/client.rb', line 173

def initialize(
  api_key: nil,
  auth_token: nil,
  credentials: nil,
  config: nil,
  base_url: nil,
  max_retries: self.class::DEFAULT_MAX_RETRIES,
  timeout: self.class::DEFAULT_TIMEOUT_IN_SECONDS,
  initial_retry_delay: self.class::DEFAULT_INITIAL_RETRY_DELAY,
  max_retry_delay: self.class::DEFAULT_MAX_RETRY_DELAY
)
  if config && credentials
    raise ArgumentError, "Pass at most one of `credentials:` or `config:`."
  end

  has_explicit_credential = api_key || auth_token || credentials || config

  unless has_explicit_credential
    api_key = ENV["ANTHROPIC_API_KEY"]
    auth_token = ENV["ANTHROPIC_AUTH_TOKEN"]
  end

  @api_key = api_key&.to_s
  @auth_token = auth_token&.to_s
  @credentials = nil
  @token_cache = nil

  base_url_is_explicit = base_url && !base_url.empty?
  base_url ||= ENV["ANTHROPIC_BASE_URL"]

  credential_headers = {}

  if config
    in_memory = Anthropic::Credentials::InMemoryConfig.new(config)
    @credentials = in_memory
    credential_headers = in_memory.extra_headers
    if !base_url_is_explicit && in_memory.resolved_base_url
      base_url = in_memory.resolved_base_url
    end
  else
    @credentials = credentials
  end

  if @credentials.nil? && @api_key.nil? && @auth_token.nil?
    default_base_url = base_url || "https://api.anthropic.com"
    result = Anthropic::Credentials.default_credentials(base_url: default_base_url)
    if result
      @credentials = result.provider
      credential_headers = result.extra_headers
      base_url = result.base_url if !base_url_is_explicit && result.base_url
    end
  end

  warn_explicit_shadow(api_key: api_key, auth_token: auth_token, credentials: credentials || config)
  warn_env_shadow(api_key: api_key, auth_token: auth_token)

  if @credentials
    @token_cache = Anthropic::Credentials::TokenCache.new(@credentials)
  end

  base_url ||= "https://api.anthropic.com"

  if @credentials.respond_to?(:bind_base_url)
    @credentials.bind_base_url(base_url)
  end

  headers = {
    "anthropic-version" => "2023-06-01"
  }
  custom_headers_env = ENV["ANTHROPIC_CUSTOM_HEADERS"]
  unless custom_headers_env.nil?
    parsed = {}
    custom_headers_env.split("\n").each do |line|
      colon = line.index(":")
      unless colon.nil?
        parsed[line[0...colon].strip] = line[(colon + 1)..].strip
      end
    end
    headers = parsed.merge(headers)
  end
  headers = headers.merge(credential_headers)

  super(
    base_url: base_url,
    timeout: timeout,
    max_retries: max_retries,
    initial_retry_delay: initial_retry_delay,
    max_retry_delay: max_retry_delay,
    headers: headers
  )

  @completions = Anthropic::Resources::Completions.new(client: self)
  @messages = Anthropic::Resources::Messages.new(client: self)
  @models = Anthropic::Resources::Models.new(client: self)
  @beta = Anthropic::Resources::Beta.new(client: self)
end

Instance Attribute Details

#api_keyString? (readonly)

Returns:

  • (String, nil)


57
58
59
# File 'lib/anthropic/client.rb', line 57

def api_key
  @api_key
end

#auth_tokenString? (readonly)

Returns:

  • (String, nil)


60
61
62
# File 'lib/anthropic/client.rb', line 60

def auth_token
  @auth_token
end

#betaAnthropic::Resources::Beta (readonly)



78
79
80
# File 'lib/anthropic/client.rb', line 78

def beta
  @beta
end

#completionsAnthropic::Resources::Completions (readonly)



69
70
71
# File 'lib/anthropic/client.rb', line 69

def completions
  @completions
end

#credentialsObject? (readonly)

Returns:

  • (Object, nil)


63
64
65
# File 'lib/anthropic/client.rb', line 63

def credentials
  @credentials
end

#messagesAnthropic::Resources::Messages (readonly)



72
73
74
# File 'lib/anthropic/client.rb', line 72

def messages
  @messages
end

#modelsAnthropic::Resources::Models (readonly)



75
76
77
# File 'lib/anthropic/client.rb', line 75

def models
  @models
end

#token_cacheAnthropic::Credentials::TokenCache? (readonly)



66
67
68
# File 'lib/anthropic/client.rb', line 66

def token_cache
  @token_cache
end

Instance Method Details

#calculate_nonstreaming_timeout(max_tokens, max_nonstreaming_tokens = nil) ⇒ Float

Calculate the timeout for non-streaming requests based on token count

Parameters:

  • max_tokens (Integer)

    The maximum number of tokens to generate

  • max_nonstreaming_tokens (Integer, nil) (defaults to: nil)

    The maximum tokens allowed for non-streaming

Returns:

  • (Float)

    The calculated timeout in seconds

Raises:

  • (ArgumentError)

    If expected time exceeds default time or max_tokens exceeds max_nonstreaming_tokens



105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/anthropic/client.rb', line 105

def calculate_nonstreaming_timeout(max_tokens, max_nonstreaming_tokens = nil)
  maximum_time = 60 * 60 # 1 hour in seconds
  default_time = 60 * 10 # 10 minutes in seconds

  expected_time = maximum_time * max_tokens / 128_000.0
  if expected_time > default_time || (max_nonstreaming_tokens && max_tokens > max_nonstreaming_tokens)
    raise ArgumentError.new(
      "Streaming is required for operations that may take longer than 10 minutes. " \
      "See https://github.com/anthropics/anthropic-sdk-ruby#long-requests for more details"
    )
  end

  DEFAULT_TIMEOUT_IN_SECONDS
end

#retry_request?(status, headers:) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • status (Integer)
  • headers (Hash{String=>String})

Returns:



276
277
278
279
280
281
282
# File 'lib/anthropic/client.rb', line 276

def retry_request?(status, headers:)
  if status == 401 && @token_cache
    @token_cache.invalidate
    return true
  end
  super
end