Module: OpenAI::Providers::Bedrock Private

Defined in:
lib/openai/providers/bedrock.rb

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

Defined Under Namespace

Classes: BearerAuth, CustomCredentialsProvider, DefaultCredentialsProvider, Definition, ProfileCredentialsProvider, SigV4Auth

Constant Summary collapse

SERVICES =

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

{mantle: "bedrock-mantle", runtime: "bedrock"}.freeze
AWS_REGION_PATTERN =

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

/\A[a-z]{2,8}(?:-[a-z0-9]+)+-\d+\z/
AUTH_HEADERS =

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

%w[authorization].freeze
SIGNING_HEADERS =

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

%w[authorization x-amz-content-sha256 x-amz-date x-amz-security-token].freeze
BEARER_AUTH_MARKER =

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

:openai_bedrock_bearer
SIGV4_AUTH_MARKER =

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

:openai_bedrock_sigv4
MISSING_REGION_MESSAGE =

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

"Bedrock requires an AWS region. Pass `region` to `bedrock(...)`, or set `AWS_REGION` " \
"or `AWS_DEFAULT_REGION`."
MISSING_CREDENTIALS_MESSAGE =

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

"Could not find credentials for Bedrock. Pass a bearer credential or AWS credentials " \
"to `bedrock(...)`, set `AWS_BEARER_TOKEN_BEDROCK`, or configure the default AWS credential chain."
CREDENTIAL_RESOLUTION_MESSAGE =

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

"Failed to resolve AWS credentials for Bedrock. Verify your AWS profile, environment " \
"variables, or runtime identity configuration and try again."
NON_REPLAYABLE_BODY_MESSAGE =

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

"Bedrock SigV4 authentication requires a replayable request body. Buffer the body " \
"before sending or use bearer authentication."
MISSING_DEPENDENCY_MESSAGE =

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

"Bedrock AWS authentication requires optional AWS dependencies. Add `gem \"aws-sdk-core\"` " \
"to your Gemfile, run `bundle install`, and try again."
PARTIAL_STATIC_CREDENTIALS_MESSAGE =

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

"Static AWS credentials require both `access_key_id` and `secret_access_key`. " \
"A `session_token` may only be used with both."
AMBIGUOUS_AWS_AUTH_MESSAGE =

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

"Bedrock authentication is ambiguous. Configure exactly one explicit AWS mode: " \
"static credentials, profile, or credential provider."
AMBIGUOUS_AUTH_MESSAGE =

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

"Bedrock authentication is ambiguous. Configure exactly one explicit mode: bearer " \
"credential, static AWS credentials, profile, or credential provider."

Class Method Summary collapse

Class Method Details

.load_aws!Object

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.



263
264
265
266
267
268
269
# File 'lib/openai/providers/bedrock.rb', line 263

def load_aws!
  require("aws-sdk-core")
  require("aws-sigv4")

rescue LoadError => e
  raise OpenAI::Errors::Error.new(MISSING_DEPENDENCY_MESSAGE), cause: e
end

.normalize_base_url(base_url) ⇒ Object

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.



362
363
364
365
366
367
368
369
370
371
372
373
374
# File 'lib/openai/providers/bedrock.rb', line 362

def normalize_base_url(base_url)
  uri = URI(base_url)
  unless uri.is_a?(URI::HTTP) && uri.host
    raise ArgumentError, "The Bedrock `base_url` must be an absolute HTTP or HTTPS URL."
  end

  uri.path = uri.path.sub(%r{/responses(?:/.*)?\z}, "")
  uri.path = "" if uri.path == "/"
  uri.to_s.sub(%r{/\z}, "")
rescue URI::InvalidURIError => e
  message = "The Bedrock `base_url` must be an absolute HTTP or HTTPS URL."
  raise ArgumentError.new(message), cause: e
end

.normalize_endpoint(endpoint) ⇒ Object

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.

Raises:

  • (ArgumentError)


354
355
356
357
358
359
360
# File 'lib/openai/providers/bedrock.rb', line 354

def normalize_endpoint(endpoint)
  return nil if endpoint.nil?
  return endpoint.to_sym if endpoint == "mantle" || endpoint == "runtime"
  return endpoint if endpoint == :mantle || endpoint == :runtime

  raise ArgumentError, "The Bedrock `endpoint` must be either `mantle` or `runtime`."
end

.normalize_optional_string(value) ⇒ Object

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.



443
444
445
446
447
448
# File 'lib/openai/providers/bedrock.rb', line 443

def normalize_optional_string(value)
  return nil if value.nil?
  return nil unless value.is_a?(String)
  normalized = value.strip
  normalized unless normalized.empty?
end

.parse_endpoint_hostname(hostname) ⇒ Object

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.



302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
# File 'lib/openai/providers/bedrock.rb', line 302

def parse_endpoint_hostname(hostname)
  service, region, *suffix_parts = hostname.delete_suffix(".").downcase.split(".")
  suffix = suffix_parts.join(".")

  if service == "bedrock-mantle" && region&.match?(/\A[a-z0-9-]+\z/) && suffix == "api.aws"
    return {endpoint: :mantle, region: region}
  end

  if %w[bedrock-runtime bedrock-runtime-fips].include?(service) &&
      region &&
      runtime_dns_suffixes(region).include?(suffix)
    return {endpoint: :runtime, region: region}
  end

  nil
end

.profile_region(profile) ⇒ Object

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.



376
377
378
379
380
381
382
# File 'lib/openai/providers/bedrock.rb', line 376

def profile_region(profile)
  configured_profile = profile || ENV["AWS_PROFILE"] || ENV["AWS_DEFAULT_PROFILE"] || "default"
  region = Aws.shared_config.region(profile: configured_profile)
  normalize_optional_string(region)
rescue StandardError => e
  raise OpenAI::Errors::Error.new(CREDENTIAL_RESOLUTION_MESSAGE), cause: e
end

.provider_headers(request, marker:) ⇒ Object

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.



384
385
386
387
388
389
390
391
392
393
394
395
396
# File 'lib/openai/providers/bedrock.rb', line 384

def provider_headers(request, marker:)
  headers = request.fetch(:headers).dup
  if request[:provider_auth] == marker
    headers.delete("authorization")
  elsif headers.key?("authorization")
    raise(
      OpenAI::Errors::Error,
      "Bedrock provider authentication cannot be combined with a custom `Authorization` header."
    )
  end

  headers
end

.resolve_base_url(base_url, region, endpoint:) ⇒ Object

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.

Raises:

  • (ArgumentError)


271
272
273
274
275
276
277
278
279
280
281
# File 'lib/openai/providers/bedrock.rb', line 271

def resolve_base_url(base_url, region, endpoint:)
  return base_url if base_url
  raise ArgumentError, MISSING_REGION_MESSAGE if region.nil?

  if endpoint == :runtime
    suffix, = runtime_dns_suffixes(region)
    "https://bedrock-runtime.#{region}.#{suffix}/openai/v1"
  else
    "https://bedrock-mantle.#{region}.api.aws/v1"
  end
end

.runtime_dns_suffixes(region) ⇒ Object

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.



283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
# File 'lib/openai/providers/bedrock.rb', line 283

def runtime_dns_suffixes(region)
  case region
  when /\Acn-/
    ["amazonaws.com.cn", "api.amazonwebservices.com.cn"]
  when /\Aeusc-/
    ["amazonaws.eu", "api.amazonwebservices.eu"]
  when /\Aus-iso-/
    ["c2s.ic.gov", "api.aws.ic.gov"]
  when /\Aus-isob-/
    ["sc2s.sgov.gov", "api.aws.scloud"]
  when /\Aeu-isoe-/
    ["cloud.adc-e.uk", "api.cloud-aws.adc-e.uk"]
  when /\Aus-isof-/
    ["csp.hci.ic.gov", "api.aws.hci.ic.gov"]
  else
    ["amazonaws.com", "api.aws"]
  end
end

.validate_canonical_endpoint!(base_url, endpoint, region) ⇒ Object

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.

Raises:

  • (ArgumentError)


319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
# File 'lib/openai/providers/bedrock.rb', line 319

def validate_canonical_endpoint!(base_url, endpoint, region)
  uri = URI(base_url)
  canonical = parse_endpoint_hostname(uri.host)
  return unless canonical

  unless uri.is_a?(URI::HTTPS)
    raise ArgumentError, "Canonical Amazon Bedrock endpoints require HTTPS."
  end

  if canonical.fetch(:endpoint) != endpoint
    raise(
      ArgumentError,
      "The Bedrock #{canonical.fetch(:endpoint)} hostname does not match the " \
        "selected `#{endpoint}` endpoint."
    )
  end

  return if region.nil? || canonical.fetch(:region) == region

  raise(
    ArgumentError,
    "The Bedrock endpoint region `#{canonical.fetch(:region)}` does not match the " \
      "configured AWS region `#{region}`."
  )
end

.validate_credentials!(credentials) ⇒ Object

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.



430
431
432
433
434
435
436
437
438
439
440
441
# File 'lib/openai/providers/bedrock.rb', line 430

def validate_credentials!(credentials)
  access_key_id = credentials&.access_key_id
  secret_access_key = credentials&.secret_access_key
  session_token = credentials&.session_token if credentials.respond_to?(:session_token)
  valid = access_key_id.is_a?(String) &&
    !access_key_id.strip.empty? &&
    secret_access_key.is_a?(String) &&
    !secret_access_key.strip.empty? &&
    (session_token.nil? || (session_token.is_a?(String) && !session_token.strip.empty?))
  return credentials if valid
  raise OpenAI::Errors::Error, CREDENTIAL_RESOLUTION_MESSAGE
end

.validate_endpoint_region!(url, region, endpoint:) ⇒ Object

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.



408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
# File 'lib/openai/providers/bedrock.rb', line 408

def validate_endpoint_region!(url, region, endpoint:)
  canonical = parse_endpoint_hostname(url.host)
  return unless canonical

  if canonical.fetch(:endpoint) != endpoint
    raise(
      OpenAI::Errors::Error,
      "The Bedrock #{canonical.fetch(:endpoint)} hostname does not match the " \
        "selected `#{endpoint}` endpoint."
    )
  end

  endpoint_region = canonical.fetch(:region)
  return if endpoint_region == region
  message = "The Bedrock endpoint region `#{endpoint_region}` does not match the SigV4 " \
    "region `#{region}`."
  raise(
    OpenAI::Errors::Error,
    message
  )
end

.validate_origin!(url, base_url, action:) ⇒ Object

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.



398
399
400
401
402
403
404
405
406
# File 'lib/openai/providers/bedrock.rb', line 398

def validate_origin!(url, base_url, action:)
  return if OpenAI::Internal::Util.uri_origin(url) == OpenAI::Internal::Util.uri_origin(base_url)
  message = "Refusing to #{action} a Bedrock request for an origin other than the configured " \
    "provider URL."
  raise(
    OpenAI::Errors::Error,
    message
  )
end

.validate_region!(region) ⇒ Object

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.

Raises:

  • (ArgumentError)


345
346
347
348
349
350
351
352
# File 'lib/openai/providers/bedrock.rb', line 345

def validate_region!(region)
  return if AWS_REGION_PATTERN.match?(region)

  raise(
    ArgumentError,
    "The Bedrock AWS `region` is invalid. Use a standard AWS region such as `us-east-1`."
  )
end